1 // jpgd.h - C++ class for JPEG decompression.
2 // Rich Geldreich <richgel99@gmail.com>
3 // Alex Evans: Linear memory allocator (taken from jpge.h).
4 // v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless)
5 // D translation by Ketmar // Invisible Vector
7 // This is free and unencumbered software released into the public domain.
9 // Anyone is free to copy, modify, publish, use, compile, sell, or
10 // distribute this software, either in source code form or as a compiled
11 // binary, for any purpose, commercial or non-commercial, and by any
14 // In jurisdictions that recognize copyright laws, the author or authors
15 // of this software dedicate any and all copyright interest in the
16 // software to the public domain. We make this dedication for the benefit
17 // of the public at large and to the detriment of our heirs and
18 // successors. We intend this dedication to be an overt act of
19 // relinquishment in perpetuity of all present and future rights to this
20 // software under copyright law.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 // OTHER DEALINGS IN THE SOFTWARE.
30 // For more information, please refer to <http://unlicense.org/>
32 // Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
34 // Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling.
35 // Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain"
36 // http://vision.ai.uiuc.edu/~dugad/research/dct/index.html
38 * Loads a JPEG image from a memory buffer or a file.
39 * req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
40 * 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).
41 * 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.
43 module iv
.jpegd
/*is aliced*/;
47 // Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling).
48 // This is slower, but results in higher quality on images with highly saturated colors.
49 version = JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING
;
51 /// Input stream interface.
52 /// This delegate is called when the internal input buffer is empty.
54 /// pBuf - input buffer
55 /// max_bytes_to_read - maximum bytes that can be written to pBuf
56 /// pEOF_flag - set this to true if at end of stream (no more bytes remaining)
57 /// Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
58 /// Notes: This delegate will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
59 alias JpegStreamReadFunc
= int delegate (void* pBuf
, int max_bytes_to_read
, bool* pEOF_flag
);
62 // ////////////////////////////////////////////////////////////////////////// //
64 void *jpgd_malloc (usize nSize
) { import core
.stdc
.stdlib
: malloc
; return malloc(nSize
); }
65 void jpgd_free (void *p
) { import core
.stdc
.stdlib
: free
; if (p
!is null) free(p
); }
67 // Success/failure error codes.
68 alias jpgd_status
= int;
69 enum /*jpgd_status*/ {
70 JPGD_SUCCESS
= 0, JPGD_FAILED
= -1, JPGD_DONE
= 1,
71 JPGD_BAD_DHT_COUNTS
= -256, JPGD_BAD_DHT_INDEX
, JPGD_BAD_DHT_MARKER
, JPGD_BAD_DQT_MARKER
, JPGD_BAD_DQT_TABLE
,
72 JPGD_BAD_PRECISION
, JPGD_BAD_HEIGHT
, JPGD_BAD_WIDTH
, JPGD_TOO_MANY_COMPONENTS
,
73 JPGD_BAD_SOF_LENGTH
, JPGD_BAD_VARIABLE_MARKER
, JPGD_BAD_DRI_LENGTH
, JPGD_BAD_SOS_LENGTH
,
74 JPGD_BAD_SOS_COMP_ID
, JPGD_W_EXTRA_BYTES_BEFORE_MARKER
, JPGD_NO_ARITHMITIC_SUPPORT
, JPGD_UNEXPECTED_MARKER
,
75 JPGD_NOT_JPEG
, JPGD_UNSUPPORTED_MARKER
, JPGD_BAD_DQT_LENGTH
, JPGD_TOO_MANY_BLOCKS
,
76 JPGD_UNDEFINED_QUANT_TABLE
, JPGD_UNDEFINED_HUFF_TABLE
, JPGD_NOT_SINGLE_SCAN
, JPGD_UNSUPPORTED_COLORSPACE
,
77 JPGD_UNSUPPORTED_SAMP_FACTORS
, JPGD_DECODE_ERROR
, JPGD_BAD_RESTART_MARKER
, JPGD_ASSERTION_ERROR
,
78 JPGD_BAD_SOS_SPECTRAL
, JPGD_BAD_SOS_SUCCESSIVE
, JPGD_STREAM_READ
, JPGD_NOTENOUGHMEM
,
82 JPGD_IN_BUF_SIZE
= 8192, JPGD_MAX_BLOCKS_PER_MCU
= 10, JPGD_MAX_HUFF_TABLES
= 8, JPGD_MAX_QUANT_TABLES
= 4,
83 JPGD_MAX_COMPONENTS
= 4, JPGD_MAX_COMPS_IN_SCAN
= 4, JPGD_MAX_BLOCKS_PER_ROW
= 8192, JPGD_MAX_HEIGHT
= 16384, JPGD_MAX_WIDTH
= 16384,
86 // DCT coefficients are stored in this sequence.
87 static immutable int[64] g_ZAG
= [ 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 ];
89 alias JPEG_MARKER
= int;
90 enum /*JPEG_MARKER*/ {
91 M_SOF0
= 0xC0, M_SOF1
= 0xC1, M_SOF2
= 0xC2, M_SOF3
= 0xC3, M_SOF5
= 0xC5, M_SOF6
= 0xC6, M_SOF7
= 0xC7, M_JPG
= 0xC8,
92 M_SOF9
= 0xC9, M_SOF10
= 0xCA, M_SOF11
= 0xCB, M_SOF13
= 0xCD, M_SOF14
= 0xCE, M_SOF15
= 0xCF, M_DHT
= 0xC4, M_DAC
= 0xCC,
93 M_RST0
= 0xD0, M_RST1
= 0xD1, M_RST2
= 0xD2, M_RST3
= 0xD3, M_RST4
= 0xD4, M_RST5
= 0xD5, M_RST6
= 0xD6, M_RST7
= 0xD7,
94 M_SOI
= 0xD8, M_EOI
= 0xD9, M_SOS
= 0xDA, M_DQT
= 0xDB, M_DNL
= 0xDC, M_DRI
= 0xDD, M_DHP
= 0xDE, M_EXP
= 0xDF,
95 M_APP0
= 0xE0, M_APP15
= 0xEF, M_JPG0
= 0xF0, M_JPG13
= 0xFD, M_COM
= 0xFE, M_TEM
= 0x01, M_ERROR
= 0x100, RST0
= 0xD0,
98 alias JPEG_SUBSAMPLING
= int;
99 enum /*JPEG_SUBSAMPLING*/ { JPGD_GRAYSCALE
= 0, JPGD_YH1V1
, JPGD_YH2V1
, JPGD_YH1V2
, JPGD_YH2V2
};
101 enum CONST_BITS
= 13;
103 enum SCALEDONE
= cast(int)1;
105 enum FIX_0_298631336
= cast(int)2446; /* FIX(0.298631336) */
106 enum FIX_0_390180644
= cast(int)3196; /* FIX(0.390180644) */
107 enum FIX_0_541196100
= cast(int)4433; /* FIX(0.541196100) */
108 enum FIX_0_765366865
= cast(int)6270; /* FIX(0.765366865) */
109 enum FIX_0_899976223
= cast(int)7373; /* FIX(0.899976223) */
110 enum FIX_1_175875602
= cast(int)9633; /* FIX(1.175875602) */
111 enum FIX_1_501321110
= cast(int)12299; /* FIX(1.501321110) */
112 enum FIX_1_847759065
= cast(int)15137; /* FIX(1.847759065) */
113 enum FIX_1_961570560
= cast(int)16069; /* FIX(1.961570560) */
114 enum FIX_2_053119869
= cast(int)16819; /* FIX(2.053119869) */
115 enum FIX_2_562915447
= cast(int)20995; /* FIX(2.562915447) */
116 enum FIX_3_072711026
= cast(int)25172; /* FIX(3.072711026) */
118 int DESCALE() (int x
, int n
) { pragma(inline
, true); return (((x
) + (SCALEDONE
<< ((n
)-1))) >> (n
)); }
119 int DESCALE_ZEROSHIFT() (int x
, int n
) { pragma(inline
, true); return (((x
) + (128 << (n
)) + (SCALEDONE
<< ((n
)-1))) >> (n
)); }
120 ubyte CLAMP() (int i
) { pragma(inline
, true); return cast(ubyte)(cast(uint)i
> 255 ?
(((~i
) >> 31) & 0xFF) : i
); }
123 // Compiler creates a fast path 1D IDCT for X non-zero columns
124 struct Row(int NONZERO_COLS
) {
125 pure nothrow @trusted @nogc:
126 static void idct(int* pTemp
, const(jpeg_decoder
.jpgd_block_t
)* pSrc
) {
127 static if (NONZERO_COLS
== 0) {
129 } else static if (NONZERO_COLS
== 1) {
130 immutable int dcval
= (pSrc
[0] << PASS1_BITS
);
140 // ACCESS_COL() will be optimized at compile time to either an array access, or 0.
141 //#define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
142 template ACCESS_COL(int x
) {
143 static if (x
< NONZERO_COLS
) enum ACCESS_COL
= "cast(int)pSrc["~x
.stringof
~"]"; else enum ACCESS_COL
= "0";
146 immutable int z2
= mixin(ACCESS_COL
!2), z3
= mixin(ACCESS_COL
!6);
148 immutable int z1
= (z2
+ z3
)*FIX_0_541196100
;
149 immutable int tmp2
= z1
+ z3
*(-FIX_1_847759065
);
150 immutable int tmp3
= z1
+ z2
*FIX_0_765366865
;
152 immutable int tmp0
= (mixin(ACCESS_COL
!0) + mixin(ACCESS_COL
!4)) << CONST_BITS
;
153 immutable int tmp1
= (mixin(ACCESS_COL
!0) - mixin(ACCESS_COL
!4)) << CONST_BITS
;
155 immutable int tmp10
= tmp0
+ tmp3
, tmp13
= tmp0
- tmp3
, tmp11
= tmp1
+ tmp2
, tmp12
= tmp1
- tmp2
;
157 immutable int atmp0
= mixin(ACCESS_COL
!7), atmp1
= mixin(ACCESS_COL
!5), atmp2
= mixin(ACCESS_COL
!3), atmp3
= mixin(ACCESS_COL
!1);
159 immutable int bz1
= atmp0
+ atmp3
, bz2
= atmp1
+ atmp2
, bz3
= atmp0
+ atmp2
, bz4
= atmp1
+ atmp3
;
160 immutable int bz5
= (bz3
+ bz4
)*FIX_1_175875602
;
162 immutable int az1
= bz1
*(-FIX_0_899976223
);
163 immutable int az2
= bz2
*(-FIX_2_562915447
);
164 immutable int az3
= bz3
*(-FIX_1_961570560
) + bz5
;
165 immutable int az4
= bz4
*(-FIX_0_390180644
) + bz5
;
167 immutable int btmp0
= atmp0
*FIX_0_298631336
+ az1
+ az3
;
168 immutable int btmp1
= atmp1
*FIX_2_053119869
+ az2
+ az4
;
169 immutable int btmp2
= atmp2
*FIX_3_072711026
+ az2
+ az3
;
170 immutable int btmp3
= atmp3
*FIX_1_501321110
+ az1
+ az4
;
172 pTemp
[0] = DESCALE(tmp10
+ btmp3
, CONST_BITS
-PASS1_BITS
);
173 pTemp
[7] = DESCALE(tmp10
- btmp3
, CONST_BITS
-PASS1_BITS
);
174 pTemp
[1] = DESCALE(tmp11
+ btmp2
, CONST_BITS
-PASS1_BITS
);
175 pTemp
[6] = DESCALE(tmp11
- btmp2
, CONST_BITS
-PASS1_BITS
);
176 pTemp
[2] = DESCALE(tmp12
+ btmp1
, CONST_BITS
-PASS1_BITS
);
177 pTemp
[5] = DESCALE(tmp12
- btmp1
, CONST_BITS
-PASS1_BITS
);
178 pTemp
[3] = DESCALE(tmp13
+ btmp0
, CONST_BITS
-PASS1_BITS
);
179 pTemp
[4] = DESCALE(tmp13
- btmp0
, CONST_BITS
-PASS1_BITS
);
185 // Compiler creates a fast path 1D IDCT for X non-zero rows
186 struct Col (int NONZERO_ROWS
) {
187 pure nothrow @trusted @nogc:
188 static void idct(ubyte* pDst_ptr
, const(int)* pTemp
) {
189 static assert(NONZERO_ROWS
> 0);
190 static if (NONZERO_ROWS
== 1) {
191 int dcval
= DESCALE_ZEROSHIFT(pTemp
[0], PASS1_BITS
+3);
192 immutable ubyte dcval_clamped
= cast(ubyte)CLAMP(dcval
);
193 pDst_ptr
[0*8] = dcval_clamped
;
194 pDst_ptr
[1*8] = dcval_clamped
;
195 pDst_ptr
[2*8] = dcval_clamped
;
196 pDst_ptr
[3*8] = dcval_clamped
;
197 pDst_ptr
[4*8] = dcval_clamped
;
198 pDst_ptr
[5*8] = dcval_clamped
;
199 pDst_ptr
[6*8] = dcval_clamped
;
200 pDst_ptr
[7*8] = dcval_clamped
;
202 // ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
203 //#define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
204 template ACCESS_ROW(int x
) {
205 static if (x
< NONZERO_ROWS
) enum ACCESS_ROW
= "pTemp["~(x
*8).stringof
~"]"; else enum ACCESS_ROW
= "0";
208 immutable int z2
= mixin(ACCESS_ROW
!2);
209 immutable int z3
= mixin(ACCESS_ROW
!6);
211 immutable int z1
= (z2
+ z3
)*FIX_0_541196100
;
212 immutable int tmp2
= z1
+ z3
*(-FIX_1_847759065
);
213 immutable int tmp3
= z1
+ z2
*FIX_0_765366865
;
215 immutable int tmp0
= (mixin(ACCESS_ROW
!0) + mixin(ACCESS_ROW
!4)) << CONST_BITS
;
216 immutable int tmp1
= (mixin(ACCESS_ROW
!0) - mixin(ACCESS_ROW
!4)) << CONST_BITS
;
218 immutable int tmp10
= tmp0
+ tmp3
, tmp13
= tmp0
- tmp3
, tmp11
= tmp1
+ tmp2
, tmp12
= tmp1
- tmp2
;
220 immutable int atmp0
= mixin(ACCESS_ROW
!7), atmp1
= mixin(ACCESS_ROW
!5), atmp2
= mixin(ACCESS_ROW
!3), atmp3
= mixin(ACCESS_ROW
!1);
222 immutable int bz1
= atmp0
+ atmp3
, bz2
= atmp1
+ atmp2
, bz3
= atmp0
+ atmp2
, bz4
= atmp1
+ atmp3
;
223 immutable int bz5
= (bz3
+ bz4
)*FIX_1_175875602
;
225 immutable int az1
= bz1
*(-FIX_0_899976223
);
226 immutable int az2
= bz2
*(-FIX_2_562915447
);
227 immutable int az3
= bz3
*(-FIX_1_961570560
) + bz5
;
228 immutable int az4
= bz4
*(-FIX_0_390180644
) + bz5
;
230 immutable int btmp0
= atmp0
*FIX_0_298631336
+ az1
+ az3
;
231 immutable int btmp1
= atmp1
*FIX_2_053119869
+ az2
+ az4
;
232 immutable int btmp2
= atmp2
*FIX_3_072711026
+ az2
+ az3
;
233 immutable int btmp3
= atmp3
*FIX_1_501321110
+ az1
+ az4
;
235 int i
= DESCALE_ZEROSHIFT(tmp10
+ btmp3
, CONST_BITS
+PASS1_BITS
+3);
236 pDst_ptr
[8*0] = cast(ubyte)CLAMP(i
);
238 i
= DESCALE_ZEROSHIFT(tmp10
- btmp3
, CONST_BITS
+PASS1_BITS
+3);
239 pDst_ptr
[8*7] = cast(ubyte)CLAMP(i
);
241 i
= DESCALE_ZEROSHIFT(tmp11
+ btmp2
, CONST_BITS
+PASS1_BITS
+3);
242 pDst_ptr
[8*1] = cast(ubyte)CLAMP(i
);
244 i
= DESCALE_ZEROSHIFT(tmp11
- btmp2
, CONST_BITS
+PASS1_BITS
+3);
245 pDst_ptr
[8*6] = cast(ubyte)CLAMP(i
);
247 i
= DESCALE_ZEROSHIFT(tmp12
+ btmp1
, CONST_BITS
+PASS1_BITS
+3);
248 pDst_ptr
[8*2] = cast(ubyte)CLAMP(i
);
250 i
= DESCALE_ZEROSHIFT(tmp12
- btmp1
, CONST_BITS
+PASS1_BITS
+3);
251 pDst_ptr
[8*5] = cast(ubyte)CLAMP(i
);
253 i
= DESCALE_ZEROSHIFT(tmp13
+ btmp0
, CONST_BITS
+PASS1_BITS
+3);
254 pDst_ptr
[8*3] = cast(ubyte)CLAMP(i
);
256 i
= DESCALE_ZEROSHIFT(tmp13
- btmp0
, CONST_BITS
+PASS1_BITS
+3);
257 pDst_ptr
[8*4] = cast(ubyte)CLAMP(i
);
263 static immutable ubyte[512] s_idct_row_table
= [
264 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
265 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
266 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
267 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
268 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
269 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
270 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
271 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
274 static immutable ubyte[64] s_idct_col_table
= [ 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ];
276 void idct() (const(jpeg_decoder
.jpgd_block_t
)* pSrc_ptr
, ubyte* pDst_ptr
, int block_max_zag
) {
277 assert(block_max_zag
>= 1);
278 assert(block_max_zag
<= 64);
280 if (block_max_zag
<= 1)
282 int k
= ((pSrc_ptr
[0] + 4) >> 3) + 128;
287 for (int i
= 8; i
> 0; i
--)
289 *cast(int*)&pDst_ptr
[0] = k
;
290 *cast(int*)&pDst_ptr
[4] = k
;
298 const(jpeg_decoder
.jpgd_block_t
)* pSrc
= pSrc_ptr
;
299 int* pTemp
= temp
.ptr
;
301 const(ubyte)* pRow_tab
= &s_idct_row_table
.ptr
[(block_max_zag
- 1) * 8];
303 for (i
= 8; i
> 0; i
--, pRow_tab
++)
307 case 0: Row
!(0).idct(pTemp
, pSrc
); break;
308 case 1: Row
!(1).idct(pTemp
, pSrc
); break;
309 case 2: Row
!(2).idct(pTemp
, pSrc
); break;
310 case 3: Row
!(3).idct(pTemp
, pSrc
); break;
311 case 4: Row
!(4).idct(pTemp
, pSrc
); break;
312 case 5: Row
!(5).idct(pTemp
, pSrc
); break;
313 case 6: Row
!(6).idct(pTemp
, pSrc
); break;
314 case 7: Row
!(7).idct(pTemp
, pSrc
); break;
315 case 8: Row
!(8).idct(pTemp
, pSrc
); break;
325 immutable int nonzero_rows
= s_idct_col_table
.ptr
[block_max_zag
- 1];
326 for (i
= 8; i
> 0; i
--)
328 switch (nonzero_rows
)
330 case 1: Col
!(1).idct(pDst_ptr
, pTemp
); break;
331 case 2: Col
!(2).idct(pDst_ptr
, pTemp
); break;
332 case 3: Col
!(3).idct(pDst_ptr
, pTemp
); break;
333 case 4: Col
!(4).idct(pDst_ptr
, pTemp
); break;
334 case 5: Col
!(5).idct(pDst_ptr
, pTemp
); break;
335 case 6: Col
!(6).idct(pDst_ptr
, pTemp
); break;
336 case 7: Col
!(7).idct(pDst_ptr
, pTemp
); break;
337 case 8: Col
!(8).idct(pDst_ptr
, pTemp
); break;
346 void idct_4x4() (const(jpeg_decoder
.jpgd_block_t
)* pSrc_ptr
, ubyte* pDst_ptr
) {
348 int* pTemp
= temp
.ptr
;
349 const(jpeg_decoder
.jpgd_block_t
)* pSrc
= pSrc_ptr
;
351 for (int i
= 4; i
> 0; i
--)
353 Row
!(4).idct(pTemp
, pSrc
);
359 for (int i
= 8; i
> 0; i
--)
361 Col
!(4).idct(pDst_ptr
, pTemp
);
368 // ////////////////////////////////////////////////////////////////////////// //
369 struct jpeg_decoder
{
370 private import core
.stdc
.string
: memcpy
, memset
;
372 static auto JPGD_MIN(T
) (T a
, T b
) pure nothrow @safe @nogc { pragma(inline
, true); return (a
< b ? a
: b
); }
373 static auto JPGD_MAX(T
) (T a
, T b
) pure nothrow @safe @nogc { pragma(inline
, true); return (a
> b ? a
: b
); }
375 alias jpgd_quant_t
= short;
376 alias jpgd_block_t
= short;
377 alias pDecode_block_func
= void function (ref jpeg_decoder
, int, int, int);
379 static struct huff_tables
{
383 ubyte[256] code_size
;
387 static struct coeff_buf
{
389 int block_num_x
, block_num_y
;
390 int block_len_x
, block_len_y
;
394 static struct mem_block
{
401 mem_block
* m_pMem_blocks
;
404 JpegStreamReadFunc readfn
;
405 int m_progressive_flag
;
406 ubyte[JPGD_MAX_HUFF_TABLES
] m_huff_ac
;
407 ubyte*[JPGD_MAX_HUFF_TABLES
] m_huff_num
; // pointer to number of Huffman codes per bit size
408 ubyte*[JPGD_MAX_HUFF_TABLES
] m_huff_val
; // pointer to Huffman codes per bit size
409 jpgd_quant_t
*[JPGD_MAX_QUANT_TABLES
] m_quant
; // pointer to quantization tables
410 int m_scan_type
; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
411 int m_comps_in_frame
; // # of components in frame
412 int[JPGD_MAX_COMPONENTS
] m_comp_h_samp
; // component's horizontal sampling factor
413 int[JPGD_MAX_COMPONENTS
] m_comp_v_samp
; // component's vertical sampling factor
414 int[JPGD_MAX_COMPONENTS
] m_comp_quant
; // component's quantization table selector
415 int[JPGD_MAX_COMPONENTS
] m_comp_ident
; // component's ID
416 int[JPGD_MAX_COMPONENTS
] m_comp_h_blocks
;
417 int[JPGD_MAX_COMPONENTS
] m_comp_v_blocks
;
418 int m_comps_in_scan
; // # of components in scan
419 int[JPGD_MAX_COMPS_IN_SCAN
] m_comp_list
; // components in this scan
420 int[JPGD_MAX_COMPONENTS
] m_comp_dc_tab
; // component's DC Huffman coding table selector
421 int[JPGD_MAX_COMPONENTS
] m_comp_ac_tab
; // component's AC Huffman coding table selector
422 int m_spectral_start
; // spectral selection start
423 int m_spectral_end
; // spectral selection end
424 int m_successive_low
; // successive approximation low
425 int m_successive_high
; // successive approximation high
426 int m_max_mcu_x_size
; // MCU's max. X size in pixels
427 int m_max_mcu_y_size
; // MCU's max. Y size in pixels
428 int m_blocks_per_mcu
;
429 int m_max_blocks_per_row
;
430 int m_mcus_per_row
, m_mcus_per_col
;
431 int[JPGD_MAX_BLOCKS_PER_MCU
] m_mcu_org
;
432 int m_total_lines_left
; // total # lines left in image
433 int m_mcu_lines_left
; // total # lines left in this MCU
434 int m_real_dest_bytes_per_scan_line
;
435 int m_dest_bytes_per_scan_line
; // rounded up
436 int m_dest_bytes_per_pixel
; // 4 (RGB) or 1 (Y)
437 huff_tables
*[JPGD_MAX_HUFF_TABLES
] m_pHuff_tabs
;
438 coeff_buf
*[JPGD_MAX_COMPONENTS
] m_dc_coeffs
;
439 coeff_buf
*[JPGD_MAX_COMPONENTS
] m_ac_coeffs
;
441 int[JPGD_MAX_COMPONENTS
] m_block_y_mcu
;
442 ubyte* m_pIn_buf_ofs
;
446 ubyte[128] m_in_buf_pad_start
;
447 ubyte[JPGD_IN_BUF_SIZE
+128] m_in_buf
;
448 ubyte[128] m_in_buf_pad_end
;
451 int m_restart_interval
;
453 int m_next_restart_num
;
454 int m_max_mcus_per_row
;
455 int m_max_blocks_per_mcu
;
456 int m_expanded_blocks_per_mcu
;
457 int m_expanded_blocks_per_row
;
458 int m_expanded_blocks_per_component
;
459 bool m_freq_domain_chroma_upsample
;
460 int m_max_mcus_per_col
;
461 uint[JPGD_MAX_COMPONENTS
] m_last_dc_val
;
462 jpgd_block_t
* m_pMCU_coefficients
;
463 int[JPGD_MAX_BLOCKS_PER_MCU
] m_mcu_block_max_zag
;
464 ubyte* m_pSample_buf
;
469 ubyte* m_pScan_line_0
;
470 ubyte* m_pScan_line_1
;
471 jpgd_status m_error_code
;
473 int m_total_bytes_read
;
476 // Inspect `error_code` after constructing to determine if the stream is valid or not. You may look at the `width`, `height`, etc.
477 // 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.
478 this (JpegStreamReadFunc rfn
) { decode_init(rfn
); }
480 ~this () { free_all_blocks(); }
482 @disable this (this); // no copies
484 // Call this method after constructing the object to begin decompression.
485 // If JPGD_SUCCESS is returned you may then call decode() on each scanline.
486 int begin_decoding () {
487 if (m_ready_flag
) return JPGD_SUCCESS
;
488 if (m_error_code
) return JPGD_FAILED
;
493 } catch (Exception
) {}
497 // Returns the next scan line.
498 // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (`bytes_per_pixel` will return 1).
499 // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and `bytes_per_pixel` will return 4).
500 // Returns JPGD_SUCCESS if a scan line has been returned.
501 // Returns JPGD_DONE if all scan lines have been returned.
502 // Returns JPGD_FAILED if an error occurred. Inspect `error_code` for a more info.
503 int decode (/*const void** */void** pScan_line
, uint* pScan_line_len
) {
504 if (m_error_code ||
!m_ready_flag
) return JPGD_FAILED
;
505 if (m_total_lines_left
== 0) return JPGD_DONE
;
507 if (m_mcu_lines_left
== 0) {
508 if (m_progressive_flag
) load_next_row(); else decode_next_row();
509 // Find the EOI marker if that was the last row.
510 if (m_total_lines_left
<= m_max_mcu_y_size
) find_eoi();
511 m_mcu_lines_left
= m_max_mcu_y_size
;
513 if (m_freq_domain_chroma_upsample
) {
515 *pScan_line
= m_pScan_line_0
;
517 switch (m_scan_type
) {
519 if ((m_mcu_lines_left
& 1) == 0) {
521 *pScan_line
= m_pScan_line_0
;
523 *pScan_line
= m_pScan_line_1
;
528 *pScan_line
= m_pScan_line_0
;
531 if ((m_mcu_lines_left
& 1) == 0) {
533 *pScan_line
= m_pScan_line_0
;
535 *pScan_line
= m_pScan_line_1
;
540 *pScan_line
= m_pScan_line_0
;
544 *pScan_line
= m_pScan_line_0
;
549 *pScan_line_len
= m_real_dest_bytes_per_scan_line
;
551 --m_total_lines_left
;
553 } catch (Exception
) {}
557 @property const pure nothrow @safe @nogc {
558 jpgd_status
error_code () { pragma(inline
, true); return m_error_code
; }
560 int width () { pragma(inline
, true); return m_image_x_size
; }
561 int height () { pragma(inline
, true); return m_image_y_size
; }
563 int num_components () { pragma(inline
, true); return m_comps_in_frame
; }
565 int bytes_per_pixel () { pragma(inline
, true); return m_dest_bytes_per_pixel
; }
566 int bytes_per_scan_line () { pragma(inline
, true); return m_image_x_size
* bytes_per_pixel(); }
568 // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
569 int total_bytes_read () { pragma(inline
, true); return m_total_bytes_read
; }
573 // Retrieve one character from the input stream.
575 // Any bytes remaining in buffer?
576 if (!m_in_buf_left
) {
577 // Try to get more bytes.
579 // Still nothing to get?
580 if (!m_in_buf_left
) {
581 // Pad the end of the stream with 0xFF 0xD9 (EOI marker)
584 return (t ?
0xD9 : 0xFF);
587 uint c
= *m_pIn_buf_ofs
++;
592 // Same as previous method, except can indicate if the character is a pad character or not.
593 uint get_char (bool* pPadding_flag
) {
594 if (!m_in_buf_left
) {
596 if (!m_in_buf_left
) {
597 *pPadding_flag
= true;
600 return (t ?
0xD9 : 0xFF);
603 *pPadding_flag
= false;
604 uint c
= *m_pIn_buf_ofs
++;
609 // Inserts a previously retrieved character back into the input buffer.
610 void stuff_char (ubyte q
) {
611 *(--m_pIn_buf_ofs
) = q
;
615 // Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
618 int c
= get_char(&padding_flag
);
620 if (padding_flag
) return 0xFF;
621 c
= get_char(&padding_flag
);
622 if (padding_flag
) { stuff_char(0xFF); return 0xFF; }
623 if (c
== 0x00) return 0xFF;
624 stuff_char(cast(ubyte)(c
));
628 return cast(ubyte)(c
);
631 // Retrieves a variable number of bits from the input stream. Does not recognize markers.
632 uint get_bits (int num_bits
) {
633 if (!num_bits
) return 0;
634 uint i
= m_bit_buf
>> (32 - num_bits
);
635 if ((m_bits_left
-= num_bits
) <= 0) {
636 m_bit_buf
<<= (num_bits
+= m_bits_left
);
637 uint c1
= get_char();
638 uint c2
= get_char();
639 m_bit_buf
= (m_bit_buf
& 0xFFFF0000) |
(c1
<< 8) | c2
;
640 m_bit_buf
<<= -m_bits_left
;
642 assert(m_bits_left
>= 0);
644 m_bit_buf
<<= num_bits
;
649 // 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.
650 uint get_bits_no_markers (int num_bits
) {
651 if (!num_bits
) return 0;
652 uint i
= m_bit_buf
>> (32 - num_bits
);
653 if ((m_bits_left
-= num_bits
) <= 0) {
654 m_bit_buf
<<= (num_bits
+= m_bits_left
);
655 if (m_in_buf_left
< 2 || m_pIn_buf_ofs
[0] == 0xFF || m_pIn_buf_ofs
[1] == 0xFF) {
656 uint c1
= get_octet();
657 uint c2
= get_octet();
658 m_bit_buf |
= (c1
<< 8) | c2
;
660 m_bit_buf |
= (cast(uint)m_pIn_buf_ofs
[0] << 8) | m_pIn_buf_ofs
[1];
664 m_bit_buf
<<= -m_bits_left
;
666 assert(m_bits_left
>= 0);
668 m_bit_buf
<<= num_bits
;
673 // Decodes a Huffman encoded symbol.
674 int huff_decode (huff_tables
*pH
) {
676 // Check first 8-bits: do we have a complete symbol?
677 if ((symbol
= pH
.look_up
.ptr
[m_bit_buf
>> 24]) < 0) {
678 // Decode more bits, use a tree traversal to find symbol.
681 symbol
= pH
.tree
.ptr
[-cast(int)(symbol
+ ((m_bit_buf
>> ofs
) & 1))];
683 } while (symbol
< 0);
684 get_bits_no_markers(8 + (23 - ofs
));
686 get_bits_no_markers(pH
.code_size
.ptr
[symbol
]);
691 // Decodes a Huffman encoded symbol.
692 int huff_decode (huff_tables
*pH
, ref int extra_bits
) {
694 // Check first 8-bits: do we have a complete symbol?
695 if ((symbol
= pH
.look_up2
.ptr
[m_bit_buf
>> 24]) < 0) {
696 // Use a tree traversal to find symbol.
699 symbol
= pH
.tree
.ptr
[-cast(int)(symbol
+ ((m_bit_buf
>> ofs
) & 1))];
701 } while (symbol
< 0);
702 get_bits_no_markers(8 + (23 - ofs
));
703 extra_bits
= get_bits_no_markers(symbol
& 0xF);
705 assert(((symbol
>> 8) & 31) == pH
.code_size
.ptr
[symbol
& 255] + ((symbol
& 0x8000) ?
(symbol
& 15) : 0));
706 if (symbol
& 0x8000) {
707 get_bits_no_markers((symbol
>> 8) & 31);
708 extra_bits
= symbol
>> 16;
710 int code_size
= (symbol
>> 8) & 31;
711 int num_extra_bits
= symbol
& 0xF;
712 int bits
= code_size
+ num_extra_bits
;
713 if (bits
<= (m_bits_left
+ 16)) {
714 extra_bits
= get_bits_no_markers(bits
) & ((1 << num_extra_bits
) - 1);
716 get_bits_no_markers(code_size
);
717 extra_bits
= get_bits_no_markers(num_extra_bits
);
725 // Tables and macro used to fully decode the DPCM differences.
726 static immutable int[16] s_extend_test
= [ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 ];
727 static immutable int[16] s_extend_offset
= [ 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 ];
728 static immutable int[18] s_extend_mask
= [ 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) ];
729 // The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this)
730 //#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x))
731 static JPGD_HUFF_EXTEND (int x
, int s
) nothrow @trusted @nogc { pragma(inline
, true); return (((x
) < s_extend_test
.ptr
[s
& 15]) ?
((x
) + s_extend_offset
.ptr
[s
& 15]) : (x
)); }
733 // Clamps a value between 0-255.
734 //static ubyte clamp (int i) { if (cast(uint)(i) > 255) i = (((~i) >> 31) & 0xFF); return cast(ubyte)(i); }
737 static struct DCT_Upsample
{
739 static struct Matrix44
{
740 pure nothrow @trusted @nogc:
741 alias Element_Type
= int;
742 enum { NUM_ROWS
= 4, NUM_COLS
= 4 }
744 Element_Type
[NUM_COLS
][NUM_ROWS
] v
;
746 this() (in auto ref Matrix44 m
) {
747 foreach (immutable r
; 0..NUM_ROWS
) v
[r
][] = m
.v
[r
][];
750 //@property int rows () const { pragma(inline, true); return NUM_ROWS; }
751 //@property int cols () const { pragma(inline, true); return NUM_COLS; }
753 ref inout(Element_Type
) at (int r
, int c
) inout { pragma(inline
, true); return v
.ptr
[r
].ptr
[c
]; }
755 ref Matrix44
opOpAssign(string op
:"+") (in auto ref Matrix44 a
) {
756 foreach (int r
; 0..NUM_ROWS
) {
757 at(r
, 0) += a
.at(r
, 0);
758 at(r
, 1) += a
.at(r
, 1);
759 at(r
, 2) += a
.at(r
, 2);
760 at(r
, 3) += a
.at(r
, 3);
765 ref Matrix44
opOpAssign(string op
:"-") (in auto ref Matrix44 a
) {
766 foreach (int r
; 0..NUM_ROWS
) {
767 at(r
, 0) -= a
.at(r
, 0);
768 at(r
, 1) -= a
.at(r
, 1);
769 at(r
, 2) -= a
.at(r
, 2);
770 at(r
, 3) -= a
.at(r
, 3);
775 Matrix44
opBinary(string op
:"+") (in auto ref Matrix44 b
) const {
778 foreach (int r
; 0..NUM_ROWS
) {
779 ret.at(r
, 0) = a
.at(r
, 0) + b
.at(r
, 0);
780 ret.at(r
, 1) = a
.at(r
, 1) + b
.at(r
, 1);
781 ret.at(r
, 2) = a
.at(r
, 2) + b
.at(r
, 2);
782 ret.at(r
, 3) = a
.at(r
, 3) + b
.at(r
, 3);
787 Matrix44
opBinary(string op
:"-") (in auto ref Matrix44 b
) const {
790 foreach (int r
; 0..NUM_ROWS
) {
791 ret.at(r
, 0) = a
.at(r
, 0) - b
.at(r
, 0);
792 ret.at(r
, 1) = a
.at(r
, 1) - b
.at(r
, 1);
793 ret.at(r
, 2) = a
.at(r
, 2) - b
.at(r
, 2);
794 ret.at(r
, 3) = a
.at(r
, 3) - b
.at(r
, 3);
799 static void add_and_store() (jpgd_block_t
* pDst
, in auto ref Matrix44 a
, in auto ref Matrix44 b
) {
800 foreach (int r
; 0..4) {
801 pDst
[0*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 0) + b
.at(r
, 0));
802 pDst
[1*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 1) + b
.at(r
, 1));
803 pDst
[2*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 2) + b
.at(r
, 2));
804 pDst
[3*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 3) + b
.at(r
, 3));
808 static void sub_and_store() (jpgd_block_t
* pDst
, in auto ref Matrix44 a
, in auto ref Matrix44 b
) {
809 foreach (int r
; 0..4) {
810 pDst
[0*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 0) - b
.at(r
, 0));
811 pDst
[1*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 1) - b
.at(r
, 1));
812 pDst
[2*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 2) - b
.at(r
, 2));
813 pDst
[3*8 + r
] = cast(jpgd_block_t
)(a
.at(r
, 3) - b
.at(r
, 3));
818 enum FRACT_BITS
= 10;
819 enum SCALE
= 1 << FRACT_BITS
;
821 alias Temp_Type
= int;
822 //TODO: convert defines to mixins
823 //#define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS)
824 //#define F(i) ((int)((i) * SCALE + .5f))
825 // Any decent C++ compiler will optimize this at compile time to a 0, or an array access.
826 //#define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8])
828 static int D(T
) (T i
) { pragma(inline
, true); return (((i
) + (SCALE
>> 1)) >> FRACT_BITS
); }
829 enum F(float i
) = (cast(int)((i
) * SCALE
+ 0.5f));
831 // NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix
832 static struct P_Q(int NUM_ROWS
, int NUM_COLS
) {
833 static void calc (ref Matrix44 P
, ref Matrix44 Q
, const(jpgd_block_t
)* pSrc
) {
834 //auto AT (int c, int r) nothrow @trusted @nogc { return (c >= NUM_COLS || r >= NUM_ROWS ? 0 : pSrc[c+r*8]); }
835 template AT(int c
, int r
) {
836 static if (c
>= NUM_COLS || r
>= NUM_ROWS
) enum AT
= "0"; else enum AT
= "pSrc["~c
.stringof
~"+"~r
.stringof
~"*8]";
838 // 4x8 = 4x8 times 8x8, matrix 0 is constant
839 immutable Temp_Type X000
= mixin(AT
!(0, 0));
840 immutable Temp_Type X001
= mixin(AT
!(0, 1));
841 immutable Temp_Type X002
= mixin(AT
!(0, 2));
842 immutable Temp_Type X003
= mixin(AT
!(0, 3));
843 immutable Temp_Type X004
= mixin(AT
!(0, 4));
844 immutable Temp_Type X005
= mixin(AT
!(0, 5));
845 immutable Temp_Type X006
= mixin(AT
!(0, 6));
846 immutable Temp_Type X007
= mixin(AT
!(0, 7));
847 immutable Temp_Type X010
= D(F
!(0.415735f) * mixin(AT
!(1, 0)) + F
!(0.791065f) * mixin(AT
!(3, 0)) + F
!(-0.352443f) * mixin(AT
!(5, 0)) + F
!(0.277785f) * mixin(AT
!(7, 0)));
848 immutable Temp_Type X011
= D(F
!(0.415735f) * mixin(AT
!(1, 1)) + F
!(0.791065f) * mixin(AT
!(3, 1)) + F
!(-0.352443f) * mixin(AT
!(5, 1)) + F
!(0.277785f) * mixin(AT
!(7, 1)));
849 immutable Temp_Type X012
= D(F
!(0.415735f) * mixin(AT
!(1, 2)) + F
!(0.791065f) * mixin(AT
!(3, 2)) + F
!(-0.352443f) * mixin(AT
!(5, 2)) + F
!(0.277785f) * mixin(AT
!(7, 2)));
850 immutable Temp_Type X013
= D(F
!(0.415735f) * mixin(AT
!(1, 3)) + F
!(0.791065f) * mixin(AT
!(3, 3)) + F
!(-0.352443f) * mixin(AT
!(5, 3)) + F
!(0.277785f) * mixin(AT
!(7, 3)));
851 immutable Temp_Type X014
= D(F
!(0.415735f) * mixin(AT
!(1, 4)) + F
!(0.791065f) * mixin(AT
!(3, 4)) + F
!(-0.352443f) * mixin(AT
!(5, 4)) + F
!(0.277785f) * mixin(AT
!(7, 4)));
852 immutable Temp_Type X015
= D(F
!(0.415735f) * mixin(AT
!(1, 5)) + F
!(0.791065f) * mixin(AT
!(3, 5)) + F
!(-0.352443f) * mixin(AT
!(5, 5)) + F
!(0.277785f) * mixin(AT
!(7, 5)));
853 immutable Temp_Type X016
= D(F
!(0.415735f) * mixin(AT
!(1, 6)) + F
!(0.791065f) * mixin(AT
!(3, 6)) + F
!(-0.352443f) * mixin(AT
!(5, 6)) + F
!(0.277785f) * mixin(AT
!(7, 6)));
854 immutable Temp_Type X017
= D(F
!(0.415735f) * mixin(AT
!(1, 7)) + F
!(0.791065f) * mixin(AT
!(3, 7)) + F
!(-0.352443f) * mixin(AT
!(5, 7)) + F
!(0.277785f) * mixin(AT
!(7, 7)));
855 immutable Temp_Type X020
= mixin(AT
!(4, 0));
856 immutable Temp_Type X021
= mixin(AT
!(4, 1));
857 immutable Temp_Type X022
= mixin(AT
!(4, 2));
858 immutable Temp_Type X023
= mixin(AT
!(4, 3));
859 immutable Temp_Type X024
= mixin(AT
!(4, 4));
860 immutable Temp_Type X025
= mixin(AT
!(4, 5));
861 immutable Temp_Type X026
= mixin(AT
!(4, 6));
862 immutable Temp_Type X027
= mixin(AT
!(4, 7));
863 immutable Temp_Type X030
= D(F
!(0.022887f) * mixin(AT
!(1, 0)) + F
!(-0.097545f) * mixin(AT
!(3, 0)) + F
!(0.490393f) * mixin(AT
!(5, 0)) + F
!(0.865723f) * mixin(AT
!(7, 0)));
864 immutable Temp_Type X031
= D(F
!(0.022887f) * mixin(AT
!(1, 1)) + F
!(-0.097545f) * mixin(AT
!(3, 1)) + F
!(0.490393f) * mixin(AT
!(5, 1)) + F
!(0.865723f) * mixin(AT
!(7, 1)));
865 immutable Temp_Type X032
= D(F
!(0.022887f) * mixin(AT
!(1, 2)) + F
!(-0.097545f) * mixin(AT
!(3, 2)) + F
!(0.490393f) * mixin(AT
!(5, 2)) + F
!(0.865723f) * mixin(AT
!(7, 2)));
866 immutable Temp_Type X033
= D(F
!(0.022887f) * mixin(AT
!(1, 3)) + F
!(-0.097545f) * mixin(AT
!(3, 3)) + F
!(0.490393f) * mixin(AT
!(5, 3)) + F
!(0.865723f) * mixin(AT
!(7, 3)));
867 immutable Temp_Type X034
= D(F
!(0.022887f) * mixin(AT
!(1, 4)) + F
!(-0.097545f) * mixin(AT
!(3, 4)) + F
!(0.490393f) * mixin(AT
!(5, 4)) + F
!(0.865723f) * mixin(AT
!(7, 4)));
868 immutable Temp_Type X035
= D(F
!(0.022887f) * mixin(AT
!(1, 5)) + F
!(-0.097545f) * mixin(AT
!(3, 5)) + F
!(0.490393f) * mixin(AT
!(5, 5)) + F
!(0.865723f) * mixin(AT
!(7, 5)));
869 immutable Temp_Type X036
= D(F
!(0.022887f) * mixin(AT
!(1, 6)) + F
!(-0.097545f) * mixin(AT
!(3, 6)) + F
!(0.490393f) * mixin(AT
!(5, 6)) + F
!(0.865723f) * mixin(AT
!(7, 6)));
870 immutable Temp_Type X037
= D(F
!(0.022887f) * mixin(AT
!(1, 7)) + F
!(-0.097545f) * mixin(AT
!(3, 7)) + F
!(0.490393f) * mixin(AT
!(5, 7)) + F
!(0.865723f) * mixin(AT
!(7, 7)));
872 // 4x4 = 4x8 times 8x4, matrix 1 is constant
874 P
.at(0, 1) = D(X001
* F
!(0.415735f) + X003
* F
!(0.791065f) + X005
* F
!(-0.352443f) + X007
* F
!(0.277785f));
876 P
.at(0, 3) = D(X001
* F
!(0.022887f) + X003
* F
!(-0.097545f) + X005
* F
!(0.490393f) + X007
* F
!(0.865723f));
878 P
.at(1, 1) = D(X011
* F
!(0.415735f) + X013
* F
!(0.791065f) + X015
* F
!(-0.352443f) + X017
* F
!(0.277785f));
880 P
.at(1, 3) = D(X011
* F
!(0.022887f) + X013
* F
!(-0.097545f) + X015
* F
!(0.490393f) + X017
* F
!(0.865723f));
882 P
.at(2, 1) = D(X021
* F
!(0.415735f) + X023
* F
!(0.791065f) + X025
* F
!(-0.352443f) + X027
* F
!(0.277785f));
884 P
.at(2, 3) = D(X021
* F
!(0.022887f) + X023
* F
!(-0.097545f) + X025
* F
!(0.490393f) + X027
* F
!(0.865723f));
886 P
.at(3, 1) = D(X031
* F
!(0.415735f) + X033
* F
!(0.791065f) + X035
* F
!(-0.352443f) + X037
* F
!(0.277785f));
888 P
.at(3, 3) = D(X031
* F
!(0.022887f) + X033
* F
!(-0.097545f) + X035
* F
!(0.490393f) + X037
* F
!(0.865723f));
891 // 4x4 = 4x8 times 8x4, matrix 1 is constant
892 Q
.at(0, 0) = D(X001
* F
!(0.906127f) + X003
* F
!(-0.318190f) + X005
* F
!(0.212608f) + X007
* F
!(-0.180240f));
894 Q
.at(0, 2) = D(X001
* F
!(-0.074658f) + X003
* F
!(0.513280f) + X005
* F
!(0.768178f) + X007
* F
!(-0.375330f));
896 Q
.at(1, 0) = D(X011
* F
!(0.906127f) + X013
* F
!(-0.318190f) + X015
* F
!(0.212608f) + X017
* F
!(-0.180240f));
898 Q
.at(1, 2) = D(X011
* F
!(-0.074658f) + X013
* F
!(0.513280f) + X015
* F
!(0.768178f) + X017
* F
!(-0.375330f));
900 Q
.at(2, 0) = D(X021
* F
!(0.906127f) + X023
* F
!(-0.318190f) + X025
* F
!(0.212608f) + X027
* F
!(-0.180240f));
902 Q
.at(2, 2) = D(X021
* F
!(-0.074658f) + X023
* F
!(0.513280f) + X025
* F
!(0.768178f) + X027
* F
!(-0.375330f));
904 Q
.at(3, 0) = D(X031
* F
!(0.906127f) + X033
* F
!(-0.318190f) + X035
* F
!(0.212608f) + X037
* F
!(-0.180240f));
906 Q
.at(3, 2) = D(X031
* F
!(-0.074658f) + X033
* F
!(0.513280f) + X035
* F
!(0.768178f) + X037
* F
!(-0.375330f));
912 static struct R_S(int NUM_ROWS
, int NUM_COLS
) {
913 static void calc(ref Matrix44 R
, ref Matrix44 S
, const(jpgd_block_t
)* pSrc
) {
914 //auto AT (int c, int r) nothrow @trusted @nogc { return (c >= NUM_COLS || r >= NUM_ROWS ? 0 : pSrc[c+r*8]); }
915 template AT(int c
, int r
) {
916 static if (c
>= NUM_COLS || r
>= NUM_ROWS
) enum AT
= "0"; else enum AT
= "pSrc["~c
.stringof
~"+"~r
.stringof
~"*8]";
918 // 4x8 = 4x8 times 8x8, matrix 0 is constant
919 immutable Temp_Type X100
= D(F
!(0.906127f) * mixin(AT
!(1, 0)) + F
!(-0.318190f) * mixin(AT
!(3, 0)) + F
!(0.212608f) * mixin(AT
!(5, 0)) + F
!(-0.180240f) * mixin(AT
!(7, 0)));
920 immutable Temp_Type X101
= D(F
!(0.906127f) * mixin(AT
!(1, 1)) + F
!(-0.318190f) * mixin(AT
!(3, 1)) + F
!(0.212608f) * mixin(AT
!(5, 1)) + F
!(-0.180240f) * mixin(AT
!(7, 1)));
921 immutable Temp_Type X102
= D(F
!(0.906127f) * mixin(AT
!(1, 2)) + F
!(-0.318190f) * mixin(AT
!(3, 2)) + F
!(0.212608f) * mixin(AT
!(5, 2)) + F
!(-0.180240f) * mixin(AT
!(7, 2)));
922 immutable Temp_Type X103
= D(F
!(0.906127f) * mixin(AT
!(1, 3)) + F
!(-0.318190f) * mixin(AT
!(3, 3)) + F
!(0.212608f) * mixin(AT
!(5, 3)) + F
!(-0.180240f) * mixin(AT
!(7, 3)));
923 immutable Temp_Type X104
= D(F
!(0.906127f) * mixin(AT
!(1, 4)) + F
!(-0.318190f) * mixin(AT
!(3, 4)) + F
!(0.212608f) * mixin(AT
!(5, 4)) + F
!(-0.180240f) * mixin(AT
!(7, 4)));
924 immutable Temp_Type X105
= D(F
!(0.906127f) * mixin(AT
!(1, 5)) + F
!(-0.318190f) * mixin(AT
!(3, 5)) + F
!(0.212608f) * mixin(AT
!(5, 5)) + F
!(-0.180240f) * mixin(AT
!(7, 5)));
925 immutable Temp_Type X106
= D(F
!(0.906127f) * mixin(AT
!(1, 6)) + F
!(-0.318190f) * mixin(AT
!(3, 6)) + F
!(0.212608f) * mixin(AT
!(5, 6)) + F
!(-0.180240f) * mixin(AT
!(7, 6)));
926 immutable Temp_Type X107
= D(F
!(0.906127f) * mixin(AT
!(1, 7)) + F
!(-0.318190f) * mixin(AT
!(3, 7)) + F
!(0.212608f) * mixin(AT
!(5, 7)) + F
!(-0.180240f) * mixin(AT
!(7, 7)));
927 immutable Temp_Type X110
= mixin(AT
!(2, 0));
928 immutable Temp_Type X111
= mixin(AT
!(2, 1));
929 immutable Temp_Type X112
= mixin(AT
!(2, 2));
930 immutable Temp_Type X113
= mixin(AT
!(2, 3));
931 immutable Temp_Type X114
= mixin(AT
!(2, 4));
932 immutable Temp_Type X115
= mixin(AT
!(2, 5));
933 immutable Temp_Type X116
= mixin(AT
!(2, 6));
934 immutable Temp_Type X117
= mixin(AT
!(2, 7));
935 immutable Temp_Type X120
= D(F
!(-0.074658f) * mixin(AT
!(1, 0)) + F
!(0.513280f) * mixin(AT
!(3, 0)) + F
!(0.768178f) * mixin(AT
!(5, 0)) + F
!(-0.375330f) * mixin(AT
!(7, 0)));
936 immutable Temp_Type X121
= D(F
!(-0.074658f) * mixin(AT
!(1, 1)) + F
!(0.513280f) * mixin(AT
!(3, 1)) + F
!(0.768178f) * mixin(AT
!(5, 1)) + F
!(-0.375330f) * mixin(AT
!(7, 1)));
937 immutable Temp_Type X122
= D(F
!(-0.074658f) * mixin(AT
!(1, 2)) + F
!(0.513280f) * mixin(AT
!(3, 2)) + F
!(0.768178f) * mixin(AT
!(5, 2)) + F
!(-0.375330f) * mixin(AT
!(7, 2)));
938 immutable Temp_Type X123
= D(F
!(-0.074658f) * mixin(AT
!(1, 3)) + F
!(0.513280f) * mixin(AT
!(3, 3)) + F
!(0.768178f) * mixin(AT
!(5, 3)) + F
!(-0.375330f) * mixin(AT
!(7, 3)));
939 immutable Temp_Type X124
= D(F
!(-0.074658f) * mixin(AT
!(1, 4)) + F
!(0.513280f) * mixin(AT
!(3, 4)) + F
!(0.768178f) * mixin(AT
!(5, 4)) + F
!(-0.375330f) * mixin(AT
!(7, 4)));
940 immutable Temp_Type X125
= D(F
!(-0.074658f) * mixin(AT
!(1, 5)) + F
!(0.513280f) * mixin(AT
!(3, 5)) + F
!(0.768178f) * mixin(AT
!(5, 5)) + F
!(-0.375330f) * mixin(AT
!(7, 5)));
941 immutable Temp_Type X126
= D(F
!(-0.074658f) * mixin(AT
!(1, 6)) + F
!(0.513280f) * mixin(AT
!(3, 6)) + F
!(0.768178f) * mixin(AT
!(5, 6)) + F
!(-0.375330f) * mixin(AT
!(7, 6)));
942 immutable Temp_Type X127
= D(F
!(-0.074658f) * mixin(AT
!(1, 7)) + F
!(0.513280f) * mixin(AT
!(3, 7)) + F
!(0.768178f) * mixin(AT
!(5, 7)) + F
!(-0.375330f) * mixin(AT
!(7, 7)));
943 immutable Temp_Type X130
= mixin(AT
!(6, 0));
944 immutable Temp_Type X131
= mixin(AT
!(6, 1));
945 immutable Temp_Type X132
= mixin(AT
!(6, 2));
946 immutable Temp_Type X133
= mixin(AT
!(6, 3));
947 immutable Temp_Type X134
= mixin(AT
!(6, 4));
948 immutable Temp_Type X135
= mixin(AT
!(6, 5));
949 immutable Temp_Type X136
= mixin(AT
!(6, 6));
950 immutable Temp_Type X137
= mixin(AT
!(6, 7));
953 // 4x4 = 4x8 times 8x4, matrix 1 is constant
955 R
.at(0, 1) = D(X101
* F
!(0.415735f) + X103
* F
!(0.791065f) + X105
* F
!(-0.352443f) + X107
* F
!(0.277785f));
957 R
.at(0, 3) = D(X101
* F
!(0.022887f) + X103
* F
!(-0.097545f) + X105
* F
!(0.490393f) + X107
* F
!(0.865723f));
959 R
.at(1, 1) = D(X111
* F
!(0.415735f) + X113
* F
!(0.791065f) + X115
* F
!(-0.352443f) + X117
* F
!(0.277785f));
961 R
.at(1, 3) = D(X111
* F
!(0.022887f) + X113
* F
!(-0.097545f) + X115
* F
!(0.490393f) + X117
* F
!(0.865723f));
963 R
.at(2, 1) = D(X121
* F
!(0.415735f) + X123
* F
!(0.791065f) + X125
* F
!(-0.352443f) + X127
* F
!(0.277785f));
965 R
.at(2, 3) = D(X121
* F
!(0.022887f) + X123
* F
!(-0.097545f) + X125
* F
!(0.490393f) + X127
* F
!(0.865723f));
967 R
.at(3, 1) = D(X131
* F
!(0.415735f) + X133
* F
!(0.791065f) + X135
* F
!(-0.352443f) + X137
* F
!(0.277785f));
969 R
.at(3, 3) = D(X131
* F
!(0.022887f) + X133
* F
!(-0.097545f) + X135
* F
!(0.490393f) + X137
* F
!(0.865723f));
971 // 4x4 = 4x8 times 8x4, matrix 1 is constant
972 S
.at(0, 0) = D(X101
* F
!(0.906127f) + X103
* F
!(-0.318190f) + X105
* F
!(0.212608f) + X107
* F
!(-0.180240f));
974 S
.at(0, 2) = D(X101
* F
!(-0.074658f) + X103
* F
!(0.513280f) + X105
* F
!(0.768178f) + X107
* F
!(-0.375330f));
976 S
.at(1, 0) = D(X111
* F
!(0.906127f) + X113
* F
!(-0.318190f) + X115
* F
!(0.212608f) + X117
* F
!(-0.180240f));
978 S
.at(1, 2) = D(X111
* F
!(-0.074658f) + X113
* F
!(0.513280f) + X115
* F
!(0.768178f) + X117
* F
!(-0.375330f));
980 S
.at(2, 0) = D(X121
* F
!(0.906127f) + X123
* F
!(-0.318190f) + X125
* F
!(0.212608f) + X127
* F
!(-0.180240f));
982 S
.at(2, 2) = D(X121
* F
!(-0.074658f) + X123
* F
!(0.513280f) + X125
* F
!(0.768178f) + X127
* F
!(-0.375330f));
984 S
.at(3, 0) = D(X131
* F
!(0.906127f) + X133
* F
!(-0.318190f) + X135
* F
!(0.212608f) + X137
* F
!(-0.180240f));
986 S
.at(3, 2) = D(X131
* F
!(-0.074658f) + X133
* F
!(0.513280f) + X135
* F
!(0.768178f) + X137
* F
!(-0.375330f));
991 } // end namespace DCT_Upsample
993 // Unconditionally frees all allocated m_blocks.
994 void free_all_blocks () {
997 for (mem_block
*b
= m_pMem_blocks
; b
; ) {
998 mem_block
* n
= b
.m_pNext
;
1002 m_pMem_blocks
= null;
1005 // This method handles all errors. It will never return.
1006 // It could easily be changed to use C++ exceptions.
1007 /*JPGD_NORETURN*/ void stop_decoding (jpgd_status status
) {
1008 m_error_code
= status
;
1010 //longjmp(m_jmp_state, status);
1011 throw new Exception("jpeg decoding error");
1014 void* alloc (usize nSize
, bool zero
=false) {
1015 nSize
= (JPGD_MAX(nSize
, 1) + 3) & ~3;
1017 for (mem_block
*b
= m_pMem_blocks
; b
; b
= b
.m_pNext
)
1019 if ((b
.m_used_count
+ nSize
) <= b
.m_size
)
1021 rv
= b
.m_data
.ptr
+ b
.m_used_count
;
1022 b
.m_used_count
+= nSize
;
1028 int capacity
= JPGD_MAX(32768 - 256, (nSize
+ 2047) & ~2047);
1029 mem_block
*b
= cast(mem_block
*)jpgd_malloc(mem_block
.sizeof
+ capacity
);
1030 if (!b
) { stop_decoding(JPGD_NOTENOUGHMEM
); }
1031 b
.m_pNext
= m_pMem_blocks
; m_pMem_blocks
= b
;
1032 b
.m_used_count
= nSize
;
1033 b
.m_size
= capacity
;
1036 if (zero
) memset(rv
, 0, nSize
);
1040 void word_clear (void *p
, ushort c
, uint n
) {
1041 ubyte *pD
= cast(ubyte*)p
;
1042 immutable ubyte l
= c
& 0xFF, h
= (c
>> 8) & 0xFF;
1045 pD
[0] = l
; pD
[1] = h
; pD
+= 2;
1050 // Refill the input buffer.
1051 // This method will sit in a loop until (A) the buffer is full or (B)
1052 // the stream's read() method reports and end of file condition.
1053 void prep_in_buffer () {
1055 m_pIn_buf_ofs
= m_in_buf
.ptr
;
1062 int bytes_read
= readfn(m_in_buf
.ptr
+ m_in_buf_left
, JPGD_IN_BUF_SIZE
- m_in_buf_left
, &m_eof_flag
);
1063 if (bytes_read
== -1)
1064 stop_decoding(JPGD_STREAM_READ
);
1066 m_in_buf_left
+= bytes_read
;
1067 } while ((m_in_buf_left
< JPGD_IN_BUF_SIZE
) && (!m_eof_flag
));
1069 m_total_bytes_read
+= m_in_buf_left
;
1071 // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
1072 // (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.)
1073 word_clear(m_pIn_buf_ofs
+ m_in_buf_left
, 0xD9FF, 64);
1076 // Read a Huffman code table.
1077 void read_dht_marker () {
1078 int i
, index
, count
;
1080 ubyte[256] huff_val
;
1082 uint num_left
= get_bits(16);
1085 stop_decoding(JPGD_BAD_DHT_MARKER
);
1091 index
= get_bits(8);
1093 huff_num
.ptr
[0] = 0;
1097 for (i
= 1; i
<= 16; i
++)
1099 huff_num
.ptr
[i
] = cast(ubyte)(get_bits(8));
1100 count
+= huff_num
.ptr
[i
];
1104 stop_decoding(JPGD_BAD_DHT_COUNTS
);
1106 for (i
= 0; i
< count
; i
++)
1107 huff_val
.ptr
[i
] = cast(ubyte)(get_bits(8));
1111 if (num_left
< cast(uint)i
)
1112 stop_decoding(JPGD_BAD_DHT_MARKER
);
1116 if ((index
& 0x10) > 0x10)
1117 stop_decoding(JPGD_BAD_DHT_INDEX
);
1119 index
= (index
& 0x0F) + ((index
& 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES
>> 1);
1121 if (index
>= JPGD_MAX_HUFF_TABLES
)
1122 stop_decoding(JPGD_BAD_DHT_INDEX
);
1124 if (!m_huff_num
.ptr
[index
])
1125 m_huff_num
.ptr
[index
] = cast(ubyte*)alloc(17);
1127 if (!m_huff_val
.ptr
[index
])
1128 m_huff_val
.ptr
[index
] = cast(ubyte*)alloc(256);
1130 m_huff_ac
.ptr
[index
] = (index
& 0x10) != 0;
1131 memcpy(m_huff_num
.ptr
[index
], huff_num
.ptr
, 17);
1132 memcpy(m_huff_val
.ptr
[index
], huff_val
.ptr
, 256);
1136 // Read a quantization table.
1137 void read_dqt_marker () {
1142 num_left
= get_bits(16);
1145 stop_decoding(JPGD_BAD_DQT_MARKER
);
1155 if (n
>= JPGD_MAX_QUANT_TABLES
)
1156 stop_decoding(JPGD_BAD_DQT_TABLE
);
1158 if (!m_quant
.ptr
[n
])
1159 m_quant
.ptr
[n
] = cast(jpgd_quant_t
*)alloc(64 * jpgd_quant_t
.sizeof
);
1161 // read quantization entries, in zag order
1162 for (i
= 0; i
< 64; i
++)
1167 temp
= (temp
<< 8) + get_bits(8);
1169 m_quant
.ptr
[n
][i
] = cast(jpgd_quant_t
)(temp
);
1177 if (num_left
< cast(uint)i
)
1178 stop_decoding(JPGD_BAD_DQT_LENGTH
);
1184 // Read the start of frame (SOF) marker.
1185 void read_sof_marker () {
1189 num_left
= get_bits(16);
1191 if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */
1192 stop_decoding(JPGD_BAD_PRECISION
);
1194 m_image_y_size
= get_bits(16);
1196 if ((m_image_y_size
< 1) ||
(m_image_y_size
> JPGD_MAX_HEIGHT
))
1197 stop_decoding(JPGD_BAD_HEIGHT
);
1199 m_image_x_size
= get_bits(16);
1201 if ((m_image_x_size
< 1) ||
(m_image_x_size
> JPGD_MAX_WIDTH
))
1202 stop_decoding(JPGD_BAD_WIDTH
);
1204 m_comps_in_frame
= get_bits(8);
1206 if (m_comps_in_frame
> JPGD_MAX_COMPONENTS
)
1207 stop_decoding(JPGD_TOO_MANY_COMPONENTS
);
1209 if (num_left
!= cast(uint)(m_comps_in_frame
* 3 + 8))
1210 stop_decoding(JPGD_BAD_SOF_LENGTH
);
1212 for (i
= 0; i
< m_comps_in_frame
; i
++)
1214 m_comp_ident
.ptr
[i
] = get_bits(8);
1215 m_comp_h_samp
.ptr
[i
] = get_bits(4);
1216 m_comp_v_samp
.ptr
[i
] = get_bits(4);
1217 m_comp_quant
.ptr
[i
] = get_bits(8);
1221 // Used to skip unrecognized markers.
1222 void skip_variable_marker () {
1225 num_left
= get_bits(16);
1228 stop_decoding(JPGD_BAD_VARIABLE_MARKER
);
1239 // Read a define restart interval (DRI) marker.
1240 void read_dri_marker () {
1241 if (get_bits(16) != 4)
1242 stop_decoding(JPGD_BAD_DRI_LENGTH
);
1244 m_restart_interval
= get_bits(16);
1247 // Read a start of scan (SOS) marker.
1248 void read_sos_marker () {
1250 int i
, ci
, n
, c
, cc
;
1252 num_left
= get_bits(16);
1256 m_comps_in_scan
= n
;
1260 if ( (num_left
!= cast(uint)(n
* 2 + 3)) ||
(n
< 1) ||
(n
> JPGD_MAX_COMPS_IN_SCAN
) )
1261 stop_decoding(JPGD_BAD_SOS_LENGTH
);
1263 for (i
= 0; i
< n
; i
++)
1269 for (ci
= 0; ci
< m_comps_in_frame
; ci
++)
1270 if (cc
== m_comp_ident
.ptr
[ci
])
1273 if (ci
>= m_comps_in_frame
)
1274 stop_decoding(JPGD_BAD_SOS_COMP_ID
);
1276 m_comp_list
.ptr
[i
] = ci
;
1277 m_comp_dc_tab
.ptr
[ci
] = (c
>> 4) & 15;
1278 m_comp_ac_tab
.ptr
[ci
] = (c
& 15) + (JPGD_MAX_HUFF_TABLES
>> 1);
1281 m_spectral_start
= get_bits(8);
1282 m_spectral_end
= get_bits(8);
1283 m_successive_high
= get_bits(4);
1284 m_successive_low
= get_bits(4);
1286 if (!m_progressive_flag
)
1288 m_spectral_start
= 0;
1289 m_spectral_end
= 63;
1294 /* read past whatever is num_left */
1302 // Finds the next marker.
1303 int next_marker () {
1314 } while (c
!= 0xFF);
1319 } while (c
== 0xFF);
1323 // If bytes > 0 here, there where extra bytes before the marker (not good).
1328 // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
1330 int process_markers () {
1359 // No arithmitic support - dumb patents!
1361 stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT
);
1369 //case M_APP0: /* no need to read the JFIF marker */
1372 case M_RST0
: /* no parameters */
1381 stop_decoding(JPGD_UNEXPECTED_MARKER
);
1383 default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
1384 skip_variable_marker();
1390 // Finds the start of image (SOI) marker.
1391 // This code is rather defensive: it only checks the first 512 bytes to avoid
1393 void locate_soi_marker () {
1394 uint lastchar
, thischar
;
1397 lastchar
= get_bits(8);
1399 thischar
= get_bits(8);
1401 /* ok if it's a normal JPEG file without a special header */
1403 if ((lastchar
== 0xFF) && (thischar
== M_SOI
))
1406 bytesleft
= 4096; //512;
1410 if (--bytesleft
== 0)
1411 stop_decoding(JPGD_NOT_JPEG
);
1413 lastchar
= thischar
;
1415 thischar
= get_bits(8);
1417 if (lastchar
== 0xFF)
1419 if (thischar
== M_SOI
)
1421 else if (thischar
== M_EOI
) // get_bits will keep returning M_EOI if we read past the end
1422 stop_decoding(JPGD_NOT_JPEG
);
1426 // 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.
1427 thischar
= (m_bit_buf
>> 24) & 0xFF;
1429 if (thischar
!= 0xFF)
1430 stop_decoding(JPGD_NOT_JPEG
);
1433 // Find a start of frame (SOF) marker.
1434 void locate_sof_marker () {
1435 locate_soi_marker();
1437 int c
= process_markers();
1442 m_progressive_flag
= true;
1444 case M_SOF0
: /* baseline DCT */
1445 case M_SOF1
: /* extended sequential DCT */
1448 case M_SOF9
: /* Arithmitic coding */
1449 stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT
);
1452 stop_decoding(JPGD_UNSUPPORTED_MARKER
);
1457 // Find a start of scan (SOS) marker.
1458 int locate_sos_marker () {
1461 c
= process_markers();
1465 else if (c
!= M_SOS
)
1466 stop_decoding(JPGD_UNEXPECTED_MARKER
);
1473 // Reset everything to default/uninitialized state.
1474 void initit (JpegStreamReadFunc rfn
) {
1475 m_pMem_blocks
= null;
1476 m_error_code
= JPGD_SUCCESS
;
1477 m_ready_flag
= false;
1478 m_image_x_size
= m_image_y_size
= 0;
1480 m_progressive_flag
= false;
1482 memset(m_huff_ac
.ptr
, 0, m_huff_ac
.sizeof
);
1483 memset(m_huff_num
.ptr
, 0, m_huff_num
.sizeof
);
1484 memset(m_huff_val
.ptr
, 0, m_huff_val
.sizeof
);
1485 memset(m_quant
.ptr
, 0, m_quant
.sizeof
);
1488 m_comps_in_frame
= 0;
1490 memset(m_comp_h_samp
.ptr
, 0, m_comp_h_samp
.sizeof
);
1491 memset(m_comp_v_samp
.ptr
, 0, m_comp_v_samp
.sizeof
);
1492 memset(m_comp_quant
.ptr
, 0, m_comp_quant
.sizeof
);
1493 memset(m_comp_ident
.ptr
, 0, m_comp_ident
.sizeof
);
1494 memset(m_comp_h_blocks
.ptr
, 0, m_comp_h_blocks
.sizeof
);
1495 memset(m_comp_v_blocks
.ptr
, 0, m_comp_v_blocks
.sizeof
);
1497 m_comps_in_scan
= 0;
1498 memset(m_comp_list
.ptr
, 0, m_comp_list
.sizeof
);
1499 memset(m_comp_dc_tab
.ptr
, 0, m_comp_dc_tab
.sizeof
);
1500 memset(m_comp_ac_tab
.ptr
, 0, m_comp_ac_tab
.sizeof
);
1502 m_spectral_start
= 0;
1504 m_successive_low
= 0;
1505 m_successive_high
= 0;
1506 m_max_mcu_x_size
= 0;
1507 m_max_mcu_y_size
= 0;
1508 m_blocks_per_mcu
= 0;
1509 m_max_blocks_per_row
= 0;
1512 m_expanded_blocks_per_component
= 0;
1513 m_expanded_blocks_per_mcu
= 0;
1514 m_expanded_blocks_per_row
= 0;
1515 m_freq_domain_chroma_upsample
= false;
1517 memset(m_mcu_org
.ptr
, 0, m_mcu_org
.sizeof
);
1519 m_total_lines_left
= 0;
1520 m_mcu_lines_left
= 0;
1521 m_real_dest_bytes_per_scan_line
= 0;
1522 m_dest_bytes_per_scan_line
= 0;
1523 m_dest_bytes_per_pixel
= 0;
1525 memset(m_pHuff_tabs
.ptr
, 0, m_pHuff_tabs
.sizeof
);
1527 memset(m_dc_coeffs
.ptr
, 0, m_dc_coeffs
.sizeof
);
1528 memset(m_ac_coeffs
.ptr
, 0, m_ac_coeffs
.sizeof
);
1529 memset(m_block_y_mcu
.ptr
, 0, m_block_y_mcu
.sizeof
);
1533 memset(m_block_y_mcu
.ptr
, 0, m_block_y_mcu
.sizeof
);
1535 m_pIn_buf_ofs
= m_in_buf
.ptr
;
1540 memset(m_in_buf_pad_start
.ptr
, 0, m_in_buf_pad_start
.sizeof
);
1541 memset(m_in_buf
.ptr
, 0, m_in_buf
.sizeof
);
1542 memset(m_in_buf_pad_end
.ptr
, 0, m_in_buf_pad_end
.sizeof
);
1544 m_restart_interval
= 0;
1545 m_restarts_left
= 0;
1546 m_next_restart_num
= 0;
1548 m_max_mcus_per_row
= 0;
1549 m_max_blocks_per_mcu
= 0;
1550 m_max_mcus_per_col
= 0;
1552 memset(m_last_dc_val
.ptr
, 0, m_last_dc_val
.sizeof
);
1553 m_pMCU_coefficients
= null;
1554 m_pSample_buf
= null;
1556 m_total_bytes_read
= 0;
1558 m_pScan_line_0
= null;
1559 m_pScan_line_1
= null;
1561 // Ready the input buffer.
1564 // Prime the bit buffer.
1571 for (int i
= 0; i
< JPGD_MAX_BLOCKS_PER_MCU
; i
++)
1572 m_mcu_block_max_zag
.ptr
[i
] = 64;
1575 enum SCALEBITS
= 16;
1576 enum ONE_HALF
= (cast(int) 1 << (SCALEBITS
-1));
1577 enum FIX(float x
) = (cast(int)((x
) * (1L<<SCALEBITS
) + 0.5f));
1579 // Create a few tables that allow us to quickly convert YCbCr to RGB.
1580 void create_look_ups () {
1581 for (int i
= 0; i
<= 255; i
++)
1584 m_crr
.ptr
[i
] = ( FIX
!(1.40200f) * k
+ ONE_HALF
) >> SCALEBITS
;
1585 m_cbb
.ptr
[i
] = ( FIX
!(1.77200f) * k
+ ONE_HALF
) >> SCALEBITS
;
1586 m_crg
.ptr
[i
] = (-FIX
!(0.71414f)) * k
;
1587 m_cbg
.ptr
[i
] = (-FIX
!(0.34414f)) * k
+ ONE_HALF
;
1591 // This method throws back into the stream any bytes that where read
1592 // into the bit buffer during initial marker scanning.
1593 void fix_in_buffer () {
1594 // In case any 0xFF's where pulled into the buffer during marker scanning.
1595 assert((m_bits_left
& 7) == 0);
1597 if (m_bits_left
== 16)
1598 stuff_char(cast(ubyte)(m_bit_buf
& 0xFF));
1600 if (m_bits_left
>= 8)
1601 stuff_char(cast(ubyte)((m_bit_buf
>> 8) & 0xFF));
1603 stuff_char(cast(ubyte)((m_bit_buf
>> 16) & 0xFF));
1604 stuff_char(cast(ubyte)((m_bit_buf
>> 24) & 0xFF));
1607 get_bits_no_markers(16);
1608 get_bits_no_markers(16);
1611 void transform_mcu (int mcu_row
) {
1612 jpgd_block_t
* pSrc_ptr
= m_pMCU_coefficients
;
1613 ubyte* pDst_ptr
= m_pSample_buf
+ mcu_row
* m_blocks_per_mcu
* 64;
1615 for (int mcu_block
= 0; mcu_block
< m_blocks_per_mcu
; mcu_block
++)
1617 idct(pSrc_ptr
, pDst_ptr
, m_mcu_block_max_zag
.ptr
[mcu_block
]);
1623 static immutable ubyte[64] s_max_rc
= [
1624 17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86,
1625 102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136,
1626 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
1627 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136
1630 void transform_mcu_expand (int mcu_row
) {
1631 jpgd_block_t
* pSrc_ptr
= m_pMCU_coefficients
;
1632 ubyte* pDst_ptr
= m_pSample_buf
+ mcu_row
* m_expanded_blocks_per_mcu
* 64;
1636 for (mcu_block
= 0; mcu_block
< m_expanded_blocks_per_component
; mcu_block
++)
1638 idct(pSrc_ptr
, pDst_ptr
, m_mcu_block_max_zag
.ptr
[mcu_block
]);
1643 // Chroma IDCT, with upsampling
1644 jpgd_block_t
[64] temp_block
;
1646 for (int i
= 0; i
< 2; i
++)
1648 DCT_Upsample
.Matrix44 P
, Q
, R
, S
;
1650 assert(m_mcu_block_max_zag
.ptr
[mcu_block
] >= 1);
1651 assert(m_mcu_block_max_zag
.ptr
[mcu_block
] <= 64);
1653 int max_zag
= m_mcu_block_max_zag
.ptr
[mcu_block
++] - 1;
1654 if (max_zag
<= 0) max_zag
= 0; // should never happen, only here to shut up static analysis
1655 switch (s_max_rc
.ptr
[max_zag
])
1658 DCT_Upsample
.P_Q
!(1, 1).calc(P
, Q
, pSrc_ptr
);
1659 DCT_Upsample
.R_S
!(1, 1).calc(R
, S
, pSrc_ptr
);
1662 DCT_Upsample
.P_Q
!(1, 2).calc(P
, Q
, pSrc_ptr
);
1663 DCT_Upsample
.R_S
!(1, 2).calc(R
, S
, pSrc_ptr
);
1666 DCT_Upsample
.P_Q
!(2, 2).calc(P
, Q
, pSrc_ptr
);
1667 DCT_Upsample
.R_S
!(2, 2).calc(R
, S
, pSrc_ptr
);
1670 DCT_Upsample
.P_Q
!(3, 2).calc(P
, Q
, pSrc_ptr
);
1671 DCT_Upsample
.R_S
!(3, 2).calc(R
, S
, pSrc_ptr
);
1674 DCT_Upsample
.P_Q
!(3, 3).calc(P
, Q
, pSrc_ptr
);
1675 DCT_Upsample
.R_S
!(3, 3).calc(R
, S
, pSrc_ptr
);
1678 DCT_Upsample
.P_Q
!(3, 4).calc(P
, Q
, pSrc_ptr
);
1679 DCT_Upsample
.R_S
!(3, 4).calc(R
, S
, pSrc_ptr
);
1682 DCT_Upsample
.P_Q
!(4, 4).calc(P
, Q
, pSrc_ptr
);
1683 DCT_Upsample
.R_S
!(4, 4).calc(R
, S
, pSrc_ptr
);
1686 DCT_Upsample
.P_Q
!(5, 4).calc(P
, Q
, pSrc_ptr
);
1687 DCT_Upsample
.R_S
!(5, 4).calc(R
, S
, pSrc_ptr
);
1690 DCT_Upsample
.P_Q
!(5, 5).calc(P
, Q
, pSrc_ptr
);
1691 DCT_Upsample
.R_S
!(5, 5).calc(R
, S
, pSrc_ptr
);
1694 DCT_Upsample
.P_Q
!(5, 6).calc(P
, Q
, pSrc_ptr
);
1695 DCT_Upsample
.R_S
!(5, 6).calc(R
, S
, pSrc_ptr
);
1698 DCT_Upsample
.P_Q
!(6, 6).calc(P
, Q
, pSrc_ptr
);
1699 DCT_Upsample
.R_S
!(6, 6).calc(R
, S
, pSrc_ptr
);
1702 DCT_Upsample
.P_Q
!(7, 6).calc(P
, Q
, pSrc_ptr
);
1703 DCT_Upsample
.R_S
!(7, 6).calc(R
, S
, pSrc_ptr
);
1706 DCT_Upsample
.P_Q
!(7, 7).calc(P
, Q
, pSrc_ptr
);
1707 DCT_Upsample
.R_S
!(7, 7).calc(R
, S
, pSrc_ptr
);
1710 DCT_Upsample
.P_Q
!(7, 8).calc(P
, Q
, pSrc_ptr
);
1711 DCT_Upsample
.R_S
!(7, 8).calc(R
, S
, pSrc_ptr
);
1714 DCT_Upsample
.P_Q
!(8, 8).calc(P
, Q
, pSrc_ptr
);
1715 DCT_Upsample
.R_S
!(8, 8).calc(R
, S
, pSrc_ptr
);
1721 auto a
= DCT_Upsample
.Matrix44(P
+ Q
);
1723 DCT_Upsample
.Matrix44
* b
= &P
;
1724 auto c
= DCT_Upsample
.Matrix44(R
+ S
);
1726 DCT_Upsample
.Matrix44
* d
= &R
;
1728 DCT_Upsample
.Matrix44
.add_and_store(temp_block
.ptr
, a
, c
);
1729 idct_4x4(temp_block
.ptr
, pDst_ptr
);
1732 DCT_Upsample
.Matrix44
.sub_and_store(temp_block
.ptr
, a
, c
);
1733 idct_4x4(temp_block
.ptr
, pDst_ptr
);
1736 DCT_Upsample
.Matrix44
.add_and_store(temp_block
.ptr
, *b
, *d
);
1737 idct_4x4(temp_block
.ptr
, pDst_ptr
);
1740 DCT_Upsample
.Matrix44
.sub_and_store(temp_block
.ptr
, *b
, *d
);
1741 idct_4x4(temp_block
.ptr
, pDst_ptr
);
1748 // Loads and dequantizes the next row of (already decoded) coefficients.
1749 // Progressive images only.
1750 void load_next_row () {
1754 int mcu_row
, mcu_block
, row_block
= 0;
1755 int component_num
, component_id
;
1756 int[JPGD_MAX_COMPONENTS
] block_x_mcu
;
1758 memset(block_x_mcu
.ptr
, 0, JPGD_MAX_COMPONENTS
* int.sizeof
);
1760 for (mcu_row
= 0; mcu_row
< m_mcus_per_row
; mcu_row
++)
1762 int block_x_mcu_ofs
= 0, block_y_mcu_ofs
= 0;
1764 for (mcu_block
= 0; mcu_block
< m_blocks_per_mcu
; mcu_block
++)
1766 component_id
= m_mcu_org
.ptr
[mcu_block
];
1767 q
= m_quant
.ptr
[m_comp_quant
.ptr
[component_id
]];
1769 p
= m_pMCU_coefficients
+ 64 * mcu_block
;
1771 jpgd_block_t
* pAC
= coeff_buf_getp(m_ac_coeffs
.ptr
[component_id
], block_x_mcu
.ptr
[component_id
] + block_x_mcu_ofs
, m_block_y_mcu
.ptr
[component_id
] + block_y_mcu_ofs
);
1772 jpgd_block_t
* pDC
= coeff_buf_getp(m_dc_coeffs
.ptr
[component_id
], block_x_mcu
.ptr
[component_id
] + block_x_mcu_ofs
, m_block_y_mcu
.ptr
[component_id
] + block_y_mcu_ofs
);
1774 memcpy(&p
[1], &pAC
[1], 63 * jpgd_block_t
.sizeof
);
1776 for (i
= 63; i
> 0; i
--)
1780 m_mcu_block_max_zag
.ptr
[mcu_block
] = i
+ 1;
1782 for ( ; i
>= 0; i
--)
1784 p
[g_ZAG
[i
]] = cast(jpgd_block_t
)(p
[g_ZAG
[i
]] * q
[i
]);
1788 if (m_comps_in_scan
== 1)
1789 block_x_mcu
.ptr
[component_id
]++;
1792 if (++block_x_mcu_ofs
== m_comp_h_samp
.ptr
[component_id
])
1794 block_x_mcu_ofs
= 0;
1796 if (++block_y_mcu_ofs
== m_comp_v_samp
.ptr
[component_id
])
1798 block_y_mcu_ofs
= 0;
1800 block_x_mcu
.ptr
[component_id
] += m_comp_h_samp
.ptr
[component_id
];
1806 if (m_freq_domain_chroma_upsample
)
1807 transform_mcu_expand(mcu_row
);
1809 transform_mcu(mcu_row
);
1812 if (m_comps_in_scan
== 1)
1813 m_block_y_mcu
.ptr
[m_comp_list
.ptr
[0]]++;
1816 for (component_num
= 0; component_num
< m_comps_in_scan
; component_num
++)
1818 component_id
= m_comp_list
.ptr
[component_num
];
1820 m_block_y_mcu
.ptr
[component_id
] += m_comp_v_samp
.ptr
[component_id
];
1825 // Restart interval processing.
1826 void process_restart () {
1830 // Align to a byte boundry
1831 // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
1832 //get_bits_no_markers(m_bits_left & 7);
1834 // Let's scan a little bit to find the marker, but not _too_ far.
1835 // 1536 is a "fudge factor" that determines how much to scan.
1836 for (i
= 1536; i
> 0; i
--)
1837 if (get_char() == 0xFF)
1841 stop_decoding(JPGD_BAD_RESTART_MARKER
);
1844 if ((c
= get_char()) != 0xFF)
1848 stop_decoding(JPGD_BAD_RESTART_MARKER
);
1850 // Is it the expected marker? If not, something bad happened.
1851 if (c
!= (m_next_restart_num
+ M_RST0
))
1852 stop_decoding(JPGD_BAD_RESTART_MARKER
);
1854 // Reset each component's DC prediction values.
1855 memset(&m_last_dc_val
, 0, m_comps_in_frame
* uint.sizeof
);
1859 m_restarts_left
= m_restart_interval
;
1861 m_next_restart_num
= (m_next_restart_num
+ 1) & 7;
1863 // Get the bit buffer going again...
1866 get_bits_no_markers(16);
1867 get_bits_no_markers(16);
1870 static int dequantize_ac (int c
, int q
) { pragma(inline
, true); c
*= q
; return c
; }
1872 // Decodes and dequantizes the next row of coefficients.
1873 void decode_next_row () {
1876 for (int mcu_row
= 0; mcu_row
< m_mcus_per_row
; mcu_row
++)
1878 if ((m_restart_interval
) && (m_restarts_left
== 0))
1881 jpgd_block_t
* p
= m_pMCU_coefficients
;
1882 for (int mcu_block
= 0; mcu_block
< m_blocks_per_mcu
; mcu_block
++, p
+= 64)
1884 int component_id
= m_mcu_org
.ptr
[mcu_block
];
1885 jpgd_quant_t
* q
= m_quant
.ptr
[m_comp_quant
.ptr
[component_id
]];
1888 s
= huff_decode(m_pHuff_tabs
.ptr
[m_comp_dc_tab
.ptr
[component_id
]], r
);
1889 s
= JPGD_HUFF_EXTEND(r
, s
);
1891 m_last_dc_val
.ptr
[component_id
] = (s
+= m_last_dc_val
.ptr
[component_id
]);
1893 p
[0] = cast(jpgd_block_t
)(s
* q
[0]);
1895 int prev_num_set
= m_mcu_block_max_zag
.ptr
[mcu_block
];
1897 huff_tables
*pH
= m_pHuff_tabs
.ptr
[m_comp_ac_tab
.ptr
[component_id
]];
1900 for (k
= 1; k
< 64; k
++)
1903 s
= huff_decode(pH
, extra_bits
);
1913 stop_decoding(JPGD_DECODE_ERROR
);
1915 if (k
< prev_num_set
)
1917 int n
= JPGD_MIN(r
, prev_num_set
- k
);
1926 s
= JPGD_HUFF_EXTEND(extra_bits
, s
);
1930 p
[g_ZAG
[k
]] = cast(jpgd_block_t
)(dequantize_ac(s
, q
[k
])); //s * q[k];
1937 stop_decoding(JPGD_DECODE_ERROR
);
1939 if (k
< prev_num_set
)
1941 int n
= JPGD_MIN(16, prev_num_set
- k
);
1950 k
+= 16 - 1; // - 1 because the loop counter is k
1951 assert(p
[g_ZAG
[k
]] == 0);
1958 if (k
< prev_num_set
)
1961 while (kt
< prev_num_set
)
1965 m_mcu_block_max_zag
.ptr
[mcu_block
] = k
;
1970 if (m_freq_domain_chroma_upsample
)
1971 transform_mcu_expand(mcu_row
);
1973 transform_mcu(mcu_row
);
1979 // YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
1980 void H1V1Convert () {
1981 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
1982 ubyte *d
= m_pScan_line_0
;
1983 ubyte *s
= m_pSample_buf
+ row
* 8;
1985 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
1987 for (int j
= 0; j
< 8; j
++)
1993 d
[0] = clamp(y
+ m_crr
.ptr
[cr
]);
1994 d
[1] = clamp(y
+ ((m_crg
.ptr
[cr
] + m_cbg
.ptr
[cb
]) >> 16));
1995 d
[2] = clamp(y
+ m_cbb
.ptr
[cb
]);
2005 // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
2006 void H2V1Convert () {
2007 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
2008 ubyte *d0
= m_pScan_line_0
;
2009 ubyte *y
= m_pSample_buf
+ row
* 8;
2010 ubyte *c
= m_pSample_buf
+ 2*64 + row
* 8;
2012 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
2014 for (int l
= 0; l
< 2; l
++)
2016 for (int j
= 0; j
< 4; j
++)
2021 int rc
= m_crr
.ptr
[cr
];
2022 int gc
= ((m_crg
.ptr
[cr
] + m_cbg
.ptr
[cb
]) >> 16);
2023 int bc
= m_cbb
.ptr
[cb
];
2026 d0
[0] = clamp(yy
+rc
);
2027 d0
[1] = clamp(yy
+gc
);
2028 d0
[2] = clamp(yy
+bc
);
2032 d0
[4] = clamp(yy
+rc
);
2033 d0
[5] = clamp(yy
+gc
);
2034 d0
[6] = clamp(yy
+bc
);
2049 // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
2050 void H1V2Convert () {
2051 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
2052 ubyte *d0
= m_pScan_line_0
;
2053 ubyte *d1
= m_pScan_line_1
;
2058 y
= m_pSample_buf
+ row
* 8;
2060 y
= m_pSample_buf
+ 64*1 + (row
& 7) * 8;
2062 c
= m_pSample_buf
+ 64*2 + (row
>> 1) * 8;
2064 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
2066 for (int j
= 0; j
< 8; j
++)
2071 int rc
= m_crr
.ptr
[cr
];
2072 int gc
= ((m_crg
.ptr
[cr
] + m_cbg
.ptr
[cb
]) >> 16);
2073 int bc
= m_cbb
.ptr
[cb
];
2076 d0
[0] = clamp(yy
+rc
);
2077 d0
[1] = clamp(yy
+gc
);
2078 d0
[2] = clamp(yy
+bc
);
2082 d1
[0] = clamp(yy
+rc
);
2083 d1
[1] = clamp(yy
+gc
);
2084 d1
[2] = clamp(yy
+bc
);
2096 // YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
2097 void H2V2Convert () {
2098 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
2099 ubyte *d0
= m_pScan_line_0
;
2100 ubyte *d1
= m_pScan_line_1
;
2105 y
= m_pSample_buf
+ row
* 8;
2107 y
= m_pSample_buf
+ 64*2 + (row
& 7) * 8;
2109 c
= m_pSample_buf
+ 64*4 + (row
>> 1) * 8;
2111 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
2113 for (int l
= 0; l
< 2; l
++)
2115 for (int j
= 0; j
< 8; j
+= 2)
2120 int rc
= m_crr
.ptr
[cr
];
2121 int gc
= ((m_crg
.ptr
[cr
] + m_cbg
.ptr
[cb
]) >> 16);
2122 int bc
= m_cbb
.ptr
[cb
];
2125 d0
[0] = clamp(yy
+rc
);
2126 d0
[1] = clamp(yy
+gc
);
2127 d0
[2] = clamp(yy
+bc
);
2131 d0
[4] = clamp(yy
+rc
);
2132 d0
[5] = clamp(yy
+gc
);
2133 d0
[6] = clamp(yy
+bc
);
2137 d1
[0] = clamp(yy
+rc
);
2138 d1
[1] = clamp(yy
+gc
);
2139 d1
[2] = clamp(yy
+bc
);
2143 d1
[4] = clamp(yy
+rc
);
2144 d1
[5] = clamp(yy
+gc
);
2145 d1
[6] = clamp(yy
+bc
);
2161 // Y (1 block per MCU) to 8-bit grayscale
2162 void gray_convert () {
2163 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
2164 ubyte *d
= m_pScan_line_0
;
2165 ubyte *s
= m_pSample_buf
+ row
* 8;
2167 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
2169 *cast(uint*)d
= *cast(uint*)s
;
2170 *cast(uint*)(&d
[4]) = *cast(uint*)(&s
[4]);
2177 void expanded_convert () {
2178 int row
= m_max_mcu_y_size
- m_mcu_lines_left
;
2180 ubyte* Py
= m_pSample_buf
+ (row
/ 8) * 64 * m_comp_h_samp
.ptr
[0] + (row
& 7) * 8;
2182 ubyte* d
= m_pScan_line_0
;
2184 for (int i
= m_max_mcus_per_row
; i
> 0; i
--)
2186 for (int k
= 0; k
< m_max_mcu_x_size
; k
+= 8)
2188 immutable int Y_ofs
= k
* 8;
2189 immutable int Cb_ofs
= Y_ofs
+ 64 * m_expanded_blocks_per_component
;
2190 immutable int Cr_ofs
= Y_ofs
+ 64 * m_expanded_blocks_per_component
* 2;
2191 for (int j
= 0; j
< 8; j
++)
2193 int y
= Py
[Y_ofs
+ j
];
2194 int cb
= Py
[Cb_ofs
+ j
];
2195 int cr
= Py
[Cr_ofs
+ j
];
2197 d
[0] = clamp(y
+ m_crr
.ptr
[cr
]);
2198 d
[1] = clamp(y
+ ((m_crg
.ptr
[cr
] + m_cbg
.ptr
[cb
]) >> 16));
2199 d
[2] = clamp(y
+ m_cbb
.ptr
[cb
]);
2206 Py
+= 64 * m_expanded_blocks_per_mcu
;
2210 // Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
2212 if (!m_progressive_flag
)
2214 // Attempt to read the EOI marker.
2215 //get_bits_no_markers(m_bits_left & 7);
2217 // Prime the bit buffer
2222 // The next marker _should_ be EOI
2226 m_total_bytes_read
-= m_in_buf_left
;
2229 // Creates the tables needed for efficient Huffman decoding.
2230 void make_huff_table (int index
, huff_tables
*pH
) {
2232 ubyte[257] huffsize
;
2241 pH
.ac_table
= m_huff_ac
.ptr
[index
] != 0;
2245 for (l
= 1; l
<= 16; l
++)
2247 for (i
= 1; i
<= m_huff_num
.ptr
[index
][l
]; i
++)
2248 huffsize
.ptr
[p
++] = cast(ubyte)(l
);
2251 huffsize
.ptr
[p
] = 0;
2256 si
= huffsize
.ptr
[0];
2259 while (huffsize
.ptr
[p
])
2261 while (huffsize
.ptr
[p
] == si
)
2263 huffcode
.ptr
[p
++] = code
;
2271 memset(pH
.look_up
.ptr
, 0, pH
.look_up
.sizeof
);
2272 memset(pH
.look_up2
.ptr
, 0, pH
.look_up2
.sizeof
);
2273 memset(pH
.tree
.ptr
, 0, pH
.tree
.sizeof
);
2274 memset(pH
.code_size
.ptr
, 0, pH
.code_size
.sizeof
);
2282 i
= m_huff_val
.ptr
[index
][p
];
2283 code
= huffcode
.ptr
[p
];
2284 code_size
= huffsize
.ptr
[p
];
2286 pH
.code_size
.ptr
[i
] = cast(ubyte)(code_size
);
2290 code
<<= (8 - code_size
);
2292 for (l
= 1 << (8 - code_size
); l
> 0; l
--)
2296 pH
.look_up
.ptr
[code
] = i
;
2298 bool has_extrabits
= false;
2300 int num_extra_bits
= i
& 15;
2302 int bits_to_fetch
= code_size
;
2305 int total_codesize
= code_size
+ num_extra_bits
;
2306 if (total_codesize
<= 8)
2308 has_extrabits
= true;
2309 extra_bits
= ((1 << num_extra_bits
) - 1) & (code
>> (8 - total_codesize
));
2310 assert(extra_bits
<= 0x7FFF);
2311 bits_to_fetch
+= num_extra_bits
;
2316 pH
.look_up2
.ptr
[code
] = i |
(bits_to_fetch
<< 8);
2318 pH
.look_up2
.ptr
[code
] = i |
0x8000 |
(extra_bits
<< 16) |
(bits_to_fetch
<< 8);
2325 subtree
= (code
>> (code_size
- 8)) & 0xFF;
2327 currententry
= pH
.look_up
.ptr
[subtree
];
2329 if (currententry
== 0)
2331 pH
.look_up
.ptr
[subtree
] = currententry
= nextfreeentry
;
2332 pH
.look_up2
.ptr
[subtree
] = currententry
= nextfreeentry
;
2337 code
<<= (16 - (code_size
- 8));
2339 for (l
= code_size
; l
> 9; l
--)
2341 if ((code
& 0x8000) == 0)
2344 if (pH
.tree
.ptr
[-currententry
- 1] == 0)
2346 pH
.tree
.ptr
[-currententry
- 1] = nextfreeentry
;
2348 currententry
= nextfreeentry
;
2353 currententry
= pH
.tree
.ptr
[-currententry
- 1];
2358 if ((code
& 0x8000) == 0)
2361 pH
.tree
.ptr
[-currententry
- 1] = i
;
2368 // Verifies the quantization tables needed for this scan are available.
2369 void check_quant_tables () {
2370 for (int i
= 0; i
< m_comps_in_scan
; i
++)
2371 if (m_quant
.ptr
[m_comp_quant
.ptr
[m_comp_list
.ptr
[i
]]] == null)
2372 stop_decoding(JPGD_UNDEFINED_QUANT_TABLE
);
2375 // Verifies that all the Huffman tables needed for this scan are available.
2376 void check_huff_tables () {
2377 for (int i
= 0; i
< m_comps_in_scan
; i
++)
2379 if ((m_spectral_start
== 0) && (m_huff_num
.ptr
[m_comp_dc_tab
.ptr
[m_comp_list
.ptr
[i
]]] == null))
2380 stop_decoding(JPGD_UNDEFINED_HUFF_TABLE
);
2382 if ((m_spectral_end
> 0) && (m_huff_num
.ptr
[m_comp_ac_tab
.ptr
[m_comp_list
.ptr
[i
]]] == null))
2383 stop_decoding(JPGD_UNDEFINED_HUFF_TABLE
);
2386 for (int i
= 0; i
< JPGD_MAX_HUFF_TABLES
; i
++)
2387 if (m_huff_num
.ptr
[i
])
2389 if (!m_pHuff_tabs
.ptr
[i
])
2390 m_pHuff_tabs
.ptr
[i
] = cast(huff_tables
*)alloc(huff_tables
.sizeof
);
2392 make_huff_table(i
, m_pHuff_tabs
.ptr
[i
]);
2396 // Determines the component order inside each MCU.
2397 // Also calcs how many MCU's are on each row, etc.
2398 void calc_mcu_block_order () {
2399 int component_num
, component_id
;
2400 int max_h_samp
= 0, max_v_samp
= 0;
2402 for (component_id
= 0; component_id
< m_comps_in_frame
; component_id
++)
2404 if (m_comp_h_samp
.ptr
[component_id
] > max_h_samp
)
2405 max_h_samp
= m_comp_h_samp
.ptr
[component_id
];
2407 if (m_comp_v_samp
.ptr
[component_id
] > max_v_samp
)
2408 max_v_samp
= m_comp_v_samp
.ptr
[component_id
];
2411 for (component_id
= 0; component_id
< m_comps_in_frame
; component_id
++)
2413 m_comp_h_blocks
.ptr
[component_id
] = ((((m_image_x_size
* m_comp_h_samp
.ptr
[component_id
]) + (max_h_samp
- 1)) / max_h_samp
) + 7) / 8;
2414 m_comp_v_blocks
.ptr
[component_id
] = ((((m_image_y_size
* m_comp_v_samp
.ptr
[component_id
]) + (max_v_samp
- 1)) / max_v_samp
) + 7) / 8;
2417 if (m_comps_in_scan
== 1)
2419 m_mcus_per_row
= m_comp_h_blocks
.ptr
[m_comp_list
.ptr
[0]];
2420 m_mcus_per_col
= m_comp_v_blocks
.ptr
[m_comp_list
.ptr
[0]];
2424 m_mcus_per_row
= (((m_image_x_size
+ 7) / 8) + (max_h_samp
- 1)) / max_h_samp
;
2425 m_mcus_per_col
= (((m_image_y_size
+ 7) / 8) + (max_v_samp
- 1)) / max_v_samp
;
2428 if (m_comps_in_scan
== 1)
2430 m_mcu_org
.ptr
[0] = m_comp_list
.ptr
[0];
2432 m_blocks_per_mcu
= 1;
2436 m_blocks_per_mcu
= 0;
2438 for (component_num
= 0; component_num
< m_comps_in_scan
; component_num
++)
2442 component_id
= m_comp_list
.ptr
[component_num
];
2444 num_blocks
= m_comp_h_samp
.ptr
[component_id
] * m_comp_v_samp
.ptr
[component_id
];
2446 while (num_blocks
--)
2447 m_mcu_org
.ptr
[m_blocks_per_mcu
++] = component_id
;
2452 // Starts a new scan.
2454 if (!locate_sos_marker())
2457 calc_mcu_block_order();
2459 check_huff_tables();
2461 check_quant_tables();
2463 memset(m_last_dc_val
.ptr
, 0, m_comps_in_frame
* uint.sizeof
);
2467 if (m_restart_interval
)
2469 m_restarts_left
= m_restart_interval
;
2470 m_next_restart_num
= 0;
2478 // Starts a frame. Determines if the number of components or sampling factors
2480 void init_frame () {
2483 if (m_comps_in_frame
== 1)
2485 if ((m_comp_h_samp
.ptr
[0] != 1) ||
(m_comp_v_samp
.ptr
[0] != 1))
2486 stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS
);
2488 m_scan_type
= JPGD_GRAYSCALE
;
2489 m_max_blocks_per_mcu
= 1;
2490 m_max_mcu_x_size
= 8;
2491 m_max_mcu_y_size
= 8;
2493 else if (m_comps_in_frame
== 3)
2495 if ( ((m_comp_h_samp
.ptr
[1] != 1) ||
(m_comp_v_samp
.ptr
[1] != 1)) ||
2496 ((m_comp_h_samp
.ptr
[2] != 1) ||
(m_comp_v_samp
.ptr
[2] != 1)) )
2497 stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS
);
2499 if ((m_comp_h_samp
.ptr
[0] == 1) && (m_comp_v_samp
.ptr
[0] == 1))
2501 m_scan_type
= JPGD_YH1V1
;
2503 m_max_blocks_per_mcu
= 3;
2504 m_max_mcu_x_size
= 8;
2505 m_max_mcu_y_size
= 8;
2507 else if ((m_comp_h_samp
.ptr
[0] == 2) && (m_comp_v_samp
.ptr
[0] == 1))
2509 m_scan_type
= JPGD_YH2V1
;
2510 m_max_blocks_per_mcu
= 4;
2511 m_max_mcu_x_size
= 16;
2512 m_max_mcu_y_size
= 8;
2514 else if ((m_comp_h_samp
.ptr
[0] == 1) && (m_comp_v_samp
.ptr
[0] == 2))
2516 m_scan_type
= JPGD_YH1V2
;
2517 m_max_blocks_per_mcu
= 4;
2518 m_max_mcu_x_size
= 8;
2519 m_max_mcu_y_size
= 16;
2521 else if ((m_comp_h_samp
.ptr
[0] == 2) && (m_comp_v_samp
.ptr
[0] == 2))
2523 m_scan_type
= JPGD_YH2V2
;
2524 m_max_blocks_per_mcu
= 6;
2525 m_max_mcu_x_size
= 16;
2526 m_max_mcu_y_size
= 16;
2529 stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS
);
2532 stop_decoding(JPGD_UNSUPPORTED_COLORSPACE
);
2534 m_max_mcus_per_row
= (m_image_x_size
+ (m_max_mcu_x_size
- 1)) / m_max_mcu_x_size
;
2535 m_max_mcus_per_col
= (m_image_y_size
+ (m_max_mcu_y_size
- 1)) / m_max_mcu_y_size
;
2537 // These values are for the *destination* pixels: after conversion.
2538 if (m_scan_type
== JPGD_GRAYSCALE
)
2539 m_dest_bytes_per_pixel
= 1;
2541 m_dest_bytes_per_pixel
= 4;
2543 m_dest_bytes_per_scan_line
= ((m_image_x_size
+ 15) & 0xFFF0) * m_dest_bytes_per_pixel
;
2545 m_real_dest_bytes_per_scan_line
= (m_image_x_size
* m_dest_bytes_per_pixel
);
2547 // Initialize two scan line buffers.
2548 m_pScan_line_0
= cast(ubyte*)alloc(m_dest_bytes_per_scan_line
, true);
2549 if ((m_scan_type
== JPGD_YH1V2
) ||
(m_scan_type
== JPGD_YH2V2
))
2550 m_pScan_line_1
= cast(ubyte*)alloc(m_dest_bytes_per_scan_line
, true);
2552 m_max_blocks_per_row
= m_max_mcus_per_row
* m_max_blocks_per_mcu
;
2554 // Should never happen
2555 if (m_max_blocks_per_row
> JPGD_MAX_BLOCKS_PER_ROW
)
2556 stop_decoding(JPGD_ASSERTION_ERROR
);
2558 // Allocate the coefficient buffer, enough for one MCU
2559 m_pMCU_coefficients
= cast(jpgd_block_t
*)alloc(m_max_blocks_per_mcu
* 64 * jpgd_block_t
.sizeof
);
2561 for (i
= 0; i
< m_max_blocks_per_mcu
; i
++)
2562 m_mcu_block_max_zag
.ptr
[i
] = 64;
2564 m_expanded_blocks_per_component
= m_comp_h_samp
.ptr
[0] * m_comp_v_samp
.ptr
[0];
2565 m_expanded_blocks_per_mcu
= m_expanded_blocks_per_component
* m_comps_in_frame
;
2566 m_expanded_blocks_per_row
= m_max_mcus_per_row
* m_expanded_blocks_per_mcu
;
2567 // Freq. domain chroma upsampling is only supported for H2V2 subsampling factor (the most common one I've seen).
2568 m_freq_domain_chroma_upsample
= false;
2569 version(JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING
) {
2570 m_freq_domain_chroma_upsample
= (m_expanded_blocks_per_mcu
== 4*3);
2573 if (m_freq_domain_chroma_upsample
)
2574 m_pSample_buf
= cast(ubyte*)alloc(m_expanded_blocks_per_row
* 64);
2576 m_pSample_buf
= cast(ubyte*)alloc(m_max_blocks_per_row
* 64);
2578 m_total_lines_left
= m_image_y_size
;
2580 m_mcu_lines_left
= 0;
2585 // The coeff_buf series of methods originally stored the coefficients
2586 // into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
2587 // was used to make this process more efficient. Now, we can store the entire
2589 coeff_buf
* coeff_buf_open(int block_num_x
, int block_num_y
, int block_len_x
, int block_len_y
) {
2590 coeff_buf
* cb
= cast(coeff_buf
*)alloc(coeff_buf
.sizeof
);
2592 cb
.block_num_x
= block_num_x
;
2593 cb
.block_num_y
= block_num_y
;
2594 cb
.block_len_x
= block_len_x
;
2595 cb
.block_len_y
= block_len_y
;
2596 cb
.block_size
= (block_len_x
* block_len_y
) * jpgd_block_t
.sizeof
;
2597 cb
.pData
= cast(ubyte*)alloc(cb
.block_size
* block_num_x
* block_num_y
, true);
2601 jpgd_block_t
* coeff_buf_getp (coeff_buf
*cb
, int block_x
, int block_y
) {
2602 assert((block_x
< cb
.block_num_x
) && (block_y
< cb
.block_num_y
));
2603 return cast(jpgd_block_t
*)(cb
.pData
+ block_x
* cb
.block_size
+ block_y
* (cb
.block_size
* cb
.block_num_x
));
2606 // The following methods decode the various types of m_blocks encountered
2607 // in progressively encoded images.
2608 static void decode_block_dc_first (ref jpeg_decoder pD
, int component_id
, int block_x
, int block_y
) {
2610 jpgd_block_t
*p
= pD
.coeff_buf_getp(pD
.m_dc_coeffs
.ptr
[component_id
], block_x
, block_y
);
2612 if ((s
= pD
.huff_decode(pD
.m_pHuff_tabs
.ptr
[pD
.m_comp_dc_tab
.ptr
[component_id
]])) != 0)
2614 r
= pD
.get_bits_no_markers(s
);
2615 s
= JPGD_HUFF_EXTEND(r
, s
);
2618 pD
.m_last_dc_val
.ptr
[component_id
] = (s
+= pD
.m_last_dc_val
.ptr
[component_id
]);
2620 p
[0] = cast(jpgd_block_t
)(s
<< pD
.m_successive_low
);
2623 static void decode_block_dc_refine (ref jpeg_decoder pD
, int component_id
, int block_x
, int block_y
) {
2624 if (pD
.get_bits_no_markers(1))
2626 jpgd_block_t
*p
= pD
.coeff_buf_getp(pD
.m_dc_coeffs
.ptr
[component_id
], block_x
, block_y
);
2628 p
[0] |
= (1 << pD
.m_successive_low
);
2632 static void decode_block_ac_first (ref jpeg_decoder pD
, int component_id
, int block_x
, int block_y
) {
2641 jpgd_block_t
*p
= pD
.coeff_buf_getp(pD
.m_ac_coeffs
.ptr
[component_id
], block_x
, block_y
);
2643 for (k
= pD
.m_spectral_start
; k
<= pD
.m_spectral_end
; k
++)
2645 s
= pD
.huff_decode(pD
.m_pHuff_tabs
.ptr
[pD
.m_comp_ac_tab
.ptr
[component_id
]]);
2653 pD
.stop_decoding(JPGD_DECODE_ERROR
);
2655 r
= pD
.get_bits_no_markers(s
);
2656 s
= JPGD_HUFF_EXTEND(r
, s
);
2658 p
[g_ZAG
[k
]] = cast(jpgd_block_t
)(s
<< pD
.m_successive_low
);
2665 pD
.stop_decoding(JPGD_DECODE_ERROR
);
2669 pD
.m_eob_run
= 1 << r
;
2672 pD
.m_eob_run
+= pD
.get_bits_no_markers(r
);
2682 static void decode_block_ac_refine (ref jpeg_decoder pD
, int component_id
, int block_x
, int block_y
) {
2684 int p1
= 1 << pD
.m_successive_low
;
2685 int m1
= (-1) << pD
.m_successive_low
;
2686 jpgd_block_t
*p
= pD
.coeff_buf_getp(pD
.m_ac_coeffs
.ptr
[component_id
], block_x
, block_y
);
2688 assert(pD
.m_spectral_end
<= 63);
2690 k
= pD
.m_spectral_start
;
2692 if (pD
.m_eob_run
== 0)
2694 for ( ; k
<= pD
.m_spectral_end
; k
++)
2696 s
= pD
.huff_decode(pD
.m_pHuff_tabs
.ptr
[pD
.m_comp_ac_tab
.ptr
[component_id
]]);
2704 pD
.stop_decoding(JPGD_DECODE_ERROR
);
2706 if (pD
.get_bits_no_markers(1))
2715 pD
.m_eob_run
= 1 << r
;
2718 pD
.m_eob_run
+= pD
.get_bits_no_markers(r
);
2726 jpgd_block_t
*this_coef
= p
+ g_ZAG
[k
& 63];
2728 if (*this_coef
!= 0)
2730 if (pD
.get_bits_no_markers(1))
2732 if ((*this_coef
& p1
) == 0)
2734 if (*this_coef
>= 0)
2735 *this_coef
= cast(jpgd_block_t
)(*this_coef
+ p1
);
2737 *this_coef
= cast(jpgd_block_t
)(*this_coef
+ m1
);
2749 } while (k
<= pD
.m_spectral_end
);
2751 if ((s
) && (k
< 64))
2753 p
[g_ZAG
[k
]] = cast(jpgd_block_t
)(s
);
2758 if (pD
.m_eob_run
> 0)
2760 for ( ; k
<= pD
.m_spectral_end
; k
++)
2762 jpgd_block_t
*this_coef
= p
+ g_ZAG
[k
& 63]; // logical AND to shut up static code analysis
2764 if (*this_coef
!= 0)
2766 if (pD
.get_bits_no_markers(1))
2768 if ((*this_coef
& p1
) == 0)
2770 if (*this_coef
>= 0)
2771 *this_coef
= cast(jpgd_block_t
)(*this_coef
+ p1
);
2773 *this_coef
= cast(jpgd_block_t
)(*this_coef
+ m1
);
2783 // Decode a scan in a progressively encoded image.
2784 void decode_scan (pDecode_block_func decode_block_func
) {
2785 int mcu_row
, mcu_col
, mcu_block
;
2786 int[JPGD_MAX_COMPONENTS
] block_x_mcu
;
2787 int[JPGD_MAX_COMPONENTS
] m_block_y_mcu
;
2789 memset(m_block_y_mcu
.ptr
, 0, m_block_y_mcu
.sizeof
);
2791 for (mcu_col
= 0; mcu_col
< m_mcus_per_col
; mcu_col
++)
2793 int component_num
, component_id
;
2795 memset(block_x_mcu
.ptr
, 0, block_x_mcu
.sizeof
);
2797 for (mcu_row
= 0; mcu_row
< m_mcus_per_row
; mcu_row
++)
2799 int block_x_mcu_ofs
= 0, block_y_mcu_ofs
= 0;
2801 if ((m_restart_interval
) && (m_restarts_left
== 0))
2804 for (mcu_block
= 0; mcu_block
< m_blocks_per_mcu
; mcu_block
++)
2806 component_id
= m_mcu_org
.ptr
[mcu_block
];
2808 decode_block_func(this, component_id
, block_x_mcu
.ptr
[component_id
] + block_x_mcu_ofs
, m_block_y_mcu
.ptr
[component_id
] + block_y_mcu_ofs
);
2810 if (m_comps_in_scan
== 1)
2811 block_x_mcu
.ptr
[component_id
]++;
2814 if (++block_x_mcu_ofs
== m_comp_h_samp
.ptr
[component_id
])
2816 block_x_mcu_ofs
= 0;
2818 if (++block_y_mcu_ofs
== m_comp_v_samp
.ptr
[component_id
])
2820 block_y_mcu_ofs
= 0;
2821 block_x_mcu
.ptr
[component_id
] += m_comp_h_samp
.ptr
[component_id
];
2830 if (m_comps_in_scan
== 1)
2831 m_block_y_mcu
.ptr
[m_comp_list
.ptr
[0]]++;
2834 for (component_num
= 0; component_num
< m_comps_in_scan
; component_num
++)
2836 component_id
= m_comp_list
.ptr
[component_num
];
2837 m_block_y_mcu
.ptr
[component_id
] += m_comp_v_samp
.ptr
[component_id
];
2843 // Decode a progressively encoded image.
2844 void init_progressive () {
2847 if (m_comps_in_frame
== 4)
2848 stop_decoding(JPGD_UNSUPPORTED_COLORSPACE
);
2850 // Allocate the coefficient buffers.
2851 for (i
= 0; i
< m_comps_in_frame
; i
++)
2853 m_dc_coeffs
.ptr
[i
] = coeff_buf_open(m_max_mcus_per_row
* m_comp_h_samp
.ptr
[i
], m_max_mcus_per_col
* m_comp_v_samp
.ptr
[i
], 1, 1);
2854 m_ac_coeffs
.ptr
[i
] = coeff_buf_open(m_max_mcus_per_row
* m_comp_h_samp
.ptr
[i
], m_max_mcus_per_col
* m_comp_v_samp
.ptr
[i
], 8, 8);
2859 int dc_only_scan
, refinement_scan
;
2860 pDecode_block_func decode_block_func
;
2865 dc_only_scan
= (m_spectral_start
== 0);
2866 refinement_scan
= (m_successive_high
!= 0);
2868 if ((m_spectral_start
> m_spectral_end
) ||
(m_spectral_end
> 63))
2869 stop_decoding(JPGD_BAD_SOS_SPECTRAL
);
2874 stop_decoding(JPGD_BAD_SOS_SPECTRAL
);
2876 else if (m_comps_in_scan
!= 1) /* AC scans can only contain one component */
2877 stop_decoding(JPGD_BAD_SOS_SPECTRAL
);
2879 if ((refinement_scan
) && (m_successive_low
!= m_successive_high
- 1))
2880 stop_decoding(JPGD_BAD_SOS_SUCCESSIVE
);
2884 if (refinement_scan
)
2885 decode_block_func
= &decode_block_dc_refine
;
2887 decode_block_func
= &decode_block_dc_first
;
2891 if (refinement_scan
)
2892 decode_block_func
= &decode_block_ac_refine
;
2894 decode_block_func
= &decode_block_ac_first
;
2897 decode_scan(decode_block_func
);
2904 m_comps_in_scan
= m_comps_in_frame
;
2906 for (i
= 0; i
< m_comps_in_frame
; i
++)
2907 m_comp_list
.ptr
[i
] = i
;
2909 calc_mcu_block_order();
2912 void init_sequential () {
2914 stop_decoding(JPGD_UNEXPECTED_MARKER
);
2917 void decode_start () {
2920 if (m_progressive_flag
)
2926 void decode_init (JpegStreamReadFunc rfn
) {
2928 locate_sof_marker();
2933 // ////////////////////////////////////////////////////////////////////////// //
2934 /// read JPEG image header, determine dimensions and number of components.
2935 /// return `false` if image is not JPEG (i hope).
2936 public bool detect_jpeg_image_from_stream (scope JpegStreamReadFunc rfn
, out int width
, out int height
, out int actual_comps
) {
2937 if (rfn
is null) return false;
2938 auto decoder
= jpeg_decoder(rfn
);
2939 version(jpegd_test
) { import core
.stdc
.stdio
: printf
; printf("%u bytes read.\n", cast(uint)decoder
.total_bytes_read
); }
2940 if (decoder
.error_code
!= JPGD_SUCCESS
) return false;
2941 width
= decoder
.width
;
2942 height
= decoder
.height
;
2943 actual_comps
= decoder
.num_components
;
2948 // ////////////////////////////////////////////////////////////////////////// //
2949 /// read JPEG image header, determine dimensions and number of components.
2950 /// return `false` if image is not JPEG (i hope).
2951 public bool detect_jpeg_image_from_file (const(char)[] filename
, out int width
, out int height
, out int actual_comps
) {
2952 import core
.stdc
.stdio
;
2955 bool m_eof_flag
, m_error_flag
;
2957 if (filename
.length
== 0) throw new Exception("cannot open unnamed file");
2958 if (filename
.length
< 2048) {
2959 import core
.stdc
.stdlib
: alloca
;
2960 auto tfn
= (cast(char*)alloca(filename
.length
+1))[0..filename
.length
+1];
2961 tfn
[0..filename
.length
] = filename
[];
2962 tfn
[filename
.length
] = 0;
2963 m_pFile
= fopen(tfn
.ptr
, "rb");
2965 import core
.stdc
.stdlib
: malloc
, free
;
2966 auto tfn
= (cast(char*)malloc(filename
.length
+1))[0..filename
.length
+1];
2968 scope(exit
) free(tfn
.ptr
);
2969 m_pFile
= fopen(tfn
.ptr
, "rb");
2972 if (m_pFile
is null) throw new Exception("cannot open file '"~filename
.idup
~"'");
2973 scope(exit
) if (m_pFile
) fclose(m_pFile
);
2975 return detect_jpeg_image_from_stream(
2976 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
2977 if (m_pFile
is null) return -1;
2982 if (m_error_flag
) return -1;
2983 int bytes_read
= cast(int)(fread(pBuf
, 1, max_bytes_to_read
, m_pFile
));
2984 if (bytes_read
< max_bytes_to_read
) {
2985 if (ferror(m_pFile
)) {
2986 m_error_flag
= true;
2994 width
, height
, actual_comps
);
2998 // ////////////////////////////////////////////////////////////////////////// //
2999 /// read JPEG image header, determine dimensions and number of components.
3000 /// return `false` if image is not JPEG (i hope).
3001 public bool detect_jpeg_image_from_memory (const(void)[] buf
, out int width
, out int height
, out int actual_comps
) {
3004 auto b
= cast(const(ubyte)*)buf
.ptr
;
3006 return detect_jpeg_image_from_stream(
3007 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3008 import core
.stdc
.string
: memcpy
;
3009 if (bufpos
>= buf
.length
) {
3013 if (buf
.length
-bufpos
< max_bytes_to_read
) max_bytes_to_read
= cast(int)(buf
.length
-bufpos
);
3014 memcpy(pBuf
, b
, max_bytes_to_read
);
3015 b
+= max_bytes_to_read
;
3016 return max_bytes_to_read
;
3018 width
, height
, actual_comps
);
3022 // ////////////////////////////////////////////////////////////////////////// //
3023 /// decompress JPEG image, what else?
3024 /// 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.
3025 public ubyte[] decompress_jpeg_image_from_stream(bool useMalloc
=false) (scope JpegStreamReadFunc rfn
, out int width
, out int height
, out int actual_comps
, int req_comps
=-1) {
3026 import core
.stdc
.string
: memcpy
;
3029 if (rfn
is null) return null;
3030 if (req_comps
!= -1 && req_comps
!= 1 && req_comps
!= 3 && req_comps
!= 4) return null;
3032 auto decoder
= jpeg_decoder(rfn
);
3033 if (decoder
.error_code
!= JPGD_SUCCESS
) return null;
3034 version(jpegd_test
) scope(exit
) { import core
.stdc
.stdio
: printf
; printf("%u bytes read.\n", cast(uint)decoder
.total_bytes_read
); }
3036 immutable int image_width
= decoder
.width
;
3037 immutable int image_height
= decoder
.height
;
3038 width
= image_width
;
3039 height
= image_height
;
3040 actual_comps
= decoder
.num_components
;
3041 if (req_comps
< 0) req_comps
= decoder
.num_components
;
3043 if (decoder
.begin_decoding() != JPGD_SUCCESS
) return null;
3045 immutable int dst_bpl
= image_width
*req_comps
;
3047 static if (useMalloc
) {
3048 ubyte* pImage_data
= cast(ubyte*)jpgd_malloc(dst_bpl
*image_height
);
3049 if (pImage_data
is null) return null;
3050 auto idata
= pImage_data
[0..dst_bpl
*image_height
];
3052 auto idata
= new ubyte[](dst_bpl
*image_height
);
3053 auto pImage_data
= idata
.ptr
;
3056 for (int y
= 0; y
< image_height
; ++y
) {
3057 const(ubyte)* pScan_line
;
3059 if (decoder
.decode(/*(const void**)*/cast(void**)&pScan_line
, &scan_line_len
) != JPGD_SUCCESS
) {
3060 jpgd_free(pImage_data
);
3064 ubyte* pDst
= pImage_data
+y
*dst_bpl
;
3066 if ((req_comps
== 1 && decoder
.num_components
== 1) ||
(req_comps
== 4 && decoder
.num_components
== 3)) {
3067 memcpy(pDst
, pScan_line
, dst_bpl
);
3068 } else if (decoder
.num_components
== 1) {
3069 if (req_comps
== 3) {
3070 for (int x
= 0; x
< image_width
; ++x
) {
3071 ubyte luma
= pScan_line
[x
];
3078 for (int x
= 0; x
< image_width
; ++x
) {
3079 ubyte luma
= pScan_line
[x
];
3087 } else if (decoder
.num_components
== 3) {
3088 if (req_comps
== 1) {
3089 immutable int YR
= 19595, YG
= 38470, YB
= 7471;
3090 for (int x
= 0; x
< image_width
; ++x
) {
3091 int r
= pScan_line
[x
*4+0];
3092 int g
= pScan_line
[x
*4+1];
3093 int b
= pScan_line
[x
*4+2];
3094 *pDst
++ = cast(ubyte)((r
* YR
+ g
* YG
+ b
* YB
+ 32768) >> 16);
3097 for (int x
= 0; x
< image_width
; ++x
) {
3098 pDst
[0] = pScan_line
[x
*4+0];
3099 pDst
[1] = pScan_line
[x
*4+1];
3100 pDst
[2] = pScan_line
[x
*4+2];
3111 // ////////////////////////////////////////////////////////////////////////// //
3112 /// decompress JPEG image from disk file.
3113 /// 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.
3114 public ubyte[] decompress_jpeg_image_from_file(bool useMalloc
=false) (const(char)[] filename
, out int width
, out int height
, out int actual_comps
, int req_comps
=-1) {
3115 import core
.stdc
.stdio
;
3118 bool m_eof_flag
, m_error_flag
;
3120 if (filename
.length
== 0) throw new Exception("cannot open unnamed file");
3121 if (filename
.length
< 2048) {
3122 import core
.stdc
.stdlib
: alloca
;
3123 auto tfn
= (cast(char*)alloca(filename
.length
+1))[0..filename
.length
+1];
3124 tfn
[0..filename
.length
] = filename
[];
3125 tfn
[filename
.length
] = 0;
3126 m_pFile
= fopen(tfn
.ptr
, "rb");
3128 import core
.stdc
.stdlib
: malloc
, free
;
3129 auto tfn
= (cast(char*)malloc(filename
.length
+1))[0..filename
.length
+1];
3131 scope(exit
) free(tfn
.ptr
);
3132 m_pFile
= fopen(tfn
.ptr
, "rb");
3135 if (m_pFile
is null) throw new Exception("cannot open file '"~filename
.idup
~"'");
3136 scope(exit
) if (m_pFile
) fclose(m_pFile
);
3138 return decompress_jpeg_image_from_stream
!useMalloc(
3139 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3140 if (m_pFile
is null) return -1;
3145 if (m_error_flag
) return -1;
3146 int bytes_read
= cast(int)(fread(pBuf
, 1, max_bytes_to_read
, m_pFile
));
3147 if (bytes_read
< max_bytes_to_read
) {
3148 if (ferror(m_pFile
)) {
3149 m_error_flag
= true;
3157 width
, height
, actual_comps
, req_comps
);
3161 // ////////////////////////////////////////////////////////////////////////// //
3162 /// decompress JPEG image from memory buffer.
3163 /// 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.
3164 public ubyte[] decompress_jpeg_image_from_memory(bool useMalloc
=false) (const(void)[] buf
, out int width
, out int height
, out int actual_comps
, int req_comps
=-1) {
3167 auto b
= cast(const(ubyte)*)buf
.ptr
;
3169 return decompress_jpeg_image_from_stream
!useMalloc(
3170 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3171 import core
.stdc
.string
: memcpy
;
3172 if (bufpos
>= buf
.length
) {
3176 if (buf
.length
-bufpos
< max_bytes_to_read
) max_bytes_to_read
= cast(int)(buf
.length
-bufpos
);
3177 memcpy(pBuf
, b
, max_bytes_to_read
);
3178 b
+= max_bytes_to_read
;
3179 return max_bytes_to_read
;
3181 width
, height
, actual_comps
, req_comps
);
3185 // ////////////////////////////////////////////////////////////////////////// //
3186 // if we have access "iv.vfs", add some handy API
3187 static if (__traits(compiles
, { import iv
.vfs
; })) enum JpegHasIVVFS
= true; else enum JpegHasIVVFS
= false;
3189 static if (JpegHasIVVFS
) {
3192 // ////////////////////////////////////////////////////////////////////////// //
3193 /// decompress JPEG image from disk file.
3194 /// 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.
3195 public ubyte[] decompress_jpeg_image_from_file(bool useMalloc
=false) (VFile fl
, out int width
, out int height
, out int actual_comps
, int req_comps
=-1) {
3196 return decompress_jpeg_image_from_stream
!useMalloc(
3197 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3198 if (!fl
.isOpen
) return -1;
3203 auto rd
= fl
.rawRead(pBuf
[0..max_bytes_to_read
]);
3204 if (fl
.eof
) *pEOF_flag
= true;
3205 return cast(int)rd
.length
;
3207 width
, height
, actual_comps
, req_comps
);
3213 // ////////////////////////////////////////////////////////////////////////// //
3214 // if we have access "arsd.color", add some handy API
3215 static if (__traits(compiles
, { import arsd
.color
; })) enum JpegHasArsd
= true; else enum JpegHasArsd
= false;
3217 static if (JpegHasArsd
) {
3220 // ////////////////////////////////////////////////////////////////////////// //
3221 /// decompress JPEG image, what else?
3222 public MemoryImage
readJpegFromStream (scope JpegStreamReadFunc rfn
) {
3223 import core
.stdc
.string
: memcpy
;
3226 if (rfn
is null) return null;
3228 auto decoder
= jpeg_decoder(rfn
);
3229 if (decoder
.error_code
!= JPGD_SUCCESS
) return null;
3230 version(jpegd_test
) scope(exit
) { import core
.stdc
.stdio
: printf
; printf("%u bytes read.\n", cast(uint)decoder
.total_bytes_read
); }
3232 immutable int image_width
= decoder
.width
;
3233 immutable int image_height
= decoder
.height
;
3234 //width = image_width;
3235 //height = image_height;
3236 //actual_comps = decoder.num_components;
3238 if (decoder
.begin_decoding() != JPGD_SUCCESS || image_width
< 1 || image_height
< 1) return null;
3240 immutable int dst_bpl
= image_width
*req_comps
;
3241 auto img
= new TrueColorImage(image_width
, image_height
);
3242 ubyte* pImage_data
= img
.imageData
.bytes
.ptr
;
3244 for (int y
= 0; y
< image_height
; ++y
) {
3245 const(ubyte)* pScan_line
;
3247 if (decoder
.decode(/*(const void**)*/cast(void**)&pScan_line
, &scan_line_len
) != JPGD_SUCCESS
) {
3248 jpgd_free(pImage_data
);
3252 ubyte* pDst
= pImage_data
+y
*dst_bpl
;
3254 if ((req_comps
== 1 && decoder
.num_components
== 1) ||
(req_comps
== 4 && decoder
.num_components
== 3)) {
3255 memcpy(pDst
, pScan_line
, dst_bpl
);
3256 } else if (decoder
.num_components
== 1) {
3257 if (req_comps
== 3) {
3258 for (int x
= 0; x
< image_width
; ++x
) {
3259 ubyte luma
= pScan_line
[x
];
3266 for (int x
= 0; x
< image_width
; ++x
) {
3267 ubyte luma
= pScan_line
[x
];
3275 } else if (decoder
.num_components
== 3) {
3276 if (req_comps
== 1) {
3277 immutable int YR
= 19595, YG
= 38470, YB
= 7471;
3278 for (int x
= 0; x
< image_width
; ++x
) {
3279 int r
= pScan_line
[x
*4+0];
3280 int g
= pScan_line
[x
*4+1];
3281 int b
= pScan_line
[x
*4+2];
3282 *pDst
++ = cast(ubyte)((r
* YR
+ g
* YG
+ b
* YB
+ 32768) >> 16);
3285 for (int x
= 0; x
< image_width
; ++x
) {
3286 pDst
[0] = pScan_line
[x
*4+0];
3287 pDst
[1] = pScan_line
[x
*4+1];
3288 pDst
[2] = pScan_line
[x
*4+2];
3299 // ////////////////////////////////////////////////////////////////////////// //
3300 /// decompress JPEG image from disk file.
3301 public MemoryImage
readJpeg (const(char)[] filename
) {
3302 import core
.stdc
.stdio
;
3305 bool m_eof_flag
, m_error_flag
;
3307 if (filename
.length
== 0) throw new Exception("cannot open unnamed file");
3308 if (filename
.length
< 2048) {
3309 import core
.stdc
.stdlib
: alloca
;
3310 auto tfn
= (cast(char*)alloca(filename
.length
+1))[0..filename
.length
+1];
3311 tfn
[0..filename
.length
] = filename
[];
3312 tfn
[filename
.length
] = 0;
3313 m_pFile
= fopen(tfn
.ptr
, "rb");
3315 import core
.stdc
.stdlib
: malloc
, free
;
3316 auto tfn
= (cast(char*)malloc(filename
.length
+1))[0..filename
.length
+1];
3318 scope(exit
) free(tfn
.ptr
);
3319 m_pFile
= fopen(tfn
.ptr
, "rb");
3322 if (m_pFile
is null) throw new Exception("cannot open file '"~filename
.idup
~"'");
3323 scope(exit
) if (m_pFile
) fclose(m_pFile
);
3325 return readJpegFromStream(
3326 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3327 if (m_pFile
is null) return -1;
3332 if (m_error_flag
) return -1;
3333 int bytes_read
= cast(int)(fread(pBuf
, 1, max_bytes_to_read
, m_pFile
));
3334 if (bytes_read
< max_bytes_to_read
) {
3335 if (ferror(m_pFile
)) {
3336 m_error_flag
= true;
3348 // ////////////////////////////////////////////////////////////////////////// //
3349 /// decompress JPEG image from memory buffer.
3350 public MemoryImage
readJpegFromMemory (const(void)[] buf
) {
3353 auto b
= cast(const(ubyte)*)buf
.ptr
;
3355 return readJpegFromStream(
3356 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3357 import core
.stdc
.string
: memcpy
;
3358 if (bufpos
>= buf
.length
) {
3362 if (buf
.length
-bufpos
< max_bytes_to_read
) max_bytes_to_read
= cast(int)(buf
.length
-bufpos
);
3363 memcpy(pBuf
, b
, max_bytes_to_read
);
3364 b
+= max_bytes_to_read
;
3365 return max_bytes_to_read
;
3369 // done with arsd API
3373 static if (JpegHasIVVFS
) {
3374 public MemoryImage
readJpeg (VFile fl
) {
3375 return readJpegFromStream(
3376 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3377 if (!fl
.isOpen
) return -1;
3382 auto rd
= fl
.rawRead(pBuf
[0..max_bytes_to_read
]);
3383 if (fl
.eof
) *pEOF_flag
= true;
3384 return cast(int)rd
.length
;
3389 public bool detectJpeg (VFile fl
, out int width
, out int height
, out int actual_comps
) {
3390 return detect_jpeg_image_from_stream(
3391 delegate int (void* pBuf
, int max_bytes_to_read
, bool *pEOF_flag
) {
3392 if (!fl
.isOpen
) return -1;
3397 auto rd
= fl
.rawRead(pBuf
[0..max_bytes_to_read
]);
3398 if (fl
.eof
) *pEOF_flag
= true;
3399 return cast(int)rd
.length
;
3401 width
, height
, actual_comps
);
3407 // ////////////////////////////////////////////////////////////////////////// //
3408 version(jpegd_test
) {
3412 void main (string
[] args
) {
3414 int width
, height
, comps
;
3416 assert(detect_jpeg_image_from_file((args
.length
> 1 ? args
[1] : "image.jpg"), width
, height
, comps
));
3417 writeln(width
, "x", height
, "x", comps
);
3418 auto img
= readJpeg((args
.length
> 1 ? args
[1] : "image.jpg"));
3419 writeln(img
.width
, "x", img
.height
);
3420 writePng("z00.png", img
);
3425 auto fl
= File(args
.length
> 1 ? args
[1] : "image.jpg");
3426 file
.length
= cast(int)fl
.size
;
3429 assert(detect_jpeg_image_from_memory(file
[], width
, height
, comps
));
3430 writeln(width
, "x", height
, "x", comps
);
3431 auto img
= readJpegFromMemory(file
[]);
3432 writeln(img
.width
, "x", img
.height
);
3433 writePng("z01.png", img
);