1 // Written in the D programming language.
2 
3 /**
4 * Copyright: Copyright 2012 -
5 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Callum Anderson
7 * Date: June 6, 2012
8 */
9 module imaged.jpeg;
10 
11 import
12     std.file,
13     std.stdio,
14     std.math,
15     std.algorithm,
16     std.conv,
17     undead.stream;
18 
19 import
20     imaged.image;
21 
22 // Clamp an integer to 0-255 (ubyte)
23 ubyte clamp(const int x)
24 {
25     return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : cast(ubyte) x);
26 }
27 
28 
29 /**
30 * Jpeg decoder. Great reference for baseline JPEG
31 * deconding: http://www.opennet.ru/docs/formats/jpeg.txt.
32 */
33 class JpegDecoder : Decoder
34 {
35 
36     // Algorithms for upsampling the chroma components, defaults to NEAREST.
37     enum Upsampling
38     {
39         NEAREST,  // Nearest neighbour (fastest)
40         BILINEAR  // Bilinear interpolation
41     }
42 
43 
44     // Empty constructor, useful for parsing a stream manually
45     this(in bool logging = false, in Upsampling algo = Upsampling.NEAREST)
46     {
47         m_logging = logging;
48 
49         // Set the resampling algorithm delegate
50         if (algo == Upsampling.NEAREST)
51         {
52             resampleDgt = &nearestNeighbourResample;
53         }
54         else if (algo == Upsampling.BILINEAR)
55         {
56             resampleDgt = &bilinearResample;
57         }
58     }
59 
60 
61     // Constructor taking a filename
62     this(in string filename, in bool logging = false, in Upsampling algo = Upsampling.NEAREST)
63     {
64         this(logging, algo);
65         parseFile(filename);
66     }
67 
68 
69     // Parse a single byte
70     override void parseByte(ubyte bite)
71     {
72         segment.buffer ~= bite;
73 
74         if (bite == 0xFF)
75         {
76             markerPending = true;
77             return;
78         }
79 
80         if (markerPending)
81         {
82             markerPending = false;
83 
84             if (bite == 0x00)   // This is an 0xFF value
85             {
86                 segment.buffer = segment.buffer[0..$-1];
87                 bite = 0xFF;
88             }
89             else if (bite >= 0xD0 && bite <= 0xD7)     // Restart marker
90             {
91                 segment.buffer = segment.buffer[0..$-2];
92                 return;
93             }
94             else if (cast(Marker)bite == Marker.EndOfImage)
95             {
96                 previousMarker = currentMarker;
97                 currentMarker = cast(Marker) bite;
98                 endOfImage();
99                 return;
100             }
101             else
102             {
103                 previousMarker = currentMarker;
104                 currentMarker = cast(Marker) bite;
105                 segment = JPGSegment();
106                 return;
107             }
108         }
109 
110         if (!segment.headerProcessed)
111         {
112             if (segment.buffer.length == 2)
113             {
114                 segment.headerLength = (segment.buffer[0] << 8 | segment.buffer[1]);
115                 return;
116             }
117             else if (segment.buffer.length == segment.headerLength)
118             {
119                 debug
120                 {
121                     if (m_logging) writeln(currentMarker);
122                 }
123 
124                 processHeader();
125                 segment.headerProcessed = true;
126                 segment.buffer.destroy;
127                 return;
128             }
129         }
130         else
131         {
132             if (currentMarker == Marker.StartOfScan)
133             {
134                 sosAction(bite);
135             }
136         }
137 
138         totalBytesParsed ++;
139     } // parse
140 
141 
142 private:
143 
144     // Markers courtesy of http://techstumbler.blogspot.com/2008/09/jpeg-marker-codes.html
145     enum Marker
146     {
147         None = 0x00,
148 
149         // Start of Frame markers, non-differential, Huffman coding
150         HuffBaselineDCT = 0xC0,
151         HuffExtSequentialDCT = 0xC1,
152         HuffProgressiveDCT = 0xC2,
153         HuffLosslessSeq = 0xC3,
154 
155         // Start of Frame markers, differential, Huffman coding
156         HuffDiffSequentialDCT = 0xC5,
157         HuffDiffProgressiveDCT = 0xC6,
158         HuffDiffLosslessSeq = 0xC7,
159 
160         // Start of Frame markers, non-differential, arithmetic coding
161         ArthBaselineDCT = 0xC8,
162         ArthExtSequentialDCT = 0xC9,
163         ArthProgressiveDCT = 0xCA,
164         ArthLosslessSeq = 0xCB,
165 
166         // Start of Frame markers, differential, arithmetic coding
167         ArthDiffSequentialDCT = 0xCD,
168         ArthDiffProgressiveDCT = 0xCE,
169         ArthDiffLosslessSeq = 0xCF,
170 
171         // Huffman table spec
172         HuffmanTableDef = 0xC4,
173 
174         // Arithmetic table spec
175         ArithmeticTableDef = 0xCC,
176 
177         // Restart Interval termination
178         RestartIntervalStart = 0xD0,
179         RestartIntervalEnd = 0xD7,
180 
181         // Other markers
182         StartOfImage = 0xD8,
183         EndOfImage = 0xD9,
184         StartOfScan = 0xDA,
185         QuantTableDef = 0xDB,
186         NumberOfLinesDef = 0xDC,
187         RestartIntervalDef = 0xDD,
188         HierarchProgressionDef = 0xDE,
189         ExpandRefComponents = 0xDF,
190 
191         // Restarts
192         Rst0 = 0xD0, Rst1 = 0xD1, Rst2 = 0xD2, Rst3 = 0xD3,
193         Rst4 = 0xD4, Rst5 = 0xD5, Rst6 = 0xD6, Rst7 = 0xD7,
194 
195         // App segments
196         App0 = 0xE0, App1 = 0xE1, App2 = 0xE2, App3 = 0xE3,
197         App4 = 0xE4, App5 = 0xE5, App6 = 0xE6, App7 = 0xE7,
198         App8 = 0xE8, App9 = 0xE9, App10 = 0xEA, App11 = 0xEB,
199         App12 = 0xEC, App13 = 0xED, App14 = 0xEE, App15 = 0xEF,
200 
201         // Jpeg Extensions
202         JpegExt0 = 0xF0, JpegExt1 = 0xF1, JpegExt2 = 0xF2, JpegExt3 = 0xF3,
203         JpegExt4 = 0xF4, JpegExt5 = 0xF5, JpegExt6 = 0xF6, JpegExt7 = 0xF7,
204         JpegExt8 = 0xF8, JpegExt9 = 0xF9, JpegExtA = 0xFA, JpegExtB = 0xFB,
205         JpegExtC = 0xFC, JpegExtD = 0xFD,
206 
207         // Comments
208         Comment = 0xFE,
209 
210         // Reserved
211         ArithTemp = 0x01,
212         ReservedStart = 0x02,
213         ReservedEnd = 0xBF
214     };
215 
216     // Value at dctComponent[ix] should go to grid[block_order[ix]]
217     immutable static ubyte[] block_order =
218         [ 0,  1,  8, 16,  9,  2,  3, 10,   17, 24, 32, 25, 18, 11,  4,  5,
219           12, 19, 26, 33, 40, 48, 41, 34,   27, 20, 13,  6,  7, 14, 21, 28,
220           35, 42, 49, 56, 57, 50, 43, 36,   29, 22, 15, 23, 30, 37, 44, 51,
221           58, 59, 52, 45, 38, 31, 39, 46,   53, 60, 61, 54, 47, 55, 62, 63 ];
222 
223     ulong totalBytesParsed = 0;
224     ulong segmentBytesParsed = 0;
225     Marker currentMarker = Marker.None;
226     Marker previousMarker = Marker.None;
227     bool markerPending = false;
228     void delegate(uint cmpIndex) resampleDgt;
229 
230     string format = "unknown"; // File format (will only do JFIF)
231     ubyte nComponents, precision;
232 
233     struct Component
234     {
235         int id, // component id
236         qtt, // quantization table id
237         h_sample, // horizontal samples
238         v_sample; // vertical samples
239         ubyte[] data; // a single MCU of data for this component
240         int x, y; // x, y are size of MCU
241     }
242     Component[] components;
243 
244     // Store the image comment field if any
245     char[] comment;
246 
247     // Quantization Tables (hash map of ubyte[64]'s, indexed by table index)
248     ubyte[][int] quantTable;
249 
250     // Huffman tables are stored in a hash map
251     ubyte[16] nCodes; // Number of codes of each bit length .destroyed after each table is defined)
252     struct hashKey
253     {
254         ubyte index;    // Table index
255         ubyte nBits;    // Number of bits in code
256         short bitCode;  // Actual bit code
257     }
258     ubyte[hashKey] huffmanTable;
259 
260     // Track the state of a scan segment
261     struct ScanState
262     {
263         short cmpIdx = 0; // Current component index in scan
264 
265         int MCUWidth, MCUHeight; // Dimensions of an MCU
266         int nxMCU, nyMCU, xMCU, yMCU; // Number of MCU's, and current MCU
267 
268         uint buffer = 0, bufferLength = 0, needBits = 0;
269         bool comparing = true;
270         ubyte[3] dct, act, nCmpBlocks; // dct, act store the DC and AC table indexes for each component
271 
272         int[3] dcTerm;  // DC coefficients for each component
273         int[64] dctComponents; // DCT coefficients for current component
274         uint dctCmpIndex = 0, blockNumber = 0; // DCT coefficient index and current block in MCU
275         int restartInterval; // How many MCU's are parsed before a restart (reset the DC terms)
276         int MCUSParsed; // Number of image MCU's parsed, for use with restart interval
277     }
278     ScanState scState; // ditto
279 
280     struct JPGSegment
281     {
282         bool headerProcessed;
283         int headerLength;
284         ubyte[] buffer;
285     }
286     JPGSegment segment;
287 
288     bool m_logging;
289     short x, y; // These are the final image width and height
290 
291     // Process a segment header
292     void processHeader()
293     {
294         /**
295         * Remember: first two bytes in the buffer are the header length,
296         * so header info starts at segment.buffer[2]!
297         */
298         switch(currentMarker)
299         {
300         case Marker.Comment: // Comment segment
301         {
302             comment = cast(char[])segment.buffer[2..$];
303 
304             debug
305             {
306                 if (m_logging) writeln("JPEG: Comment: ", comment);
307             }
308             break;
309         }
310         case Marker.App0: // App0, indicates JFIF format
311         {
312             if (previousMarker == Marker.StartOfImage)
313             {
314                 format = "JFIF";
315             }
316             break;
317         }
318         case Marker.RestartIntervalDef: // Restart interval definition
319         {
320             scState.restartInterval = cast(int) (segment.buffer[2] << 8 | segment.buffer[3]);
321 
322             debug
323             {
324                 if (m_logging) writeln("JPEG: Restart interval = ", scState.restartInterval);
325             }
326             break;
327         }
328         case Marker.QuantTableDef: // A quantization table definition
329         {
330             for (int i = 2; i < segment.buffer.length; i += 65)
331             {
332                 int precision = (segment.buffer[i] >> 4);
333                 int index = (segment.buffer[i] & 0x0F);
334                 quantTable[index] = segment.buffer[i+1..i+1+64].dup;
335 
336                 debug
337                 {
338                     if (m_logging) writefln("JPEG: Quantization table %s defined", index);
339                 }
340             }
341             break;
342         }
343         case Marker.HuffBaselineDCT: // Baseline frame
344         {
345             ubyte precision = segment.buffer[2];
346             y = cast(short) (segment.buffer[3] << 8 | segment.buffer[4]);
347             x = cast(short) (segment.buffer[5] << 8 | segment.buffer[6]);
348             nComponents = segment.buffer[7];
349             components.length = nComponents;
350 
351             int i = 8;
352             foreach(cmp; 0..nComponents)
353             {
354                 components[cmp].id = segment.buffer[i];
355                 components[cmp].h_sample = (segment.buffer[i+1] >> 4);
356                 components[cmp].v_sample = (segment.buffer[i+1] & 0x0F);
357                 components[cmp].qtt = segment.buffer[i+2];
358                 i += 3;
359 
360                 debug
361                 {
362                     if (m_logging) writefln("JPEG: Component %s defined", cmp);
363                 }
364             }
365             break;
366         }
367         case Marker.HuffProgressiveDCT: // Progressive JPEG, cannot decode
368         {
369             m_errorState.code = 1;
370             m_errorState.message = "JPG: Progressive JPEG detected, unable to load";
371             break;
372         }
373         case Marker.HuffmanTableDef: // Huffman Table Definition, the mapping between bitcodes and Huffman codes
374         {
375             int i = 2;
376             while (i < segment.buffer.length)
377             {
378                 ubyte index = segment.buffer[i]; // Huffman table index
379                 i ++;
380 
381                 auto nCodes = segment.buffer[i..i+16]; // Number of codes at each tree depth
382                 int totalCodes = reduce!("a + b")(0, nCodes); // Sum up total codes, so we know when we are done
383                 int storedCodes = 0;
384                 i += 16;
385 
386                 ubyte huffmanRow = 0;
387                 short huffmanCol = 0;
388                 while (storedCodes != totalCodes)
389                 {
390                     /**
391                     * If nCodes is zero, we need to move down the table. The 'table'
392                     * is basically a binary tree, seen as an array.
393                     */
394                     while (huffmanRow < 15 && nCodes[huffmanRow] == 0)
395                     {
396                         huffmanRow ++;
397                         huffmanCol *= 2;
398                     }
399 
400                     if (huffmanRow < 16)
401                     {   // Store the code into the hash table, using index, row and bitcode to make the key
402                         hashKey key = { index:index, nBits: cast(ubyte)(huffmanRow+1), bitCode: huffmanCol};
403                         huffmanTable[key] = segment.buffer[i];
404                         storedCodes ++;
405                         huffmanCol ++;
406                         nCodes[huffmanRow] --;
407                         i ++;
408                     }
409                 } // while storedCodes != totalCodes
410             }
411             break;
412         }
413         case Marker.StartOfScan: // StartOfScan (image data) header
414         {
415             int scanComponents = segment.buffer[2]; // Number of components in the scan
416 
417             if (scanComponents != nComponents)
418             {
419                 throw new Exception("JPEG: Scan components != image components!");
420             }
421 
422             int i = 3;
423             foreach (cmp; 0..scanComponents)
424             {
425                 ubyte id = cast(ubyte)(segment.buffer[i] - 1);
426                 scState.dct[id] = segment.buffer[i+1] >> 4;   // Component's DC huffman table
427                 scState.act[id] = segment.buffer[i+1] & 0x0F; // Component's AC huffman table
428             }
429             // There is more to the header, but it is not needed
430 
431 
432             // Calculate MCU dimensions
433             int v_samp_max = 0, h_samp_max = 0;
434             foreach (cmp; components)
435             {
436                 if (cmp.h_sample > h_samp_max)
437                     h_samp_max = cmp.h_sample;
438                 if (cmp.v_sample > v_samp_max)
439                     v_samp_max = cmp.v_sample;
440             }
441             scState.MCUWidth = h_samp_max*8;
442             scState.MCUHeight = v_samp_max*8;
443 
444             // Number of MCU's in the whole transformed image (the actual image could be smaller)
445             scState.nxMCU = x / scState.MCUWidth;
446             scState.nyMCU = y / scState.MCUHeight;
447             if (x % scState.MCUWidth > 0)
448                 scState.nxMCU ++;
449             if (y % scState.MCUHeight > 0)
450                 scState.nyMCU ++;
451 
452             // Allocate the image
453             m_image = new Img!(Px.R8G8B8)(scState.nxMCU*scState.MCUWidth,
454                                           scState.nyMCU*scState.MCUHeight);
455 
456 
457             // Calculate the number of pixels for each component from the number of MCU's and sampling rate
458             foreach (idx, ref cmp; components)
459             {
460                 // Just make it big enough for a single MCU
461                 cmp.x = cmp.h_sample*8;
462                 cmp.y = cmp.v_sample*8;
463                 cmp.data = new ubyte[](cmp.x*cmp.y);
464 
465                 debug
466                 {
467                     if (m_logging) writefln("Component %s, x:%s, y:%s", idx, cmp.x, cmp.y);
468                 }
469             }
470             break;
471         }
472         default:
473         {
474             debug
475             {
476                 if (m_logging) writeln("JPEG: ProcessHeader called on un-handled segment: ", currentMarker);
477             }
478             break;
479         }
480         }
481 
482     }
483 
484 
485     // Start of scan (image)
486     void sosAction(ubyte bite)
487     {
488         // Put the new bite into the buffer
489         scState.buffer = scState.buffer << 8 | bite ;
490         scState.bufferLength += 8;
491         segment.buffer.destroy;
492 
493         while (scState.bufferLength >= scState.needBits)
494         {
495             if (scState.comparing)
496             {
497                 // Try to get a Huffman code from the buffer
498                 ubyte* huffCode = fetchHuffmanCode(scState.buffer,
499                                                    scState.bufferLength,
500                                                    scState.needBits,
501                                                    scState.cmpIdx);
502 
503                 if (huffCode !is null)   // Found a valid huffman code
504                 {
505                     // Our buffer has effectively shrunk by the number of bits we just took
506                     scState.bufferLength -= scState.needBits;
507                     scState.needBits = 1;
508 
509                     processHuffmanCode(*huffCode);
510                     continue;
511                 }
512                 else     // Failed to get a Huffman code, try with more bits
513                 {
514                     scState.needBits ++;
515                 }
516 
517             }
518             else     // Not comparing, getting value bits
519             {
520                 if (scState.bufferLength < scState.needBits) continue; // Need more bits in the buffer
521 
522                 // We have enough bits now to grab the value, so do that
523                 int dctComp = fetchDCTComponent(scState.buffer,
524                                                 scState.bufferLength,
525                                                 scState.needBits);
526 
527                 //.destroy these bits from the buffer, set flag back to 'comparing'
528                 scState.bufferLength -= scState.needBits;
529                 scState.comparing = true;
530 
531                 // Put the new value into the component array
532                 scState.dctComponents[scState.dctCmpIndex] = dctComp;
533 
534                 scState.dctCmpIndex ++; // Increment our index in the components array
535                 if (scState.dctCmpIndex == 64) endOfBlock(); // If we have reached the last index, this is end of block
536                 scState.needBits = 1; // Reset the number of bits we need for comparing
537 
538             } // if !comparing
539         } // while bufferLength >= needBits
540     } // sosAction
541 
542 
543     // Check the buffer for a valid Huffman code
544     ubyte* fetchHuffmanCode(int buffer, int bufferLength, int needBits, int componentIndex)
545     {
546         // Create a mask to compare needBits bits in the buffer
547         uint mask = ((1 << needBits) - 1) << (bufferLength-needBits);
548         ushort bitCode = cast(ushort) ((mask & buffer) >> (bufferLength - needBits));
549 
550         ubyte tableId = 0;
551         ubyte huffIndex = cast(ubyte) (componentIndex != 0);
552 
553         if (scState.dctCmpIndex != 0)   // This is an AC component
554         {
555             huffIndex += 16;
556             tableId = scState.act[componentIndex];
557         }
558         else                            // This is a DC component
559         {
560             tableId = scState.dct[componentIndex];
561         }
562 
563         hashKey key = hashKey(huffIndex, cast(ubyte)needBits, bitCode);
564         return (key in huffmanTable);
565 
566     } // fetchHuffmanCode
567 
568 
569     // Process a Huffman code
570     void processHuffmanCode(short huffCode)
571     {
572         if (huffCode == 0x00)   // END OF BLOCK
573         {
574             if (scState.dctCmpIndex == 0)   // If we are on the DC term, don't call end of block...
575             {
576                 scState.dctCmpIndex ++; // just increment the index
577             }
578             else
579             {
580                 endOfBlock();
581             }
582 
583         }
584         else     // Not an end of block
585         {
586             // The zero run length (not used for the DC component)
587             ubyte preZeros = cast(ubyte) (huffCode >> 4);
588 
589             // Increment the index by the number of preceeding zeros
590             scState.dctCmpIndex += preZeros;
591 
592             // The number of bits we need to get an actual value
593             if (scState.dctCmpIndex == 64)   // Check if we are at the end of the block
594             {
595                 endOfBlock();
596             }
597             else
598             {
599                 scState.comparing = false; // Not comparing bits anymore, waiting for a bitcode
600                 scState.needBits = cast(uint) (huffCode & 0x0F); // Number of bits in the bitcode
601             }
602         }
603     } // processHuffmanCode
604 
605 
606     // Fetch the actual DCT component value
607     int fetchDCTComponent(int buffer, int bufferLength, int needBits)
608     {
609         // Create a mask to get the value from the (int) buffer
610         uint mask = ((1 << needBits) - 1) << (bufferLength-needBits);
611         short bits = cast(short) ((mask & buffer) >> (bufferLength - needBits));
612 
613         // The first bit tells us which side of the value table we are on (- or +)
614         int bit0 = bits >> (needBits-1);
615         int offset = 2^^needBits;
616         return (bits & ((1 << (needBits-1)) - 1)) + (bit0*offset/2 - (1-bit0)*(offset - 1));
617     } // fetchDCTComponent
618 
619 
620     // Have reached the end of a block, within a scan
621     void endOfBlock()
622     {
623         // Convert the DC value from relative to absolute
624         scState.dctComponents[0] += scState.dcTerm[scState.cmpIdx];
625 
626         // Store this block's DC term, to apply to the next block
627         scState.dcTerm[scState.cmpIdx] = scState.dctComponents[0];
628 
629         // Grab the quantization table for this component
630         int[] qTable = to!(int[])(quantTable[components[scState.cmpIdx].qtt]);
631 
632         // Dequantize the coefficients
633         scState.dctComponents[] *= qTable[];
634 
635         // Un zig-zag
636         int[64] block;
637         foreach (idx, elem; block_order)
638         {
639             block[elem] = scState.dctComponents[idx];
640         }
641 
642         // Calculate the offset into the component's pixel array
643         int offset = 0;
644         with (scState)
645         {
646             // Each component now only holds a single MCU
647             offset = 8*( (blockNumber % 2) + (blockNumber / 2)*components[cmpIdx].x);
648         }
649 
650         // The recieving buffer of the IDCT is then the component's pixel array
651         ubyte* pix = components[scState.cmpIdx].data.ptr + offset;
652 
653         // Do the inverse discrete cosine transform
654         foreach(i; 0..8) colIDCT(block.ptr + i); // columns
655         foreach(i; 0..8) rowIDCT(block.ptr + i*8, pix + i*components[scState.cmpIdx].x); // rows
656 
657         scState.dctCmpIndex = 0;
658         scState.dctComponents[] = 0;
659         scState.comparing = true;
660 
661         // We have just decoded an 8x8 'block'
662         scState.blockNumber ++;
663 
664         if (scState.blockNumber == components[scState.cmpIdx].h_sample*components[scState.cmpIdx].v_sample)
665         {
666             // All the components in this block have been parsed
667             scState.blockNumber = 0;
668             scState.cmpIdx ++;
669 
670             if (scState.cmpIdx == nComponents)
671             {
672                 // All components in the MCU have been parsed, so increment
673                 endOfMCU();
674                 scState.cmpIdx = 0;
675                 scState.MCUSParsed ++;
676                 scState.xMCU ++;
677                 if (scState.xMCU == scState.nxMCU)
678                 {
679                     scState.xMCU = 0;
680                     scState.yMCU ++;
681                 }
682             }
683         } // if done all blocks for this component in the current MCU
684 
685         // Check for restart marker
686         if (scState.restartInterval != 0 && scState.MCUSParsed == scState.restartInterval)
687         {
688             // We have come up to a restart marker, so reset the DC terms
689             scState.dcTerm[] = 0;
690             scState.MCUSParsed = 0;
691 
692             // Need to skip all the bits up to the next byte boundary
693             while (scState.bufferLength % 8 != 0) scState.bufferLength --;
694         }
695     } // endOfBlock
696 
697 
698     // An MCU has been decoded, so resample, convert, and store
699     void endOfMCU()
700     {
701         if (nComponents == 3)
702         {
703             // Resample if needed
704             if (components[1].x != scState.MCUWidth)
705                 resampleDgt(1);
706             if (components[2].x != scState.MCUWidth)
707                 resampleDgt(2);
708 
709             // YCbCr -> RGB conversion
710             YCrCBtoRGB();
711         }
712     }
713 
714 
715     // Resample an MCU with nearest neighbour interp
716     void nearestNeighbourResample(uint cmpIndex)
717     {
718         with(components[cmpIndex])
719         {
720             ubyte[] buffer = new ubyte[](scState.MCUWidth*scState.MCUHeight);
721             float x_ratio = cast(float)(x-1)/cast(float)(scState.MCUWidth);
722             float y_ratio = cast(float)(y-1)/cast(float)(scState.MCUHeight);
723 
724             foreach(r; 0..scState.MCUHeight)
725             {
726                 foreach(c; 0..scState.MCUWidth)
727                 {
728                     int px = cast(int)(x_ratio * cast(float)c);
729                     int py = cast(int)(y_ratio * cast(float)r);
730                     buffer[c + scState.MCUWidth*r] = data[px + py*x];
731                 } // cols
732             } // rows
733 
734             data.destroy;
735             data = buffer;
736         } // with components[cmpIdx]
737     }
738 
739 
740     // Resample an MCU with bilinear interp
741     void bilinearResample(uint cmpIndex)
742     {
743         with(components[cmpIndex])
744         {
745             ubyte[] buffer = new ubyte[](scState.MCUWidth*scState.MCUHeight);
746             float x_ratio = cast(float)(x-1)/cast(float)(scState.MCUWidth);
747             float y_ratio = cast(float)(y-1)/cast(float)(scState.MCUHeight);
748 
749             foreach(r; 0..scState.MCUHeight)
750             {
751                 foreach(c; 0..scState.MCUWidth)
752                 {
753                     float px = (x_ratio * cast(float)c);
754                     float py = (y_ratio * cast(float)r);
755 
756                     int x0 = cast(int)px;
757                     int y0 = cast(int)py;
758 
759                     // Weighting factors
760                     float fx = px - x0;
761                     float fy = py - y0;
762                     float fx1 = 1.0f - fx;
763                     float fy1 = 1.0f - fy;
764 
765                     /** Get the locations in the src array of the 2x2 block surrounding (row,col)
766                     * 01 ------- 11
767                     * | (row,col) |
768                     * 00 ------- 10
769                     */
770                     ubyte p1 = data[x0 + y0*x];
771                     ubyte p2 = data[(x0+1) + y0*x];
772                     ubyte p3 = data[x0 + (y0+1)*x];
773                     ubyte p4 = data[(x0+1) + (y0+1)*x];
774 
775                     int wgt1 = cast(int)(fx1 * fy1 * 256.0f);
776                     int wgt2 = cast(int)(fx  * fy1 * 256.0f);
777                     int wgt3 = cast(int)(fx1 * fy  * 256.0f);
778                     int wgt4 = cast(int)(fx  * fy  * 256.0f);
779 
780                     int v = (p1 * wgt1 + p2 * wgt2 + p3 * wgt3 + p4 * wgt4) >> 8;
781                     buffer[c + scState.MCUWidth*r] = cast(ubyte)v;
782 
783                 } // cols
784             } // rows
785 
786             data.destroy;
787             data = buffer;
788         } // with components[cmpIdx]
789     } // bilinearResample
790 
791 
792     // Convert YCbCr to RGB an store in output image
793     void YCrCBtoRGB()
794     {
795         // Convert to RGB
796         ubyte[] RGBref = m_image.pixels;
797         ubyte[] Yref = components[0].data;
798         ubyte[] Cbref = components[1].data;
799         ubyte[] Crref = components[2].data;
800         int r, g, b, i = 0, stride = scState.MCUWidth;
801 
802         int ip0 = 0, ipStride = 0;
803         with(scState)
804         {
805             ip0 = (xMCU*MCUWidth + yMCU*MCUWidth*MCUHeight*nxMCU)*3;
806             ipStride = MCUWidth*nxMCU*3;
807         }
808 
809         foreach(y; 0..scState.MCUHeight)
810         {
811             foreach(x; 0..scState.MCUWidth)
812             {
813 
814                 int y_fixed = (Yref[i+x] << 16) + 32768; // rounding
815                 int cr = Crref[i+x] - 128;
816                 int cb = Cbref[i+x] - 128;
817                 r = y_fixed + cr*cast(int)(1.40200f * 65536 + 0.5);
818                 g = y_fixed - cr*cast(int)(0.71414f * 65536 + 0.5) -
819                     cb*cast(int)(0.34414f * 65536 + 0.5);
820                 b = y_fixed + cb*cast(int)(1.77200f * 65536 + 0.5);
821                 r >>= 16;
822                 g >>= 16;
823                 b >>= 16;
824 
825                 RGBref[ip0+x*3..ip0+x*3+3] = [clamp(r), clamp(g), clamp(b)];
826             }
827             i += stride;
828             ip0 += ipStride;
829         }
830     } // YCbCrtoRGB
831 
832 
833     // End of Image
834     void endOfImage()
835     {
836         /**
837         * Crop the image back to its real size (JPEG encoders can increase
838         * increase the dimensions to make them divisible by 8 for the DCT
839         */
840         image.resize(x, y, Image.ResizeAlgo.CROP);
841 
842         //.destroy some fields
843         scState = ScanState();
844         quantTable.destroy;
845         huffmanTable.destroy;
846         components.destroy;
847 
848     } // eoiAction
849 
850 
851     /**
852     * The following inverse discrete cosine transform (IDCT) voodoo comes from:
853     * stbi-1.33 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
854     */
855     void colIDCT(int* block)
856     {
857         int x0,x1,x2,x3,t0,t1,t2,t3,p1,p2,p3,p4,p5;
858 
859         if (block[8] == 0 && block[16] == 0 && block[24] == 0 && block[32] == 0 &&
860                 block[40] == 0 && block[48] == 0 && block[56] == 0)
861         {
862 
863             int dcterm = block[0] << 2;
864             block[0] = block[8] = block[16] = block[24] =
865             block[32] = block[40] = block[48] = block[56] = dcterm;
866             return;
867         }
868 
869         p2 = block[16];
870         p3 = block[48];
871         p1 = (p2+p3)*cast(int)(0.5411961f * 4096 + 0.5);
872         t2 = p1 + p3*cast(int)(-1.847759065f * 4096 + 0.5);
873         t3 = p1 + p2*cast(int)( 0.765366865f * 4096 + 0.5);
874         p2 = block[0];
875         p3 = block[32];
876         t0 = (p2+p3) << 12;
877         t1 = (p2-p3) << 12;
878         x0 = t0+t3;
879         x3 = t0-t3;
880         x1 = t1+t2;
881         x2 = t1-t2;
882         t0 = block[56];
883         t1 = block[40];
884         t2 = block[24];
885         t3 = block[8];
886         p3 = t0+t2;
887         p4 = t1+t3;
888         p1 = t0+t3;
889         p2 = t1+t2;
890         p5 = (p3+p4)*cast(int)( 1.175875602f * 4096 + 0.5);
891         t0 = t0*cast(int)( 0.298631336f * 4096 + 0.5);
892         t1 = t1*cast(int)( 2.053119869f * 4096 + 0.5);
893         t2 = t2*cast(int)( 3.072711026f * 4096 + 0.5);
894         t3 = t3*cast(int)( 1.501321110f * 4096 + 0.5);
895         p1 = p5 + p1*cast(int)(-0.899976223f * 4096 + 0.5);
896         p2 = p5 + p2*cast(int)(-2.562915447f * 4096 + 0.5);
897         p3 = p3*cast(int)(-1.961570560f * 4096 + 0.5);
898         p4 = p4*cast(int)(-0.390180644f * 4096 + 0.5);
899         t3 += p1+p4;
900         t2 += p2+p3;
901         t1 += p2+p4;
902         t0 += p1+p3;
903 
904         x0 += 512;
905         x1 += 512;
906         x2 += 512;
907         x3 += 512;
908         block[0]  = (x0+t3) >> 10;
909         block[56] = (x0-t3) >> 10;
910         block[8]  = (x1+t2) >> 10;
911         block[48] = (x1-t2) >> 10;
912         block[16] = (x2+t1) >> 10;
913         block[40] = (x2-t1) >> 10;
914         block[24] = (x3+t0) >> 10;
915         block[32] = (x3-t0) >> 10;
916     } // IDCT_1D_COL
917 
918     // ditto
919     void rowIDCT(int* block, ubyte* outData)
920     {
921         int x0,x1,x2,x3,t0,t1,t2,t3,p1,p2,p3,p4,p5;
922 
923         p2 = block[2];
924         p3 = block[6];
925         p1 = (p2+p3)*cast(int)(0.5411961f * 4096 + 0.5);
926         t2 = p1 + p3*cast(int)(-1.847759065f * 4096 + 0.5);
927         t3 = p1 + p2*cast(int)( 0.765366865f * 4096 + 0.5);
928         p2 = block[0];
929         p3 = block[4];
930         t0 = (p2+p3) << 12;
931         t1 = (p2-p3) << 12;
932         x0 = t0+t3;
933         x3 = t0-t3;
934         x1 = t1+t2;
935         x2 = t1-t2;
936         t0 = block[7];
937         t1 = block[5];
938         t2 = block[3];
939         t3 = block[1];
940         p3 = t0+t2;
941         p4 = t1+t3;
942         p1 = t0+t3;
943         p2 = t1+t2;
944         p5 = (p3+p4)*cast(int)( 1.175875602f * 4096 + 0.5);
945         t0 = t0*cast(int)( 0.298631336f * 4096 + 0.5);
946         t1 = t1*cast(int)( 2.053119869f * 4096 + 0.5);
947         t2 = t2*cast(int)( 3.072711026f * 4096 + 0.5);
948         t3 = t3*cast(int)( 1.501321110f * 4096 + 0.5);
949         p1 = p5 + p1*cast(int)(-0.899976223f * 4096 + 0.5);
950         p2 = p5 + p2*cast(int)(-2.562915447f * 4096 + 0.5);
951         p3 = p3*cast(int)(-1.961570560f * 4096 + 0.5);
952         p4 = p4*cast(int)(-0.390180644f * 4096 + 0.5);
953         t3 += p1+p4;
954         t2 += p2+p3;
955         t1 += p2+p4;
956         t0 += p1+p3;
957 
958         x0 += 65536 + (128<<17);
959         x1 += 65536 + (128<<17);
960         x2 += 65536 + (128<<17);
961         x3 += 65536 + (128<<17);
962 
963         outData[0] = clamp((x0+t3) >> 17);
964         outData[7] = clamp((x0-t3) >> 17);
965         outData[1] = clamp((x1+t2) >> 17);
966         outData[6] = clamp((x1-t2) >> 17);
967         outData[2] = clamp((x2+t1) >> 17);
968         outData[5] = clamp((x2-t1) >> 17);
969         outData[3] = clamp((x3+t0) >> 17);
970         outData[4] = clamp((x3-t0) >> 17);
971     } // IDCT_1D_ROW
972 
973 } // JpegDecoder