1 /*
2 Copyright (c) 2015 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 // dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
30 module dimage.jpeg;
31 
32 version = USE_DIMAGE;
33 version(USE_DIMAGE):
34 
35 
36 import std.stdio;
37 import std.algorithm;
38 import std.string;
39 import std.traits;
40 
41 import dimage.huffman;
42 import dimage.stream;
43 import dimage.compound;
44 import dimage.array;
45 //import dimage.color;
46 import dimage.image;
47 import dimage.bitio;
48 import dimage.memory;
49 import dimage.idct;
50 //import dlib.core.memory;
51 //import dlib.core.stream;
52 //import dlib.core.compound;
53 //import dlib.container.array;
54 //import dlib.filesystem.local;
55 //import dlib.image.color;
56 //import dlib.image.image;
57 //import dlib.image.io.idct;
58 
59 //import dlib.core.bitio;
60 //import dlib.coding.huffman;
61 
62 /*
63  * Simple JPEG decoder
64  *
65  * Limitations:
66  *  - Doesn't support progressive JPEG
67  *  - Doesn't perform chroma interpolation
68  *  - Doesn't read EXIF metadata
69  */
70 
71 // Uncomment this to see debug messages
72 //version = JPEGDebug;
73 
74 T readNumeric(T) (InputStream istrm, Endian endian = Endian.Little)
75 if (is(T == ubyte))
76 {
77     ubyte b;
78     istrm.readBytes(&b, 1);
79     return b;
80 }
81 
82 T readNumeric(T) (InputStream istrm, Endian endian = Endian.Little)
83 if (is(T == ushort))
84 {
85     union U16
86     {
87         ubyte[2] asBytes;
88         ushort asUshort;
89     }
90     U16 u16;
91     istrm.readBytes(u16.asBytes.ptr, 2);
92     version(LittleEndian)
93     {
94         if (endian == Endian.Big)
95             return u16.asUshort.swapEndian16;
96         else
97             return u16.asUshort;
98     }
99     else
100     {
101         if (endian == Endian.Little)
102             return u16.asUshort.swapEndian16;
103         else
104             return u16.asUshort;
105     }
106 }
107 
108 char[size] readChars(size_t size) (InputStream istrm)
109 {
110     char[size] chars;
111     istrm.readBytes(chars.ptr, size);
112     return chars;
113 }
114 
115 /*
116  * JPEG-related Huffman coding
117  */
118 
119 struct HuffmanCode
120 {
121     ushort bits;
122     ushort length;
123 
124     auto bitString()
125     {
126         return .bitString(bits, length);
127     }
128 }
129 
130 struct HuffmanTableEntry
131 {
132     HuffmanCode code;
133     ubyte value;
134 }
135 
136 DynamicArray!char bitString(T)(T n, uint len = 1) if (isIntegral!T)
137 {
138     DynamicArray!char arr;
139 
140     const int size = T.sizeof * 8;
141 
142     bool s = 0;
143     for (int a = 0; a < size; a++)
144     {
145         bool bit = n >> (size - 1);
146         if (bit)
147             s = 1;
148         if (s)
149         {
150             arr.append(bit + '0');
151         }
152         n <<= 1;
153     }
154 
155     while (arr.length < len)
156         arr.appendLeft('0');
157 
158     return arr;
159 }
160 
161 HuffmanTreeNode* emptyNode()
162 {
163     return New!HuffmanTreeNode(null, null, cast(ubyte)0, 0, false);
164 }
165 
166 HuffmanTreeNode* treeFromTable(DynamicArray!(HuffmanTableEntry) table)
167 {
168     HuffmanTreeNode* root = emptyNode();
169 
170     foreach(i, v; table.data)
171         treeAddCode(root, v.code, v.value);
172 
173     return root;
174 }
175 
176 void treeAddCode(HuffmanTreeNode* root, HuffmanCode code, ubyte value)
177 {
178     HuffmanTreeNode* node = root;
179     auto bs = code.bitString;
180     foreach(bit; bs.data)
181     {
182         if (bit == '0')
183         {
184             if (node.left is null)
185             {
186                 node.left = emptyNode();
187                 node.left.parent = node;
188             }
189 
190             node = node.left;
191         }
192         else if (bit == '1')
193         {
194             if (node.right is null)
195             {
196                 node.right = emptyNode();
197                 node.right.parent = node;
198             }
199 
200             node = node.right;
201         }
202     }
203     assert (node !is null);
204     node.ch = value;
205     bs.free();
206 }
207 
208 /*
209  * JPEG-related data types
210  */
211 
212 enum JPEGMarkerType
213 {
214     Unknown,
215     SOI,
216     SOF0,
217     SOF1,
218     SOF2,
219     DHT,
220     DQT,
221     DRI,
222     SOS,
223     RSTn,
224     APP0,
225     APPn,
226     COM,
227     EOI
228 }
229 
230 struct JPEGImage
231 {
232     struct JFIF
233     {
234         ubyte versionMajor;
235         ubyte versionMinor;
236         ubyte units;
237         ushort xDensity;
238         ushort yDensity;
239         ubyte thumbnailWidth;
240         ubyte thumbnailHeight;
241         ubyte[] thumbnail;
242 
243         void free()
244         {
245             if (thumbnail.length)
246                 Delete(thumbnail);
247         }
248     }
249 
250     struct DQT
251     {
252         ubyte precision;
253         ubyte tableId;
254         ubyte[] table;
255 
256         void free()
257         {
258             if (table.length)
259                 Delete(table);
260         }
261     }
262 
263     struct SOF0Component
264     {
265         ubyte hSubsampling;
266         ubyte vSubsampling;
267         ubyte dqtTableId;
268     }
269 
270     struct SOF0
271     {
272         ubyte precision;
273         ushort height;
274         ushort width;
275         ubyte componentsNum;
276         SOF0Component[] components;
277 
278         void free()
279         {
280             if (components.length)
281                 Delete(components);
282         }
283     }
284 
285     struct DHT
286     {
287         ubyte clas;
288         ubyte tableId;
289         DynamicArray!HuffmanTableEntry huffmanTable;
290         HuffmanTreeNode* huffmanTree;
291 
292         void free()
293         {
294             huffmanTree.free();
295             Delete(huffmanTree);
296             huffmanTable.free();
297         }
298     }
299 
300     struct SOSComponent
301     {
302         ubyte tableIdDC;
303         ubyte tableIdAC;
304     }
305 
306     struct SOS
307     {
308         ubyte componentsNum;
309         SOSComponent[] components;
310         ubyte spectralSelectionStart;
311         ubyte spectralSelectionEnd;
312         ubyte successiveApproximationBitHigh;
313         ubyte successiveApproximationBitLow;
314 
315         void free()
316         {
317             if (components.length)
318                 Delete(components);
319         }
320     }
321 
322     JFIF jfif;
323     DQT[] dqt;
324     SOF0 sof0;
325     DHT[] dht;
326     SOS sos;
327 
328     DQT* addDQT()
329     {
330         if (dqt.length > 0)
331             reallocateArray(dqt, dqt.length+1);
332         else
333             dqt = New!(DQT[])(1);
334         return &dqt[$-1];
335     }
336 
337     DHT* addDHT()
338     {
339         if (dht.length > 0)
340             reallocateArray(dht, dht.length+1);
341         else
342             dht = New!(DHT[])(1);
343         return &dht[$-1];
344     }
345 
346     void free()
347     {
348         jfif.free();
349         foreach(ref t; dqt) t.free();
350         Delete(dqt);
351         sof0.free();
352         foreach(ref t; dht) t.free();
353         Delete(dht);
354         sos.free();
355     }
356 
357     DQT* getQuantizationTable(ubyte id)
358     {
359         foreach(ref t; dqt)
360             if (t.tableId == id)
361                 return &t;
362         return null;
363     }
364 
365     DHT* getHuffmanTable(ubyte clas, ubyte id)
366     {
367         foreach(ref t; dht)
368             if (t.clas == clas &&
369                 t.tableId == id)
370                 return &t;
371         return null;
372     }
373 }
374 
375 /*
376  * Load JPEG from file using local FileSystem.
377  * Causes GC allocation
378  */
379 //SuperImage loadJPEG(string filename)
380 //{
381 //    InputStream input = openForInput(filename);
382 //    auto img = loadJPEG(input);
383 //    input.close();
384 //    return img;
385 //}
386 
387 /*
388  * Load JPEG from stream using default image factory.
389  * Causes GC allocation
390  */
391 SuperImage loadJPEG(InputStream istrm)
392 {
393     Compound!(SuperImage, string) res =
394         loadJPEG(istrm, defaultImageFactory);
395     if (res[0] is null)
396         throw new Exception(res[1]);
397     else
398         return res[0];
399 }
400 
401 /*
402  * Load JPEG from stream using specified image factory.
403  * GC-free
404  */
405 Compound!(SuperImage, string) loadJPEG(
406     InputStream istrm,
407     SuperImageFactory imgFac)
408 {
409     JPEGImage jpg;
410     SuperImage img = null;
411 
412     while (istrm.readable)
413     {
414         JPEGMarkerType mt;
415         auto res = readMarker(&jpg, istrm, &mt);
416         if (res[0])
417         {
418             // TODO: add progressive JPEG support
419             if (mt == JPEGMarkerType.SOF2)
420             {
421                 jpg.free();
422                 return compound(img, "loadJPEG error: progressive JPEG is not supported");
423             }
424             else if (mt == JPEGMarkerType.SOS)
425                 break;
426         }
427         else
428         {
429             jpg.free();
430             return compound(img, res[1]);
431         }
432     }
433     auto res = decodeScanData(&jpg, istrm, imgFac);
434     jpg.free();
435     return res;
436 }
437 
438 /*
439  *  Decode marker from JPEG stream
440  */
441 Compound!(bool, string) readMarker(
442     JPEGImage* jpg,
443     InputStream istrm,
444     JPEGMarkerType* mt)
445 {
446     ushort magic = istrm.readNumeric!ushort(Endian.Big);
447 
448     switch (magic)
449     {
450         case 0xFFD8:
451             *mt = JPEGMarkerType.SOI;
452             version(JPEGDebug) writeln("SOI");
453             break;
454 
455         case 0xFFE0:
456             *mt = JPEGMarkerType.APP0;
457             return readJFIF(jpg, istrm);
458 
459         case 0xFFE1:
460             *mt = JPEGMarkerType.APPn;
461             return readAPPn(jpg, istrm, 1);
462 
463         case 0xFFE2:
464             *mt = JPEGMarkerType.APPn;
465             return readAPPn(jpg, istrm, 2);
466 
467         case 0xFFE3:
468             *mt = JPEGMarkerType.APPn;
469             return readAPPn(jpg, istrm, 3);
470 
471         case 0xFFE4:
472             *mt = JPEGMarkerType.APPn;
473             return readAPPn(jpg, istrm, 4);
474 
475         case 0xFFE5:
476             *mt = JPEGMarkerType.APPn;
477             return readAPPn(jpg, istrm, 5);
478 
479         case 0xFFE6:
480             *mt = JPEGMarkerType.APPn;
481             return readAPPn(jpg, istrm, 6);
482 
483         case 0xFFE7:
484             *mt = JPEGMarkerType.APPn;
485             return readAPPn(jpg, istrm, 7);
486 
487         case 0xFFE8:
488             *mt = JPEGMarkerType.APPn;
489             return readAPPn(jpg, istrm, 8);
490 
491          case 0xFFE9:
492             *mt = JPEGMarkerType.APPn;
493             return readAPPn(jpg, istrm, 9);
494 
495          case 0xFFEA:
496             *mt = JPEGMarkerType.APPn;
497             return readAPPn(jpg, istrm, 10);
498 
499          case 0xFFEB:
500             *mt = JPEGMarkerType.APPn;
501             return readAPPn(jpg, istrm, 11);
502 
503          case 0xFFEC:
504             *mt = JPEGMarkerType.APPn;
505             return readAPPn(jpg, istrm, 12);
506 
507          case 0xFFED:
508             *mt = JPEGMarkerType.APPn;
509             return readAPPn(jpg, istrm, 13);
510 
511          case 0xFFEE:
512             *mt = JPEGMarkerType.APPn;
513             return readAPPn(jpg, istrm, 14);
514 
515          case 0xFFEF:
516             *mt = JPEGMarkerType.APPn;
517             return readAPPn(jpg, istrm, 15);
518 
519         case 0xFFDB:
520             *mt = JPEGMarkerType.DQT;
521             return readDQT(jpg, istrm);
522 
523         case 0xFFC0:
524             *mt = JPEGMarkerType.SOF0;
525             return readSOF0(jpg, istrm);
526 
527         case 0xFFC2:
528             *mt = JPEGMarkerType.SOF2;
529             break;
530 
531         case 0xFFC4:
532             *mt = JPEGMarkerType.DHT;
533             return readDHT(jpg, istrm);
534 
535         case 0xFFDA:
536             *mt = JPEGMarkerType.SOS;
537             return readSOS(jpg, istrm);
538 
539         case 0xFFFE:
540             *mt = JPEGMarkerType.COM;
541             return readCOM(jpg, istrm);
542 
543         default:
544             *mt = JPEGMarkerType.Unknown;
545             break;
546     }
547 
548     return compound(true, "");
549 }
550 
551 Compound!(bool, string) readJFIF(JPEGImage* jpg, InputStream istrm)
552 {
553     ushort jfif_length = istrm.readNumeric!ushort(Endian.Big);
554 
555     char[5] jfif_id = istrm.readChars!5;
556     if (jfif_id != "JFIF\0")
557         return compound(false, "loadJPEG error: illegal JFIF header");
558 
559     jpg.jfif.versionMajor = istrm.readNumeric!ubyte;
560     jpg.jfif.versionMinor = istrm.readNumeric!ubyte;
561     jpg.jfif.units = istrm.readNumeric!ubyte;
562     jpg.jfif.xDensity = istrm.readNumeric!ushort(Endian.Big);
563     jpg.jfif.yDensity = istrm.readNumeric!ushort(Endian.Big);
564     jpg.jfif.thumbnailWidth = istrm.readNumeric!ubyte;
565     jpg.jfif.thumbnailHeight = istrm.readNumeric!ubyte;
566 
567     uint jfif_thumb_length = jpg.jfif.thumbnailWidth * jpg.jfif.thumbnailHeight * 3;
568     if (jfif_thumb_length > 0)
569     {
570         jpg.jfif.thumbnail = New!(ubyte[])(jfif_thumb_length);
571         istrm.readBytes(jpg.jfif.thumbnail.ptr, jfif_thumb_length);
572     }
573 
574     version(JPEGDebug)
575     {
576         writefln("APP0/JFIF length: %s", jfif_length);
577         writefln("APP0/JFIF identifier: %s", jfif_id);
578         writefln("APP0/JFIF version major: %s", jpg.jfif.versionMajor);
579         writefln("APP0/JFIF version minor: %s", jpg.jfif.versionMinor);
580         writefln("APP0/JFIF units: %s", jpg.jfif.units);
581         writefln("APP0/JFIF xdensity: %s", jpg.jfif.xDensity);
582         writefln("APP0/JFIF ydensity: %s", jpg.jfif.yDensity);
583         writefln("APP0/JFIF xthumbnail: %s", jpg.jfif.thumbnailWidth);
584         writefln("APP0/JFIF ythumbnail: %s", jpg.jfif.thumbnailHeight);
585     }
586 
587     return compound(true, "");
588 }
589 
590 /*
591  * APP1 - EXIF, XMP, ExtendedXMP, QVCI, FLIR
592  * APP2 - ICC, FPXR, MPF, PreviewImage
593  * APP3 - Kodak Meta, Stim, PreviewImage
594  * APP4 - Scalado, FPXR, PreviewImage
595  * APP5 - RMETA, PreviewImage
596  * APP6 - EPPIM, NITF, HP TDHD
597  * APP7 - Pentax, Qualcomm
598  * APP8 - SPIFF
599  * APP9 - MediaJukebox
600  * APP10 - PhotoStudio comment
601  * APP11 - JPEG-HDR
602  * APP12 - PictureInfo, Ducky
603  * APP13 - Photoshop, Adobe CM
604  * APP14 - Adobe
605  * APP15 - GraphicConverter
606  */
607 Compound!(bool, string) readAPPn(JPEGImage* jpg, InputStream istrm, uint n)
608 {
609     ushort app_length = istrm.readNumeric!ushort(Endian.Big);
610     ubyte[] app = New!(ubyte[])(app_length-2);
611     istrm.readBytes(app.ptr, app_length-2);
612 
613     // TODO: interpret APP data (EXIF etc.) and save it somewhere.
614     // Maybe add a generic ImageInfo object for this?
615     Delete(app);
616 
617     version(JPEGDebug)
618     {
619         writefln("APP%s length: %s", n, app_length);
620     }
621 
622     return compound(true, "");
623 }
624 
625 Compound!(bool, string) readCOM(JPEGImage* jpg, InputStream istrm)
626 {
627     ushort com_length = istrm.readNumeric!ushort(Endian.Big);
628     ubyte[] com = New!(ubyte[])(com_length-2);
629     istrm.readBytes(com.ptr, com_length-2);
630 
631     version(JPEGDebug)
632     {
633         writefln("COM string: \"%s\"", cast(string)com);
634         writefln("COM length: %s", com_length);
635     }
636 
637     // TODO: save COM data somewhere.
638     // Maybe add a generic ImageInfo object for this?
639     Delete(com);
640 
641     return compound(true, "");
642 }
643 
644 Compound!(bool, string) readDQT(JPEGImage* jpg, InputStream istrm)
645 {
646     ushort dqt_length = istrm.readNumeric!ushort(Endian.Big);
647     version(JPEGDebug)
648     {
649         writefln("DQT length: %s", dqt_length);
650     }
651 
652     dqt_length -= 2;
653 
654     while(dqt_length)
655     {
656         JPEGImage.DQT* dqt = jpg.addDQT();
657 
658         ubyte bite = istrm.readNumeric!ubyte;
659         dqt.precision = bite.hiNibble;
660         dqt.tableId = bite.loNibble;
661 
662         dqt_length--;
663 
664         if (dqt.precision == 0)
665         {
666             dqt.table = New!(ubyte[])(64);
667             dqt_length -= 64;
668         }
669         else if (dqt.precision == 1)
670         {
671             dqt.table = New!(ubyte[])(128);
672             dqt_length -= 128;
673         }
674 
675         istrm.readBytes(dqt.table.ptr, dqt.table.length);
676 
677         version(JPEGDebug)
678         {
679             writefln("DQT precision: %s", dqt.precision);
680             writefln("DQT table id: %s", dqt.tableId);
681             writefln("DQT table: %s", dqt.table);
682         }
683     }
684 
685     return compound(true, "");
686 }
687 
688 Compound!(bool, string) readSOF0(JPEGImage* jpg, InputStream istrm)
689 {
690     ushort sof0_length = istrm.readNumeric!ushort(Endian.Big);
691     jpg.sof0.precision = istrm.readNumeric!ubyte;
692     jpg.sof0.height = istrm.readNumeric!ushort(Endian.Big);
693     jpg.sof0.width = istrm.readNumeric!ushort(Endian.Big);
694     jpg.sof0.componentsNum = istrm.readNumeric!ubyte;
695 
696     version(JPEGDebug)
697     {
698         writefln("SOF0 length: %s", sof0_length);
699         writefln("SOF0 precision: %s", jpg.sof0.precision);
700         writefln("SOF0 height: %s", jpg.sof0.height);
701         writefln("SOF0 width: %s", jpg.sof0.width);
702         writefln("SOF0 components: %s", jpg.sof0.componentsNum);
703     }
704 
705     jpg.sof0.components = New!(JPEGImage.SOF0Component[])(jpg.sof0.componentsNum);
706 
707     foreach(ref c; jpg.sof0.components)
708     {
709         ubyte c_id = istrm.readNumeric!ubyte;
710         ubyte bite = istrm.readNumeric!ubyte;
711         c.hSubsampling = bite.hiNibble;
712         c.vSubsampling = bite.loNibble;
713         c.dqtTableId = istrm.readNumeric!ubyte;
714         version(JPEGDebug)
715         {
716             writefln("SOF0 component id: %s", c_id);
717             writefln("SOF0 component %s hsubsampling: %s", c_id, c.hSubsampling);
718             writefln("SOF0 component %s vsubsampling: %s", c_id, c.vSubsampling);
719             writefln("SOF0 component %s table id: %s", c_id, c.dqtTableId);
720         }
721     }
722 
723     return compound(true, "");
724 }
725 
726 Compound!(bool, string) readDHT(JPEGImage* jpg, InputStream istrm)
727 {
728     ushort dht_length = istrm.readNumeric!ushort(Endian.Big);
729     version(JPEGDebug)
730     {
731         writefln("DHT length: %s", dht_length);
732     }
733 
734     dht_length -= 2;
735 
736     while(dht_length > 0)
737     {
738         JPEGImage.DHT* dht = jpg.addDHT();
739 
740         ubyte bite = istrm.readNumeric!ubyte;
741         dht_length--;
742         dht.clas = bite.hiNibble;
743         dht.tableId = bite.loNibble;
744 
745         ubyte[16] dht_code_lengths;
746         istrm.readBytes(dht_code_lengths.ptr, 16);
747         dht_length -= 16;
748 
749         version(JPEGDebug)
750         {
751             writefln("DHT class: %s (%s)",
752                 dht.clas,
753                 dht.clas? "AC":"DC");
754             writefln("DHT tableId: %s", dht.tableId);
755             writefln("DHT Huffman code lengths: %s", dht_code_lengths);
756         }
757 
758         // Read Huffman table
759         int totalCodes = reduce!("a + b")(0, dht_code_lengths);
760         int storedCodes = 0;
761         ubyte treeLevel = 0;
762         ushort bits = 0;
763 
764         while (storedCodes != totalCodes)
765         {
766             while (treeLevel < 15 &&
767                 dht_code_lengths[treeLevel] == 0)
768             {
769                 treeLevel++;
770                 bits *= 2;
771             }
772 
773             if (treeLevel < 16)
774             {
775                 uint bitsNum = treeLevel + 1;
776                 HuffmanCode code = HuffmanCode(bits, cast(ushort)bitsNum);
777 
778                 auto entry = HuffmanTableEntry(code, istrm.readNumeric!ubyte);
779                 dht.huffmanTable.append(entry);
780 
781                 dht_length--;
782 
783                 storedCodes++;
784                 bits++;
785                 dht_code_lengths[treeLevel]--;
786             }
787         }
788 
789         dht.huffmanTree = treeFromTable(dht.huffmanTable);
790     }
791 
792     return compound(true, "");
793 }
794 
795 Compound!(bool, string) readSOS(JPEGImage* jpg, InputStream istrm)
796 {
797     ushort sos_length = istrm.readNumeric!ushort(Endian.Big);
798     jpg.sos.componentsNum = istrm.readNumeric!ubyte;
799 
800     version(JPEGDebug)
801     {
802         writefln("SOS length: %s", sos_length);
803         writefln("SOS components: %s", jpg.sos.componentsNum);
804     }
805 
806     jpg.sos.components = New!(JPEGImage.SOSComponent[])(jpg.sos.componentsNum);
807 
808     foreach(ref c; jpg.sos.components)
809     {
810         ubyte c_id = istrm.readNumeric!ubyte;
811         ubyte bite = istrm.readNumeric!ubyte;
812         c.tableIdDC = bite.hiNibble;
813         c.tableIdAC = bite.loNibble;
814         version(JPEGDebug)
815         {
816             writefln("SOS component id: %s", c_id);
817             writefln("SOS component %s DC table id: %s", c_id, c.tableIdDC);
818             writefln("SOS component %s AC table id: %s", c_id, c.tableIdAC);
819         }
820     }
821 
822     jpg.sos.spectralSelectionStart = istrm.readNumeric!ubyte;
823     jpg.sos.spectralSelectionEnd = istrm.readNumeric!ubyte;
824     ubyte bite = istrm.readNumeric!ubyte;
825     jpg.sos.successiveApproximationBitHigh = bite.hiNibble;
826     jpg.sos.successiveApproximationBitLow = bite.loNibble;
827 
828     version(JPEGDebug)
829     {
830         writefln("SOS spectral selection start: %s", jpg.sos.spectralSelectionStart);
831         writefln("SOS spectral selection end: %s", jpg.sos.spectralSelectionEnd);
832         writefln("SOS successive approximation bit: %s", jpg.sos.successiveApproximationBitHigh);
833         writefln("SOS successive approximation bit low: %s", jpg.sos.successiveApproximationBitLow);
834     }
835 
836     return compound(true, "");
837 }
838 
839 struct ScanBitStream
840 {
841     InputStream istrm;
842 
843     bool endMarkerFound = false;
844     uint bytesRead = 0;
845     ubyte prevByte = 0x00;
846     ubyte curByte = 0x00;
847 
848     ubyte readNextByte()
849     {
850         ubyte b = istrm.readNumeric!ubyte;
851         bytesRead++;
852         endMarkerFound = (prevByte == 0xFF && b == 0xD9);
853         assert(!endMarkerFound);
854         if (!endMarkerFound)
855         {
856             prevByte = b;
857             curByte = b;
858             return b;
859         }
860         else
861         {
862             curByte = 0;
863         }
864         return curByte;
865     }
866 
867     bool readable()
868     {
869         return !istrm.readable || endMarkerFound;
870     }
871 
872     uint bitPos = 0;
873 
874     // Huffman decode a byte
875     Compound!(bool, string) decodeByte(HuffmanTreeNode* node, ubyte* result)
876     {
877         while(!node.isLeaf)
878         {
879             ubyte b = curByte;
880 
881             bool bit = getBit(b, 7-bitPos);
882             bitPos++;
883             if (bitPos == 8)
884             {
885                 bitPos = 0;
886                 readNextByte();
887 
888                 if (b == 0xFF)
889                 {
890                     b = curByte;
891                     if (b == 0x00)
892                     {
893                         readNextByte();
894                     }
895                 }
896             }
897 
898             if (bit)
899                 node = node.right;
900             else
901                 node = node.left;
902 
903             if (node is null)
904                 return compound(false, "loadJPEG error: no Huffman code found");
905         }
906 
907         *result = node.ch;
908         return compound(true, "");
909     }
910 
911     // Read len bits from stream to buffer
912     uint readBits(ubyte len)
913     {
914         uint buffer = 0;
915         uint i = 0;
916         uint by = 0;
917         uint bi = 0;
918 
919         while (i < len)
920         {
921             ubyte b = curByte;
922 
923             bool bit = getBit(b, 7-bitPos);
924             buffer = setBit(buffer, (by * 8 + bi), bit);
925 
926             bi++;
927             if (bi == 8)
928             {
929                 bi = 0;
930                 by++;
931             }
932 
933             i++;
934 
935             bitPos++;
936             if (bitPos == 8)
937             {
938                 bitPos = 0;
939                 readNextByte();
940 
941                 if (b == 0xFF)
942                 {
943                     b = curByte;
944                     if (b == 0x00)
945                         readNextByte();
946                 }
947             }
948         }
949 
950         return buffer;
951     }
952 }
953 
954 /*
955  *  Decodes compressed data and creates RGB image from it
956  */
957 Compound!(SuperImage, string) decodeScanData(
958     JPEGImage* jpg,
959     InputStream istrm,
960     SuperImageFactory imgFac)
961 {
962     SuperImage img = imgFac.createImage(jpg.sof0.width, jpg.sof0.height, 3, 8);
963 
964     MCU mcu;
965     foreach(ci, ref c; jpg.sof0.components)
966     {
967         if (ci == 0)
968             mcu.createYBlocks(c.hSubsampling, c.vSubsampling);
969         else if (ci == 1)
970             mcu.createCbBlocks(c.hSubsampling, c.vSubsampling);
971         else if (ci == 2)
972             mcu.createCrBlocks(c.hSubsampling, c.vSubsampling);
973     }
974 
975     Compound!(SuperImage, string) error(string errorMsg)
976     {
977         mcu.free();
978         if (img)
979         {
980             img.free();
981             img = null;
982         }
983         return compound(img, errorMsg);
984     }
985 
986     // Decode DCT coefficient from bit buffer
987     int decodeCoef(uint buffer, ubyte numBits)
988     {
989         bool positive = getBit(buffer, 0);
990 
991         int value = 0;
992         foreach(j; 0..numBits)
993         {
994             bool bit = getBit(buffer, numBits-1-j);
995             value = setBit(value, j, bit);
996         }
997 
998         if (positive)
999             return value;
1000         else
1001             return value - 2^^numBits + 1;
1002     }
1003 
1004     static const ubyte[64] dezigzag =
1005     [
1006          0,  1,  8, 16,  9,  2,  3, 10,
1007         17, 24, 32, 25, 18, 11,  4,  5,
1008         12, 19, 26, 33, 40, 48, 41, 34,
1009         27, 20, 13,  6,  7, 14, 21, 28,
1010         35, 42, 49, 56, 57, 50, 43, 36,
1011         29, 22, 15, 23, 30, 37, 44, 51,
1012         58, 59, 52, 45, 38, 31, 39, 46,
1013         53, 60, 61, 54, 47, 55, 62, 63
1014     ];
1015 
1016     if (jpg.sos.componentsNum != 3)
1017     {
1018         return error(format(
1019                 "loadJPEG error: unsupported number of components: %s",
1020                 jpg.sos.componentsNum));
1021     }
1022 
1023     // Store previous DC coefficients
1024     int[3] dcCoefPrev;
1025 
1026     if (jpg.dqt.length == 0)
1027         return error("loadJPEG error: no DQTs found");
1028 
1029     ScanBitStream sbs;
1030     sbs.endMarkerFound = false;
1031     sbs.bytesRead = 0;
1032     sbs.prevByte = 0x00;
1033     sbs.curByte = 0x00;
1034     sbs.istrm = istrm;
1035     sbs.readNextByte();
1036 
1037     uint numMCUsH = jpg.sof0.width / mcu.width + ((jpg.sof0.width % mcu.width) > 0);
1038     uint numMCUsV = jpg.sof0.height / mcu.height + ((jpg.sof0.height % mcu.height) > 0);
1039 
1040     // Read MCUs
1041     foreach(mcuY; 0..numMCUsV)
1042     foreach(mcuX; 0..numMCUsH)
1043     {
1044         // Read MCU for each channel
1045         foreach(ci, ref c; jpg.sos.components)
1046         {
1047             auto tableDC = jpg.getHuffmanTable(0, c.tableIdDC);
1048             auto tableAC = jpg.getHuffmanTable(1, c.tableIdAC);
1049 
1050             if (tableDC is null)
1051                 return error("loadJPEG error: illegal DC table index in MCU component");
1052             if (tableAC is null)
1053                 return error("loadJPEG error: illegal AC table index in MCU component");
1054 
1055             auto component = jpg.sof0.components[ci];
1056             auto hblocks = component.hSubsampling;
1057             auto vblocks = component.vSubsampling;
1058             auto dqtTableId = component.dqtTableId;
1059             if (dqtTableId >= jpg.dqt.length)
1060                 return error("loadJPEG error: illegal DQT table index in MCU component");
1061 
1062             // Read 8x8 blocks
1063             foreach(by; 0..vblocks)
1064             foreach(bx; 0..hblocks)
1065             {
1066                 int[8*8] block;
1067 
1068                 // Read DC coefficient
1069                 ubyte dcDiffLen;
1070                 auto res = sbs.decodeByte(tableDC.huffmanTree, &dcDiffLen);
1071                 if (!res[0]) return error(res[1]);
1072 
1073                 if (dcDiffLen > 0)
1074                 {
1075                     uint dcBuffer = sbs.readBits(dcDiffLen);
1076                     dcCoefPrev[ci] += decodeCoef(dcBuffer, dcDiffLen);
1077                 }
1078 
1079                 block[0] = dcCoefPrev[ci];
1080 
1081                 // Read AC coefficients
1082                 {
1083                     uint i = 1;
1084                     bool eob = false;
1085                     while (!eob && i < 64)
1086                     {
1087                         ubyte code;
1088                         res = sbs.decodeByte(tableAC.huffmanTree, &code);
1089                         if (!res[0]) return error(res[1]);
1090 
1091                         if (code == 0x00) // EOB, all next values are zero
1092                             eob = true;
1093                         else if (code == 0xF0) // ZRL, next 16 values are zero
1094                         {
1095                             foreach(j; 0..16)
1096                             if (i < 64)
1097                             {
1098                                 block[i] = 0;
1099                                 i++;
1100                             }
1101                         }
1102                         else
1103                         {
1104                             ubyte hi = hiNibble(code);
1105                             ubyte lo = loNibble(code);
1106 
1107                             uint zeroes = hi;
1108                             foreach(j; 0..zeroes)
1109                             if (i < 64)
1110                             {
1111                                 block[i] = 0;
1112                                 i++;
1113                             }
1114 
1115                             int acCoef = 0;
1116                             if (lo > 0)
1117                             {
1118                                 uint acBuffer = sbs.readBits(lo);
1119                                 acCoef = decodeCoef(acBuffer, lo);
1120                             }
1121 
1122                             if (i < 64)
1123                                 block[i] = acCoef;
1124 
1125                             i++;
1126                         }
1127                     }
1128                 }
1129 
1130                 // Multiply block by quantization matrix
1131                 foreach(i, ref v; block)
1132                     v *= jpg.dqt[dqtTableId].table[i];
1133 
1134                 // Convert matrix from zig-zag order to normal order
1135                 int[8*8] dctMatrix;
1136 
1137                 foreach(i, v; block)
1138                     dctMatrix[dezigzag[i]] = v;
1139 
1140                 idct64(dctMatrix.ptr);
1141 
1142                 // Copy the matrix into corresponding channel
1143                 int* outMatrixPtr;
1144                 if (ci == 0)
1145                     outMatrixPtr = mcu.yBlocks[by * hblocks + bx].ptr;
1146                 else if (ci == 1)
1147                     outMatrixPtr = mcu.cbBlocks[by * hblocks + bx].ptr;
1148                 else if (ci == 2)
1149                     outMatrixPtr = mcu.crBlocks[by * hblocks + bx].ptr;
1150                 else
1151                     return error("loadJPEG error: illegal component index");
1152 
1153                 for(uint i = 0; i < 64; i++)
1154                     outMatrixPtr[i] = dctMatrix[i];
1155             }
1156         }
1157 
1158         // Convert MCU from YCbCr to RGB
1159         foreach(y; 0..mcu.height) // Pixel coordinates in MCU
1160         foreach(x; 0..mcu.width)
1161         {
1162             //Color4f col = mcu.getPixel(x, y);
1163             uint col = mcu.getPixel(x, y);
1164 
1165             // Pixel coordinates in image
1166             uint ix = mcuX * mcu.width + x;
1167             uint iy = mcuY * mcu.height + y;
1168 
1169             if (ix < img.width && iy < img.height)
1170                 img[ix, iy] = col;
1171         }
1172     }
1173 
1174     version(JPEGDebug)
1175     {
1176         writefln("Bytes read: %s", sbs.bytesRead);
1177     }
1178 
1179     mcu.free();
1180 
1181     return compound(img, "");
1182 }
1183 
1184 /*
1185  * MCU struct keeps a storage for one Minimal Code Unit
1186  * and provides a generalized interface for decoding
1187  * images with different subsampling modes.
1188  * Decoder should read 8x8 blocks one by one for each channel
1189  * and fill corresponding arrays in MCU.
1190  */
1191 struct MCU
1192 {
1193     uint width;
1194     uint height;
1195 
1196     alias int[8*8] Block;
1197     Block[] yBlocks;
1198     Block[] cbBlocks;
1199     Block[] crBlocks;
1200 
1201     uint ySamplesH, ySamplesV;
1202     uint cbSamplesH, cbSamplesV;
1203     uint crSamplesH, crSamplesV;
1204 
1205     uint yWidth, yHeight;
1206     uint cbWidth, cbHeight;
1207     uint crWidth, crHeight;
1208 
1209     void createYBlocks(uint hsubsampling, uint vsubsampling)
1210     {
1211         yBlocks = New!(Block[])(hsubsampling * vsubsampling);
1212 
1213         width = hsubsampling * 8;
1214         height = vsubsampling * 8;
1215 
1216         ySamplesH = hsubsampling;
1217         ySamplesV = vsubsampling;
1218 
1219         yWidth = width / ySamplesH;
1220         yHeight = height / ySamplesV;
1221     }
1222 
1223     void createCbBlocks(uint hsubsampling, uint vsubsampling)
1224     {
1225         cbBlocks = New!(Block[])(hsubsampling * vsubsampling);
1226 
1227         cbSamplesH = hsubsampling;
1228         cbSamplesV = vsubsampling;
1229 
1230         cbWidth = width / cbSamplesH;
1231         cbHeight = height / cbSamplesV;
1232     }
1233 
1234     void createCrBlocks(uint hsubsampling, uint vsubsampling)
1235     {
1236         crBlocks = New!(Block[])(hsubsampling * vsubsampling);
1237 
1238         crSamplesH = hsubsampling;
1239         crSamplesV = vsubsampling;
1240 
1241         crWidth = width / crSamplesH;
1242         crHeight = height / crSamplesV;
1243     }
1244 
1245     void free()
1246     {
1247         if (yBlocks.length) Delete(yBlocks);
1248         if (cbBlocks.length) Delete(cbBlocks);
1249         if (crBlocks.length) Delete(crBlocks);
1250     }
1251 
1252     uint getPixel(uint x, uint y) // coordinates relative to upper-left MCU corner
1253     {
1254         // Y block coordinates
1255         uint ybx = x / yWidth;
1256         uint yby = y / yHeight;
1257         uint ybi = yby * ySamplesH + ybx;
1258 
1259         // Pixel coordinates in Y block
1260         uint ybpx = x - ybx * yWidth;
1261         uint ybpy = y - yby * yHeight;
1262 
1263         // Cb block coordinates
1264         uint cbx = x / cbWidth;
1265         uint cby = y / cbHeight;
1266         uint cbi = cby * cbSamplesH + cbx;
1267 
1268         // Pixel coordinates in Cb block
1269         uint cbpx = (x - cbx * cbWidth)  / ySamplesH;
1270         uint cbpy = (y - cby * cbHeight) / ySamplesV;
1271 
1272         // Cr block coordinates
1273         uint crx = x / crWidth;
1274         uint cry = y / crHeight;
1275         uint cri = cry * crSamplesH + crx;
1276 
1277         // Pixel coordinates in Cr block
1278         uint crpx = (x - crx * crWidth)  / ySamplesH;
1279         uint crpy = (y - cry * crHeight) / ySamplesV;
1280 
1281         // Get color components
1282         float Y  = cast(float)yBlocks [ybi][ybpy * 8 + ybpx] + 128.0f;
1283         float Cb = cast(float)cbBlocks[cbi][cbpy * 8 + cbpx];
1284         float Cr = cast(float)crBlocks[cri][crpy * 8 + crpx];
1285 
1286         // Convert from YCbCr to RGB
1287         //Color4f col;
1288         uint col_r = clamp(Y + 1.402f * Cr);
1289         uint col_g = clamp(Y - 0.34414f * Cb - 0.71414f * Cr);
1290         uint col_b = clamp(Y + 1.772f * Cb);
1291         //col = col / 255.0f;
1292         //col.a = 1.0f;
1293 
1294         return 0xFF000000 | (col_r << 16) | (col_g << 8) | (col_b) ;
1295     }
1296 }
1297 
1298 uint clamp(float v) {
1299     import std.conv;
1300     if (v < 0)
1301         return 0;
1302     uint res = to!uint(v);
1303     if (v > 255)
1304         return 255;
1305     return res;
1306 }