1 /**
2 Images suitable to be drawn on a canvas. This is an _undecoded_ image, with metadata extracted.
3 
4 Copyright: Guillaume Piolat 2018.
5 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 */
7 module printed.canvas.image;
8 
9 import std.exception;
10 import std.file;
11 import std.math;
12 import std.typecons;
13 import std.base64;
14 import std.array;
15 
16 import binrange;
17 
18 /// Represented an encoded image (JPEG or PNG).
19 class Image
20 {
21     this(const(char)[] relativePath)
22     {
23         ubyte[] dataFromFile = cast(ubyte[])( std.file.read(relativePath) );
24         // has been allocated, can be assumed unique
25         this( assumeUnique(dataFromFile) );
26     }
27 
28     this(immutable(ubyte)[] data)
29     {
30         // embed for future use
31         _data = data.idup;
32 
33         bool isPNG = _data.length >= 8 && (_data[0..8] == pngSignature);
34         bool isJPEG = (_data.length >= 2) && (_data[0] == 0xff) && (_data[1] == 0xd8); // SOI
35 
36         if (isPNG)
37         {
38             _MIME = "image/png";
39             parsePNGMetadata(_data, _width, _height, _pixelsPerMeterX, _pixelsPerMeterY);
40         }
41         else if (isJPEG)
42         {
43             _MIME = "image/jpeg";
44             parseJPEGMetadata(_data, _width, _height, _pixelsPerMeterX, _pixelsPerMeterY);
45         }
46         else
47             throw new Exception("Only JPEG and PNG are supported for now");
48     }
49 
50     string MIME()
51     {
52         return _MIME;
53     }
54 
55     string toDataURI()
56     {
57         string r = "data:";
58         r ~= _MIME;
59         r ~= ";charset=utf-8;base64,";
60         r ~= Base64.encode(_data);
61         return r;
62     }
63 
64     /// Width in pixels.
65     int width()
66     {
67         return _width;
68     }
69 
70     /// Height in pixels.
71     int height()
72     {
73         return _height;
74     }
75     
76     /// Default width when printed, in mm.
77     float printWidth()
78     {
79         return 1000 * _width / pixelsPerMeterX();
80     }
81 
82     /// Default height when printed, in mm.
83     float printHeight()
84     {
85         return 1000 * _height / pixelsPerMeterY();
86     }
87 
88     float pixelsPerMeterX()
89     {
90         if (isNaN(_pixelsPerMeterX))
91             return defaultDPI;
92         else
93             return _pixelsPerMeterX;
94     }
95 
96     float pixelsPerMeterY()
97     {
98         if (isNaN(_pixelsPerMeterY))
99             return defaultDPI;
100         else
101             return _pixelsPerMeterY;
102     }
103 
104     immutable(ubyte)[] encodedData() const
105     {
106         return _data;
107     }
108 
109 private:
110 
111     // Number of horizontal pixels.
112     int _width = -1;
113 
114     // Number of vertical pixels.
115     int _height = -1;
116 
117     // DPI and aspect ratio information, critical for print
118     float _pixelsPerMeterX = float.nan; // stays NaN if not available
119     float _pixelsPerMeterY = float.nan; // stays NaN if not available
120 
121     // Encoded data.
122     immutable(ubyte)[] _data;
123 
124     // Parsed MIME type.
125     string _MIME;
126 }
127 
128 private:
129 
130 // Default to 72 ppi if missing
131 // This is the default ppi GIMP uses when saving PNG.
132 static immutable defaultDPI = convertMetersToInches(72);
133 
134 double convertMetersToInches(double x)
135 {
136     return x * 39.37007874;
137 }
138 
139 double convertInchesToMeters(double x)
140 {
141     return x / 39.37007874;
142 }
143 
144 static immutable ubyte[8] pngSignature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
145 
146 void parsePNGMetadata(immutable(ubyte)[] data, out int width, out int height, out float pixelsPerMeterX, out float pixelsPerMeterY)
147 {
148     data.skipBytes(8);
149 
150     while (!data.empty)
151     {
152         uint chunkLen = popBE!uint(data);
153         uint chunkType = popBE!uint(data);        
154 
155         switch (chunkType)
156         {
157             case 0x49484452: // 'IHDR'
158                 width = popBE!int(data);
159                 height = popBE!int(data);
160                 data.skipBytes(5);
161                 break;
162 
163             case 0x70485973: // 'pHYs'
164                 int pixelsPerUnitX = popBE!int(data);
165                 int pixelsPerUnitY = popBE!int(data);
166                 ubyte unit = popBE!ubyte(data);
167                 if (unit == 1)
168                 {
169                     pixelsPerMeterX = pixelsPerUnitX;
170                     pixelsPerMeterY = pixelsPerUnitY;
171                 }
172                 else
173                 {
174                     // assume default DPI, but keep aspect ratio
175                     pixelsPerMeterX = defaultDPI;
176                     pixelsPerMeterY = (pixelsPerUnitY/cast(double)pixelsPerUnitX) * pixelsPerMeterX;
177                 }
178                 return; // we're done here
179 
180             default:
181                 data.skipBytes(chunkLen);
182         }
183 
184         popBE!uint(data); // skip CRC
185     }
186 }
187 
188 void parseJPEGMetadata(immutable(ubyte)[] data, out int width, out int height, out float pixelsPerMeterX, out float pixelsPerMeterY)
189 {
190     int actual_comp;
191     extract_jpeg_metadata(data, width, height, pixelsPerMeterX, pixelsPerMeterY);
192 }
193 
194 // Below: a stripped down JPEG decoder for metadata only
195 
196 
197 // jpgd.h - C++ class for JPEG decompression.
198 // Rich Geldreich <richgel99@gmail.com>
199 // Alex Evans: Linear memory allocator (taken from jpge.h).
200 // v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless)
201 // D translation by Ketmar // Invisible Vector
202 //
203 // This is free and unencumbered software released into the public domain.
204 //
205 // Anyone is free to copy, modify, publish, use, compile, sell, or
206 // distribute this software, either in source code form or as a compiled
207 // binary, for any purpose, commercial or non-commercial, and by any
208 // means.
209 //
210 // In jurisdictions that recognize copyright laws, the author or authors
211 // of this software dedicate any and all copyright interest in the
212 // software to the public domain. We make this dedication for the benefit
213 // of the public at large and to the detriment of our heirs and
214 // successors. We intend this dedication to be an overt act of
215 // relinquishment in perpetuity of all present and future rights to this
216 // software under copyright law.
217 //
218 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
219 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
220 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
221 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
222 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
223 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
224 // OTHER DEALINGS IN THE SOFTWARE.
225 //
226 // For more information, please refer to <http://unlicense.org/>
227 //
228 // Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
229 //
230 // Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling.
231 // Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain"
232 // http://vision.ai.uiuc.edu/~dugad/research/dct/index.html
233 /**
234 * Loads a JPEG image from a memory buffer or a file.
235 * req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
236 * On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
237 * Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
238 */
239 /// JPEG image loading.
240 
241 
242 /// Input stream interface.
243 /// This delegate is called when the internal input buffer is empty.
244 /// Parameters:
245 ///   pBuf - input buffer
246 ///   max_bytes_to_read - maximum bytes that can be written to pBuf
247 ///   pEOF_flag - set this to true if at end of stream (no more bytes remaining)
248 ///   Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
249 ///   Notes: This delegate will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
250 alias JpegStreamReadFunc = int delegate (void* pBuf, int max_bytes_to_read, bool* pEOF_flag);
251 
252 
253 // ////////////////////////////////////////////////////////////////////////// //
254 private:
255 
256 import core.stdc.stdlib: malloc, free;
257 
258 alias jpgd_malloc = malloc;
259 alias jpgd_free = free;
260 
261 // Success/failure error codes.
262 alias jpgd_status = int;
263 enum /*jpgd_status*/ {
264     JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
265     JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
266     JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
267     JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
268     JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
269     JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
270     JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
271     JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR,
272     JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM,
273 }
274 
275 enum {
276     JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
277     JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384,
278 }
279 
280 alias JPEG_MARKER = int;
281 enum /*JPEG_MARKER*/ {
282     M_SOF0  = 0xC0, M_SOF1  = 0xC1, M_SOF2  = 0xC2, M_SOF3  = 0xC3, M_SOF5  = 0xC5, M_SOF6  = 0xC6, M_SOF7  = 0xC7, M_JPG   = 0xC8,
283     M_SOF9  = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT   = 0xC4, M_DAC   = 0xCC,
284     M_RST0  = 0xD0, M_RST1  = 0xD1, M_RST2  = 0xD2, M_RST3  = 0xD3, M_RST4  = 0xD4, M_RST5  = 0xD5, M_RST6  = 0xD6, M_RST7  = 0xD7,
285     M_SOI   = 0xD8, M_EOI   = 0xD9, M_SOS   = 0xDA, M_DQT   = 0xDB, M_DNL   = 0xDC, M_DRI   = 0xDD, M_DHP   = 0xDE, M_EXP   = 0xDF,
286     M_APP0  = 0xE0, M_APP15 = 0xEF, M_JPG0  = 0xF0, M_JPG13 = 0xFD, M_COM   = 0xFE, M_TEM   = 0x01, M_ERROR = 0x100, RST0   = 0xD0,
287 }
288 
289 struct jpeg_decoder {
290 
291     private import core.stdc..string : memcpy, memset;
292 private:
293 
294     alias jpgd_quant_t = short;
295     alias jpgd_block_t = short;
296     alias pDecode_block_func = void function (ref jpeg_decoder, int, int, int);
297 
298     static struct coeff_buf {
299         ubyte* pData;
300         int block_num_x, block_num_y;
301         int block_len_x, block_len_y;
302         int block_size;
303     }
304 
305     int m_image_x_size;
306     int m_image_y_size;
307     JpegStreamReadFunc readfn;
308     jpgd_quant_t*[JPGD_MAX_QUANT_TABLES] m_quant; // pointer to quantization tables
309     int m_comps_in_frame;                         // # of components in frame
310     int[JPGD_MAX_COMPONENTS] m_comp_ident;        // component's ID
311     int[JPGD_MAX_COMPONENTS] m_comp_h_blocks;
312     int[JPGD_MAX_COMPONENTS] m_comp_v_blocks;
313     int m_comps_in_scan;                          // # of components in scan
314     int[JPGD_MAX_COMPS_IN_SCAN] m_comp_list;      // components in this scan
315     int[JPGD_MAX_COMPONENTS] m_comp_dc_tab;       // component's DC Huffman coding table selector
316     int[JPGD_MAX_COMPONENTS] m_comp_ac_tab;       // component's AC Huffman coding table selector
317     int m_blocks_per_mcu;
318     int m_max_blocks_per_row;
319     int m_mcus_per_row, m_mcus_per_col;
320     int[JPGD_MAX_BLOCKS_PER_MCU] m_mcu_org;
321     int m_total_lines_left;                       // total # lines left in image
322     int m_mcu_lines_left;                         // total # lines left in this MCU
323     int m_real_dest_bytes_per_scan_line;
324     int m_dest_bytes_per_scan_line;               // rounded up
325     int m_dest_bytes_per_pixel;                   // 4 (RGB) or 1 (Y)
326     int m_eob_run;
327     int[JPGD_MAX_COMPONENTS] m_block_y_mcu;
328     ubyte* m_pIn_buf_ofs;
329     int m_in_buf_left;
330     int m_tem_flag;
331     bool m_eof_flag;
332     ubyte[128] m_in_buf_pad_start;
333     ubyte[JPGD_IN_BUF_SIZE+128] m_in_buf;
334     ubyte[128] m_in_buf_pad_end;
335     int m_bits_left;
336     uint m_bit_buf;
337     int m_restart_interval;
338     int m_restarts_left;
339     int m_next_restart_num;
340     int m_max_mcus_per_row;
341     int m_max_blocks_per_mcu;
342     int m_expanded_blocks_per_mcu;
343     int m_expanded_blocks_per_row;
344     int m_expanded_blocks_per_component;
345     bool m_freq_domain_chroma_upsample;
346     int m_max_mcus_per_col;
347     uint[JPGD_MAX_COMPONENTS] m_last_dc_val;
348     jpgd_block_t* m_pMCU_coefficients;
349     ubyte* m_pSample_buf;
350     int[256] m_crr;
351     int[256] m_cbb;
352     int[256] m_crg;
353     int[256] m_cbg;
354     ubyte* m_pScan_line_0;
355     ubyte* m_pScan_line_1;
356     jpgd_status m_error_code;
357 
358     float m_pixelsPerMeterX, m_pixelsPerMeterY;
359 
360 
361 public:
362     // Inspect `error_code` after constructing to determine if the stream is valid or not. You may look at the `width`, `height`, etc.
363     // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
364     this (JpegStreamReadFunc rfn) 
365     {
366         initit(rfn);
367         locate_sof_marker();
368     }
369 
370     jpgd_status error_code () { return m_error_code; }
371 
372 private:
373     // Retrieve one character from the input stream.
374     uint get_char () {
375         // Any bytes remaining in buffer?
376         if (!m_in_buf_left) {
377             // Try to get more bytes.
378             prep_in_buffer();
379             // Still nothing to get?
380             if (!m_in_buf_left) {
381                 // Pad the end of the stream with 0xFF 0xD9 (EOI marker)
382                 int t = m_tem_flag;
383                 m_tem_flag ^= 1;
384                 return (t ? 0xD9 : 0xFF);
385             }
386         }
387         uint c = *m_pIn_buf_ofs++;
388         --m_in_buf_left;
389         return c;
390     }
391 
392     // Same as previous method, except can indicate if the character is a pad character or not.
393     uint get_char (bool* pPadding_flag) {
394         if (!m_in_buf_left) {
395             prep_in_buffer();
396             if (!m_in_buf_left) {
397                 *pPadding_flag = true;
398                 int t = m_tem_flag;
399                 m_tem_flag ^= 1;
400                 return (t ? 0xD9 : 0xFF);
401             }
402         }
403         *pPadding_flag = false;
404         uint c = *m_pIn_buf_ofs++;
405         --m_in_buf_left;
406         return c;
407     }
408 
409     // Inserts a previously retrieved character back into the input buffer.
410     void stuff_char (ubyte q) {
411         *(--m_pIn_buf_ofs) = q;
412         m_in_buf_left++;
413     }
414 
415     // Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
416     ubyte get_octet () {
417         bool padding_flag;
418         int c = get_char(&padding_flag);
419         if (c == 0xFF) {
420             if (padding_flag) return 0xFF;
421             c = get_char(&padding_flag);
422             if (padding_flag) { stuff_char(0xFF); return 0xFF; }
423             if (c == 0x00) return 0xFF;
424             stuff_char(cast(ubyte)(c));
425             stuff_char(0xFF);
426             return 0xFF;
427         }
428         return cast(ubyte)(c);
429     }
430 
431     // Retrieves a variable number of bits from the input stream. Does not recognize markers.
432     uint get_bits (int num_bits) {
433         if (!num_bits) return 0;
434         uint i = m_bit_buf >> (32 - num_bits);
435         if ((m_bits_left -= num_bits) <= 0) {
436             m_bit_buf <<= (num_bits += m_bits_left);
437             uint c1 = get_char();
438             uint c2 = get_char();
439             m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2;
440             m_bit_buf <<= -m_bits_left;
441             m_bits_left += 16;
442             assert(m_bits_left >= 0);
443         } else {
444             m_bit_buf <<= num_bits;
445         }
446         return i;
447     }
448 
449     // Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
450     uint get_bits_no_markers (int num_bits) {
451         if (!num_bits) return 0;
452         uint i = m_bit_buf >> (32 - num_bits);
453         if ((m_bits_left -= num_bits) <= 0) {
454             m_bit_buf <<= (num_bits += m_bits_left);
455             if (m_in_buf_left < 2 || m_pIn_buf_ofs[0] == 0xFF || m_pIn_buf_ofs[1] == 0xFF) {
456                 uint c1 = get_octet();
457                 uint c2 = get_octet();
458                 m_bit_buf |= (c1 << 8) | c2;
459             } else {
460                 m_bit_buf |= (cast(uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1];
461                 m_in_buf_left -= 2;
462                 m_pIn_buf_ofs += 2;
463             }
464             m_bit_buf <<= -m_bits_left;
465             m_bits_left += 16;
466             assert(m_bits_left >= 0);
467         } else {
468             m_bit_buf <<= num_bits;
469         }
470         return i;
471     }
472 
473     void word_clear (void *p, ushort c, uint n) {
474         ubyte *pD = cast(ubyte*)p;
475         immutable ubyte l = c & 0xFF, h = (c >> 8) & 0xFF;
476         while (n)
477         {
478             pD[0] = l; pD[1] = h; pD += 2;
479             n--;
480         }
481     }
482 
483     // Refill the input buffer.
484     // This method will sit in a loop until (A) the buffer is full or (B)
485     // the stream's read() method reports and end of file condition.
486     void prep_in_buffer () {
487         m_in_buf_left = 0;
488         m_pIn_buf_ofs = m_in_buf.ptr;
489 
490         if (m_eof_flag)
491             return;
492 
493         do
494         {
495             int bytes_read = readfn(m_in_buf.ptr + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag);
496             if (bytes_read == -1)
497                 stop_decoding(JPGD_STREAM_READ);
498 
499             m_in_buf_left += bytes_read;
500         } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag));
501 
502 
503         // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
504         // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
505         word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64);
506     }
507 
508     void stop_decoding(int err)
509     {
510         throw new Exception("Couldn't parse JPEG");
511     }
512     
513     // Read the start of frame (SOF) marker.
514     void read_sof_marker () {
515         int i;
516         uint num_left;
517 
518         num_left = get_bits(16);
519 
520         if (get_bits(8) != 8)   /* precision: sorry, only 8-bit precision is supported right now */
521             stop_decoding(JPGD_BAD_PRECISION);
522 
523         m_image_y_size = get_bits(16);
524 
525         if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT))
526             stop_decoding(JPGD_BAD_HEIGHT);
527 
528         m_image_x_size = get_bits(16);
529 
530         if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH))
531             stop_decoding(JPGD_BAD_WIDTH);
532 
533         m_comps_in_frame = get_bits(8);
534 
535         if (num_left != cast(uint)(m_comps_in_frame * 3 + 8))
536             stop_decoding(JPGD_BAD_SOF_LENGTH);
537 
538         for (i = 0; i < m_comps_in_frame; i++)
539         {
540             m_comp_ident.ptr[i]  = get_bits(8);
541             get_bits(4);
542             get_bits(4);
543             get_bits(8);
544         }
545     }
546 
547     // Used to skip unrecognized markers.
548     void skip_variable_marker () {
549         uint num_left;
550 
551         num_left = get_bits(16);
552 
553         if (num_left < 2)
554             stop_decoding(JPGD_BAD_VARIABLE_MARKER);
555 
556         num_left -= 2;
557 
558         while (num_left)
559         {
560             get_bits(8);
561             num_left--;
562         }
563     }
564 
565     // Read a start of scan (SOS) marker.
566     void read_sos_marker () {
567         uint num_left;
568         int i, ci, n, c, cc;
569 
570         num_left = get_bits(16);
571 
572         n = get_bits(8);
573 
574         m_comps_in_scan = n;
575 
576         num_left -= 3;
577 
578         if ( (num_left != cast(uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) )
579             stop_decoding(JPGD_BAD_SOS_LENGTH);
580 
581         for (i = 0; i < n; i++)
582         {
583             cc = get_bits(8);
584             c = get_bits(8);
585             num_left -= 2;
586 
587             for (ci = 0; ci < m_comps_in_frame; ci++)
588                 if (cc == m_comp_ident.ptr[ci])
589                     break;
590 
591             if (ci >= m_comps_in_frame)
592                 stop_decoding(JPGD_BAD_SOS_COMP_ID);
593 
594             m_comp_list.ptr[i]    = ci;
595             m_comp_dc_tab.ptr[ci] = (c >> 4) & 15;
596             m_comp_ac_tab.ptr[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1);
597         }
598 
599         get_bits(8);
600         get_bits(8);
601         get_bits(4);
602         get_bits(4);
603 
604         num_left -= 3;
605 
606         /* read past whatever is num_left */
607         while (num_left)
608         {
609             get_bits(8);
610             num_left--;
611         }
612     }
613 
614     // Finds the next marker.
615     int next_marker () {
616         uint c, bytes;
617 
618         bytes = 0;
619 
620         do
621         {
622             do
623             {
624                 bytes++;
625                 c = get_bits(8);
626             } while (c != 0xFF);
627 
628             do
629             {
630                 c = get_bits(8);
631             } while (c == 0xFF);
632 
633         } while (c == 0);
634 
635         // If bytes > 0 here, there where extra bytes before the marker (not good).
636 
637         return c;
638     }
639 
640     // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
641     // encountered.
642     int process_markers () {
643         int c;
644 
645         for ( ; ; ) {
646             c = next_marker();
647 
648             switch (c)
649             {
650                 case M_SOF0:
651                 case M_SOF1:
652                 case M_SOF2:
653                 case M_SOF3:
654                 case M_SOF5:
655                 case M_SOF6:
656                 case M_SOF7:
657                     //case M_JPG:
658                 case M_SOF9:
659                 case M_SOF10:
660                 case M_SOF11:
661                 case M_SOF13:
662                 case M_SOF14:
663                 case M_SOF15:
664                 case M_SOI:
665                 case M_EOI:
666                 case M_SOS:
667                     return c;
668 
669                 case M_APP0:
670                     uint num_left;
671 
672                     num_left = get_bits(16);
673 
674                     if (num_left < 7)
675                         stop_decoding(JPGD_BAD_VARIABLE_MARKER);
676 
677                     num_left -= 2;
678 
679                     ubyte[5] jfif_id;
680                     foreach(i; 0..5)
681                         jfif_id[i] = cast(ubyte) get_bits(8);
682 
683                     num_left -= 5;
684                     static immutable ubyte[5] JFIF = [0x4A, 0x46, 0x49, 0x46, 0x00];
685                     if (jfif_id == JFIF && num_left >= 7)
686                     {
687                         // skip version
688                         get_bits(16);
689                         uint units = get_bits(8);
690                         int Xdensity = get_bits(16);
691                         int Ydensity = get_bits(16);
692                         num_left -= 7;
693 
694                         switch (units)
695                         {
696                             case 0: // no units
697                                 m_pixelsPerMeterX = defaultDPI;
698                                 m_pixelsPerMeterY = (Ydensity/cast(double)Xdensity) * m_pixelsPerMeterX;
699                                 break;
700       
701                             case 1: // dot per inch
702                                 m_pixelsPerMeterX = convertMetersToInches(Xdensity);
703                                 m_pixelsPerMeterY = convertMetersToInches(Ydensity);
704                                 break;
705                             
706                             case 2: // dot per cm
707                                 m_pixelsPerMeterX = Xdensity * 100.0f;
708                                 m_pixelsPerMeterY = Ydensity * 100.0f;
709                                 break;
710                             default:
711                         }
712                     }
713 
714                     // skip rests of chunk
715 
716                     while (num_left)
717                     {
718                         get_bits(8);
719                         num_left--;
720                     }
721                     break;
722 
723                 case M_APP0+1: // possibly EXIF data
724                     uint num_left;
725                     num_left = get_bits(16);
726 
727                     if (num_left < 2)
728                         stop_decoding(JPGD_BAD_VARIABLE_MARKER);
729                     num_left -= 2;
730 
731                     ubyte[] exifData = new ubyte[num_left];
732                     foreach(i; 0..num_left)
733                         exifData[i] = cast(ubyte)(get_bits(8));
734 
735                     ubyte[6] exif_id;
736                     foreach(i; 0..6)
737                         exif_id[i] = popBE!ubyte(exifData);
738 
739                     static immutable ubyte[6] ExifIdentifierCode = [0x45, 0x78, 0x69, 0x66, 0x00, 0x00]; // "Exif\0\0"
740                     if (exif_id == ExifIdentifierCode)
741                     {
742                         // See EXIF specification: http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf
743 
744                         ubyte[] tiffFile = exifData.dup; // save exif chunk from "start of TIFF file"
745 
746                         ushort byteOrder = popBE!ushort(exifData);
747                         if (byteOrder != 0x4949 && byteOrder != 0x4D4D)
748                             stop_decoding(JPGD_DECODE_ERROR);
749                         bool littleEndian = (byteOrder == 0x4949);
750                         ushort version_ = littleEndian ? popLE!ushort(exifData) : popBE!ushort(exifData);
751                         if (version_ != 42)
752                             stop_decoding(JPGD_DECODE_ERROR);
753 
754                         uint offset = littleEndian ? popLE!uint(exifData) : popBE!uint(exifData);
755 
756                         double resolutionX = 72;
757                         double resolutionY = 72;
758                         int unit = 2;
759 
760                         // parse all IFDs
761                         while(offset != 0)
762                         {
763                             if (offset > exifData.length)
764                                 stop_decoding(JPGD_DECODE_ERROR);
765                             exifData = tiffFile[offset..$];
766                             ushort numEntries = littleEndian ? popLE!ushort(exifData) : popBE!ushort(exifData);
767 
768                             foreach(entry; 0..numEntries)
769                             {
770                                 ushort tag = littleEndian ? popLE!ushort(exifData) : popBE!ushort(exifData);
771                                 ushort type = littleEndian ? popLE!ushort(exifData) : popBE!ushort(exifData);
772                                 uint count = littleEndian ? popLE!uint(exifData) : popBE!uint(exifData);
773                                 uint valueOffset = littleEndian ? popLE!uint(exifData) : popBE!uint(exifData);
774 
775                                 if (tag == 282 || tag == 283) // XResolution  
776                                 {
777                                     ubyte[] tagData = tiffFile[valueOffset..$];
778                                     double num = littleEndian ? popLE!uint(tagData) : popBE!uint(tagData);
779                                     double denom = littleEndian ? popLE!uint(tagData) : popBE!uint(tagData);
780                                     double frac = num / denom;
781                                     if (tag == 282)
782                                         resolutionX = frac;
783                                     else
784                                         resolutionY = frac;
785                                 }
786 
787                                 if (tag == 296) // unit  
788                                     unit = valueOffset;
789                             }
790                             offset = littleEndian ? popLE!uint(exifData) : popBE!uint(exifData);
791                         }
792 
793                         if (unit == 2) // inches
794                         {
795                             m_pixelsPerMeterX = convertMetersToInches(resolutionX);
796                             m_pixelsPerMeterY = convertMetersToInches(resolutionY);
797                         }
798                         else if (unit == 3)
799                         {
800                             m_pixelsPerMeterX = resolutionX * 100;
801                             m_pixelsPerMeterY = resolutionY * 100;
802                         }
803                     }
804 
805                     break;
806 
807                 case M_JPG:
808                 case M_RST0:    /* no parameters */
809                 case M_RST1:
810                 case M_RST2:
811                 case M_RST3:
812                 case M_RST4:
813                 case M_RST5:
814                 case M_RST6:
815                 case M_RST7:
816                 case M_TEM:
817                     stop_decoding(JPGD_UNEXPECTED_MARKER);
818                     break;
819                 default:    /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
820                     skip_variable_marker();
821                     break;
822             }
823         }
824     }
825 
826     // Finds the start of image (SOI) marker.
827     // This code is rather defensive: it only checks the first 512 bytes to avoid
828     // false positives.
829     void locate_soi_marker () {
830         uint lastchar, thischar;
831         uint bytesleft;
832 
833         lastchar = get_bits(8);
834 
835         thischar = get_bits(8);
836 
837         /* ok if it's a normal JPEG file without a special header */
838 
839         if ((lastchar == 0xFF) && (thischar == M_SOI))
840             return;
841 
842         bytesleft = 4096; //512;
843 
844         for ( ; ; )
845         {
846             if (--bytesleft == 0)
847                 stop_decoding(JPGD_NOT_JPEG);
848 
849             lastchar = thischar;
850 
851             thischar = get_bits(8);
852 
853             if (lastchar == 0xFF)
854             {
855                 if (thischar == M_SOI)
856                     break;
857                 else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end
858                     stop_decoding(JPGD_NOT_JPEG);
859             }
860         }
861 
862         // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
863         thischar = (m_bit_buf >> 24) & 0xFF;
864 
865         if (thischar != 0xFF)
866             stop_decoding(JPGD_NOT_JPEG);
867     }
868 
869     // Find a start of frame (SOF) marker.
870     void locate_sof_marker () {
871         locate_soi_marker();
872 
873         int c = process_markers();
874 
875         switch (c)
876         {
877             case M_SOF2:
878                 goto case;
879             case M_SOF0:  /* baseline DCT */
880             case M_SOF1:  /* extended sequential DCT */
881                 read_sof_marker();
882                 break;
883             case M_SOF9:  /* Arithmitic coding */
884                 stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
885                 break;
886             default:
887                 stop_decoding(JPGD_UNSUPPORTED_MARKER);
888                 break;
889         }
890     }
891 
892     // Reset everything to default/uninitialized state.
893     void initit (JpegStreamReadFunc rfn) {
894         m_error_code = JPGD_SUCCESS;
895         m_image_x_size = m_image_y_size = 0;
896         readfn = rfn;
897 
898         memset(m_quant.ptr, 0, m_quant.sizeof);
899 
900         m_comps_in_frame = 0;
901 
902         memset(m_comp_ident.ptr, 0, m_comp_ident.sizeof);
903         memset(m_comp_h_blocks.ptr, 0, m_comp_h_blocks.sizeof);
904         memset(m_comp_v_blocks.ptr, 0, m_comp_v_blocks.sizeof);
905 
906         m_comps_in_scan = 0;
907         memset(m_comp_list.ptr, 0, m_comp_list.sizeof);
908         memset(m_comp_dc_tab.ptr, 0, m_comp_dc_tab.sizeof);
909         memset(m_comp_ac_tab.ptr, 0, m_comp_ac_tab.sizeof);
910 
911         m_blocks_per_mcu = 0;
912         m_max_blocks_per_row = 0;
913         m_mcus_per_row = 0;
914         m_mcus_per_col = 0;
915         m_expanded_blocks_per_component = 0;
916         m_expanded_blocks_per_mcu = 0;
917         m_expanded_blocks_per_row = 0;
918         m_freq_domain_chroma_upsample = false;
919 
920         memset(m_mcu_org.ptr, 0, m_mcu_org.sizeof);
921 
922         m_total_lines_left = 0;
923         m_mcu_lines_left = 0;
924         m_real_dest_bytes_per_scan_line = 0;
925         m_dest_bytes_per_scan_line = 0;
926         m_dest_bytes_per_pixel = 0;
927 
928         memset(m_block_y_mcu.ptr, 0, m_block_y_mcu.sizeof);
929 
930         m_eob_run = 0;
931 
932         memset(m_block_y_mcu.ptr, 0, m_block_y_mcu.sizeof);
933 
934         m_pIn_buf_ofs = m_in_buf.ptr;
935         m_in_buf_left = 0;
936         m_eof_flag = false;
937         m_tem_flag = 0;
938 
939         memset(m_in_buf_pad_start.ptr, 0, m_in_buf_pad_start.sizeof);
940         memset(m_in_buf.ptr, 0, m_in_buf.sizeof);
941         memset(m_in_buf_pad_end.ptr, 0, m_in_buf_pad_end.sizeof);
942 
943         m_restart_interval = 0;
944         m_restarts_left    = 0;
945         m_next_restart_num = 0;
946 
947         m_max_mcus_per_row = 0;
948         m_max_blocks_per_mcu = 0;
949         m_max_mcus_per_col = 0;
950 
951         memset(m_last_dc_val.ptr, 0, m_last_dc_val.sizeof);
952         m_pMCU_coefficients = null;
953         m_pSample_buf = null;
954 
955         m_pScan_line_0 = null;
956         m_pScan_line_1 = null;
957 
958         // Ready the input buffer.
959         prep_in_buffer();
960 
961         // Prime the bit buffer.
962         m_bits_left = 16;
963         m_bit_buf = 0;
964 
965         get_bits(16);
966         get_bits(16);
967     }
968 
969     // This method throws back into the stream any bytes that where read
970     // into the bit buffer during initial marker scanning.
971     void fix_in_buffer () {
972         // In case any 0xFF's where pulled into the buffer during marker scanning.
973         assert((m_bits_left & 7) == 0);
974 
975         if (m_bits_left == 16)
976             stuff_char(cast(ubyte)(m_bit_buf & 0xFF));
977 
978         if (m_bits_left >= 8)
979             stuff_char(cast(ubyte)((m_bit_buf >> 8) & 0xFF));
980 
981         stuff_char(cast(ubyte)((m_bit_buf >> 16) & 0xFF));
982         stuff_char(cast(ubyte)((m_bit_buf >> 24) & 0xFF));
983 
984         m_bits_left = 16;
985         get_bits_no_markers(16);
986         get_bits_no_markers(16);
987     }
988 }
989 
990 
991 
992 // ////////////////////////////////////////////////////////////////////////// //
993 /// decompress JPEG image, what else?
994 /// you can specify required color components in `req_comps` (3 for RGB or 4 for RGBA), or leave it as is to use image value.
995 void extract_jpeg_metadata(scope JpegStreamReadFunc rfn, out int width, out int height, out float pixelsPerMeterX, out float pixelsPerMeterY) 
996 {
997     auto decoder = jpeg_decoder(rfn);
998     if (decoder.error_code != JPGD_SUCCESS) 
999         return;
1000     width =  decoder.m_image_x_size;
1001     height = decoder.m_image_y_size; 
1002     pixelsPerMeterX = decoder.m_pixelsPerMeterX;
1003     pixelsPerMeterY = decoder.m_pixelsPerMeterY;
1004 }
1005 
1006 // ////////////////////////////////////////////////////////////////////////// //
1007 /// decompress JPEG image from memory buffer.
1008 /// you can specify required color components in `req_comps` (3 for RGB or 4 for RGBA), or leave it as is to use image value.
1009 void extract_jpeg_metadata(const(ubyte)[] buf, out int width, out int height, out float pixelsPerMeterX, out float pixelsPerMeterY) {
1010     bool m_eof_flag;
1011     size_t bufpos;
1012     auto b = cast(const(ubyte)*)buf.ptr;
1013     extract_jpeg_metadata(      delegate int (void* pBuf, int max_bytes_to_read, bool *pEOF_flag) {
1014                                                 import core.stdc..string : memcpy;
1015                                                 if (bufpos >= buf.length) {
1016                                                     *pEOF_flag = true;
1017                                                     return 0;
1018                                                 }
1019                                                 if (buf.length-bufpos < max_bytes_to_read) max_bytes_to_read = cast(int)(buf.length-bufpos);
1020                                                 memcpy(pBuf, b, max_bytes_to_read);
1021                                                 b += max_bytes_to_read;
1022                                                 return max_bytes_to_read;
1023                                              },
1024                                              width, height, pixelsPerMeterX, pixelsPerMeterY);
1025 }