1 // jpge.cpp - C++ class for JPEG compression.
2 // Public domain, Rich Geldreich <richgel99@gmail.com>
3 // Alex Evans: Added RGBA support, linear memory allocator.
4 // v1.01, Dec. 18, 2010 - Initial release
5 // v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.)
6 // v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc.
7 // Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03).
8 // v1.04, May. 19, 2012: Forgot to set m_pFile ptr to null in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug.
9 // Code tweaks to fix VS2008 static code analysis warnings (all looked harmless).
10 // Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02.
11 // D translation by Ketmar // Invisible Vector
13 // This is free and unencumbered software released into the public domain.
15 // Anyone is free to copy, modify, publish, use, compile, sell, or
16 // distribute this software, either in source code form or as a compiled
17 // binary, for any purpose, commercial or non-commercial, and by any
20 // In jurisdictions that recognize copyright laws, the author or authors
21 // of this software dedicate any and all copyright interest in the
22 // software to the public domain. We make this dedication for the benefit
23 // of the public at large and to the detriment of our heirs and
24 // successors. We intend this dedication to be an overt act of
25 // relinquishment in perpetuity of all present and future rights to this
26 // software under copyright law.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
31 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
32 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
33 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34 // OTHER DEALINGS IN THE SOFTWARE.
36 // For more information, please refer to <http://unlicense.org/>
38 * Writes a JPEG image to a file or stream.
39 * num_channels must be 1 (Y), 3 (RGB), 4 (RGBA), image pitch must be width*num_channels.
40 * note that alpha will not be stored in jpeg file.
42 module iv
.jpege
/*is aliced*/;
47 // ////////////////////////////////////////////////////////////////////////// //
48 // JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
49 enum JpegSubsampling
{ Y_ONLY
= 0, H1V1
= 1, H2V1
= 2, H2V2
= 3 }
51 // JPEG compression parameters structure.
52 public struct JpegParams
{
53 // Quality: 1-100, higher is better. Typical values are around 50-95.
57 // 0 = Y (grayscale) only
58 // 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU)
59 // 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
60 // 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
61 JpegSubsampling subsampling
= JpegSubsampling
.H2V2
;
63 // Disables CbCr discrimination - only intended for testing.
64 // If true, the Y quantization table is also used for the CbCr channels.
65 bool noChromaDiscrimFlag
= false;
69 bool check () const pure nothrow @safe @nogc {
70 if (quality
< 1 || quality
> 100) return false;
71 if (cast(uint)subsampling
> cast(uint)JpegSubsampling
.H2V2
) return false;
77 // ////////////////////////////////////////////////////////////////////////// //
78 /// Writes JPEG image to file.
79 /// num_channels must be 1 (Y), 3 (RGB), 4 (RGBA), image pitch must be width*num_channels.
80 /// note that alpha will not be stored in jpeg file.
81 bool compress_image_to_jpeg_stream() (scope jpeg_encoder
.WriteFunc wfn
, int width
, int height
, int num_channels
, const(ubyte)[] pImage_data
) { return compress_image_to_jpeg_stream(wfn
, width
, height
, num_channels
, pImage_data
, JpegParams()); }
83 /// Writes JPEG image to file.
84 /// num_channels must be 1 (Y), 3 (RGB), 4 (RGBA), image pitch must be width*num_channels.
85 /// note that alpha will not be stored in jpeg file.
86 bool compress_image_to_jpeg_stream() (scope jpeg_encoder
.WriteFunc wfn
, int width
, int height
, int num_channels
, const(ubyte)[] pImage_data
, in auto ref JpegParams comp_params
) {
87 jpeg_encoder dst_image
;
88 if (!dst_image
.setup(wfn
, width
, height
, num_channels
, comp_params
)) return false;
89 for (uint pass_index
= 0; pass_index
< dst_image
.total_passes(); pass_index
++) {
90 for (int i
= 0; i
< height
; i
++) {
91 const(ubyte)* pBuf
= pImage_data
.ptr
+i
*width
*num_channels
;
92 if (!dst_image
.process_scanline(pBuf
)) return false;
94 if (!dst_image
.process_scanline(null)) return false;
97 //return dst_stream.close();
102 /// Writes JPEG image to file.
103 /// num_channels must be 1 (Y), 3 (RGB), 4 (RGBA), image pitch must be width*num_channels.
104 /// note that alpha will not be stored in jpeg file.
105 bool compress_image_to_jpeg_file (const(char)[] fname
, int width
, int height
, int num_channels
, const(ubyte)[] pImage_data
) { return compress_image_to_jpeg_file(fname
, width
, height
, num_channels
, pImage_data
, JpegParams()); }
107 /// Writes JPEG image to file.
108 /// num_channels must be 1 (Y), 3 (RGB), 4 (RGBA), image pitch must be width*num_channels.
109 /// note that alpha will not be stored in jpeg file.
110 bool compress_image_to_jpeg_file() (const(char)[] fname
, int width
, int height
, int num_channels
, const(ubyte)[] pImage_data
, in auto ref JpegParams comp_params
) {
111 import std
.internal
.cstring
;
112 import core
.stdc
.stdio
: FILE
, fopen
, fclose
, fwrite
;
113 FILE
* fl
= fopen(fname
.tempCString
, "wb");
114 if (fl
is null) return false;
115 scope(exit
) if (fl
!is null) fclose(fl
);
116 auto res
= compress_image_to_jpeg_stream(
117 delegate bool (const(void)[] buf
) {
118 if (fwrite(buf
.ptr
, 1, buf
.length
, fl
) != buf
.length
) return false;
120 }, width
, height
, num_channels
, pImage_data
, comp_params
);
122 if (fclose(fl
) != 0) res
= false;
129 // ////////////////////////////////////////////////////////////////////////// //
131 nothrow @trusted @nogc {
132 auto JPGE_MIN(T
) (T a
, T b
) pure nothrow @safe @nogc { pragma(inline
, true); return (a
< b ? a
: b
); }
133 auto JPGE_MAX(T
) (T a
, T b
) pure nothrow @safe @nogc { pragma(inline
, true); return (a
> b ? a
: b
); }
135 void *jpge_malloc (usize nSize
) { import core
.stdc
.stdlib
: malloc
; return malloc(nSize
); }
136 void jpge_free (void *p
) { import core
.stdc
.stdlib
: free
; if (p
!is null) free(p
); }
139 // Various JPEG enums and tables.
140 enum { M_SOF0
= 0xC0, M_DHT
= 0xC4, M_SOI
= 0xD8, M_EOI
= 0xD9, M_SOS
= 0xDA, M_DQT
= 0xDB, M_APP0
= 0xE0 }
141 enum { DC_LUM_CODES
= 12, AC_LUM_CODES
= 256, DC_CHROMA_CODES
= 12, AC_CHROMA_CODES
= 256, MAX_HUFF_SYMBOLS
= 257, MAX_HUFF_CODESIZE
= 32 }
143 static immutable ubyte[64] s_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 ];
144 static immutable short[64] s_std_lum_quant
= [ 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 ];
145 static immutable short[64] s_std_croma_quant
= [ 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 ];
146 static immutable ubyte[17] s_dc_lum_bits
= [ 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 ];
147 static immutable ubyte[DC_LUM_CODES
] s_dc_lum_val
= [ 0,1,2,3,4,5,6,7,8,9,10,11 ];
148 static immutable ubyte[17] s_ac_lum_bits
= [ 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d ];
149 static immutable ubyte[AC_LUM_CODES
] s_ac_lum_val
= [
150 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
151 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
152 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
153 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
154 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
157 static immutable ubyte[17] s_dc_chroma_bits
= [ 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 ];
158 static immutable ubyte[DC_CHROMA_CODES
] s_dc_chroma_val
= [ 0,1,2,3,4,5,6,7,8,9,10,11 ];
159 static immutable ubyte[17] s_ac_chroma_bits
= [ 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 ];
160 static immutable ubyte[AC_CHROMA_CODES
] s_ac_chroma_val
= [
161 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
162 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
163 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
164 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
165 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
169 // Low-level helper functions.
170 //template <class T> inline void clear_obj(T &obj) { memset(&obj, 0, sizeof(obj)); }
172 enum YR
= 19595, YG
= 38470, YB
= 7471, CB_R
= -11059, CB_G
= -21709, CB_B
= 32768, CR_R
= 32768, CR_G
= -27439, CR_B
= -5329; // int
173 //ubyte clamp (int i) { if (cast(uint)(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return cast(ubyte)(i); }
174 ubyte clamp() (int i
) { pragma(inline
, true); return cast(ubyte)(cast(uint)i
> 255 ?
(((~i
)>>31)&0xFF) : i
); }
176 void RGB_to_YCC (ubyte* pDst
, const(ubyte)* pSrc
, int num_pixels
) {
177 for (; num_pixels
; pDst
+= 3, pSrc
+= 3, --num_pixels
) {
178 immutable int r
= pSrc
[0], g
= pSrc
[1], b
= pSrc
[2];
179 pDst
[0] = cast(ubyte)((r
*YR
+g
*YG
+b
*YB
+32768)>>16);
180 pDst
[1] = clamp(128+((r
*CB_R
+g
*CB_G
+b
*CB_B
+32768)>>16));
181 pDst
[2] = clamp(128+((r
*CR_R
+g
*CR_G
+b
*CR_B
+32768)>>16));
185 void RGB_to_Y (ubyte* pDst
, const(ubyte)* pSrc
, int num_pixels
) {
186 for (; num_pixels
; ++pDst
, pSrc
+= 3, --num_pixels
) {
187 pDst
[0] = cast(ubyte)((pSrc
[0]*YR
+pSrc
[1]*YG
+pSrc
[2]*YB
+32768)>>16);
191 void RGBA_to_YCC (ubyte* pDst
, const(ubyte)* pSrc
, int num_pixels
) {
192 for (; num_pixels
; pDst
+= 3, pSrc
+= 4, --num_pixels
) {
193 immutable int r
= pSrc
[0], g
= pSrc
[1], b
= pSrc
[2];
194 pDst
[0] = cast(ubyte)((r
*YR
+g
*YG
+b
*YB
+32768)>>16);
195 pDst
[1] = clamp(128+((r
*CB_R
+g
*CB_G
+b
*CB_B
+32768)>>16));
196 pDst
[2] = clamp(128+((r
*CR_R
+g
*CR_G
+b
*CR_B
+32768)>>16));
200 void RGBA_to_Y (ubyte* pDst
, const(ubyte)* pSrc
, int num_pixels
) {
201 for (; num_pixels
; ++pDst
, pSrc
+= 4, --num_pixels
) {
202 pDst
[0] = cast(ubyte)((pSrc
[0]*YR
+pSrc
[1]*YG
+pSrc
[2]*YB
+32768)>>16);
206 void Y_to_YCC (ubyte* pDst
, const(ubyte)* pSrc
, int num_pixels
) {
207 for (; num_pixels
; pDst
+= 3, ++pSrc
, --num_pixels
) { pDst
[0] = pSrc
[0]; pDst
[1] = 128; pDst
[2] = 128; }
210 // Forward DCT - DCT derived from jfdctint.
211 enum { CONST_BITS
= 13, ROW_BITS
= 2 }
212 //#define DCT_DESCALE(x, n) (((x)+(((int)1)<<((n)-1)))>>(n))
213 int DCT_DESCALE() (int x
, int n
) { pragma(inline
, true); return (((x
)+((cast(int)1)<<((n
)-1)))>>(n
)); }
214 //#define DCT_MUL(var, c) (cast(short)(var)*cast(int)(c))
216 //#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7)
218 int t0
= s0
+s7
, t7
= s0
-s7
, t1
= s1
+s6
, t6
= s1
-s6
, t2
= s2
+s5
, t5
= s2
-s5
, t3
= s3
+s4
, t4
= s3
-s4
;
219 int t10
= t0
+t3
, t13
= t0
-t3
, t11
= t1
+t2
, t12
= t1
-t2
;
220 int u1
= (cast(short)(t12
+t13
)*cast(int)(4433));
221 s2
= u1
+(cast(short)(t13
)*cast(int)(6270));
222 s6
= u1
+(cast(short)(t12
)*cast(int)(-15137));
224 int u2
= t5
+t6
, u3
= t4
+t6
, u4
= t5
+t7
;
225 int z5
= (cast(short)(u3
+u4
)*cast(int)(9633));
226 t4
= (cast(short)(t4
)*cast(int)(2446)); t5
= (cast(short)(t5
)*cast(int)(16819));
227 t6
= (cast(short)(t6
)*cast(int)(25172)); t7
= (cast(short)(t7
)*cast(int)(12299));
228 u1
= (cast(short)(u1
)*cast(int)(-7373)); u2
= (cast(short)(u2
)*cast(int)(-20995));
229 u3
= (cast(short)(u3
)*cast(int)(-16069)); u4
= (cast(short)(u4
)*cast(int)(-3196));
231 s0
= t10
+t11
; s1
= t7
+u1
+u4
; s3
= t6
+u2
+u3
; s4
= t10
-t11
; s5
= t5
+u2
+u4
; s7
= t4
+u1
+u3
;
234 void DCT2D (int* p
) {
237 for (c
= 7; c
>= 0; --c
, q
+= 8) {
238 int s0
= q
[0], s1
= q
[1], s2
= q
[2], s3
= q
[3], s4
= q
[4], s5
= q
[5], s6
= q
[6], s7
= q
[7];
239 //DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
241 q
[0] = s0
<<ROW_BITS
; q
[1] = DCT_DESCALE(s1
, CONST_BITS
-ROW_BITS
); q
[2] = DCT_DESCALE(s2
, CONST_BITS
-ROW_BITS
); q
[3] = DCT_DESCALE(s3
, CONST_BITS
-ROW_BITS
);
242 q
[4] = s4
<<ROW_BITS
; q
[5] = DCT_DESCALE(s5
, CONST_BITS
-ROW_BITS
); q
[6] = DCT_DESCALE(s6
, CONST_BITS
-ROW_BITS
); q
[7] = DCT_DESCALE(s7
, CONST_BITS
-ROW_BITS
);
244 for (q
= p
, c
= 7; c
>= 0; --c
, ++q
) {
245 int s0
= q
[0*8], s1
= q
[1*8], s2
= q
[2*8], s3
= q
[3*8], s4
= q
[4*8], s5
= q
[5*8], s6
= q
[6*8], s7
= q
[7*8];
246 //DCT1D(s0, s1, s2, s3, s4, s5, s6, s7);
248 q
[0*8] = DCT_DESCALE(s0
, ROW_BITS
+3); q
[1*8] = DCT_DESCALE(s1
, CONST_BITS
+ROW_BITS
+3); q
[2*8] = DCT_DESCALE(s2
, CONST_BITS
+ROW_BITS
+3); q
[3*8] = DCT_DESCALE(s3
, CONST_BITS
+ROW_BITS
+3);
249 q
[4*8] = DCT_DESCALE(s4
, ROW_BITS
+3); q
[5*8] = DCT_DESCALE(s5
, CONST_BITS
+ROW_BITS
+3); q
[6*8] = DCT_DESCALE(s6
, CONST_BITS
+ROW_BITS
+3); q
[7*8] = DCT_DESCALE(s7
, CONST_BITS
+ROW_BITS
+3);
253 struct sym_freq
{ uint m_key
, m_sym_index
; }
255 // Radix sorts sym_freq[] array by 32-bit key m_key. Returns ptr to sorted values.
256 sym_freq
* radix_sort_syms (uint num_syms
, sym_freq
* pSyms0
, sym_freq
* pSyms1
) {
257 const uint cMaxPasses
= 4;
258 uint[256*cMaxPasses
] hist
;
260 for (uint i
= 0; i
< num_syms
; i
++) {
261 uint freq
= pSyms0
[i
].m_key
;
263 ++hist
[256+((freq
>>8)&0xFF)];
264 ++hist
[256*2+((freq
>>16)&0xFF)];
265 ++hist
[256*3+((freq
>>24)&0xFF)];
267 sym_freq
* pCur_syms
= pSyms0
;
268 sym_freq
* pNew_syms
= pSyms1
;
269 uint total_passes
= cMaxPasses
; while (total_passes
> 1 && num_syms
== hist
[(total_passes
-1)*256]) --total_passes
;
271 for (uint pass_shift
= 0, pass
= 0; pass
< total_passes
; ++pass
, pass_shift
+= 8) {
272 const(uint)* pHist
= &hist
[pass
<<8];
274 for (uint i
= 0; i
< 256; i
++) { offsets
[i
] = cur_ofs
; cur_ofs
+= pHist
[i
]; }
275 for (uint i
= 0; i
< num_syms
; i
++) pNew_syms
[offsets
[(pCur_syms
[i
].m_key
>>pass_shift
)&0xFF]++] = pCur_syms
[i
];
276 sym_freq
* t
= pCur_syms
; pCur_syms
= pNew_syms
; pNew_syms
= t
;
281 // calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
282 void calculate_minimum_redundancy (sym_freq
* A
, int n
) {
283 int root
, leaf
, next
, avbl
, used
, dpth
;
285 if (n
== 1) { A
[0].m_key
= 1; return; }
286 A
[0].m_key
+= A
[1].m_key
; root
= 0; leaf
= 2;
287 for (next
=1; next
< n
-1; next
++)
289 if (leaf
>=n || A
[root
].m_key
<A
[leaf
].m_key
) { A
[next
].m_key
= A
[root
].m_key
; A
[root
++].m_key
= next
; } else A
[next
].m_key
= A
[leaf
++].m_key
;
290 if (leaf
>=n ||
(root
<next
&& A
[root
].m_key
<A
[leaf
].m_key
)) { A
[next
].m_key
+= A
[root
].m_key
; A
[root
++].m_key
= next
; } else A
[next
].m_key
+= A
[leaf
++].m_key
;
293 for (next
=n
-3; next
>=0; next
--) A
[next
].m_key
= A
[A
[next
].m_key
].m_key
+1;
294 avbl
= 1; used
= dpth
= 0; root
= n
-2; next
= n
-1;
297 while (root
>= 0 && cast(int)A
[root
].m_key
== dpth
) { used
++; root
--; }
298 while (avbl
>used
) { A
[next
--].m_key
= dpth
; avbl
--; }
299 avbl
= 2*used
; dpth
++; used
= 0;
303 // Limits canonical Huffman code table's max code size to max_code_size.
304 void huffman_enforce_max_code_size (int* pNum_codes
, int code_list_len
, int max_code_size
) {
305 if (code_list_len
<= 1) return;
306 for (int i
= max_code_size
+1; i
<= MAX_HUFF_CODESIZE
; i
++) pNum_codes
[max_code_size
] += pNum_codes
[i
];
308 for (int i
= max_code_size
; i
> 0; i
--) total
+= ((cast(uint)pNum_codes
[i
])<<(max_code_size
-i
));
309 while (total
!= (1UL<<max_code_size
)) {
310 pNum_codes
[max_code_size
]--;
311 for (int i
= max_code_size
-1; i
> 0; i
--) {
312 if (pNum_codes
[i
]) { pNum_codes
[i
]--; pNum_codes
[i
+1] += 2; break; }
320 // ////////////////////////////////////////////////////////////////////////// //
321 // Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
322 struct jpeg_encoder
{
324 alias WriteFunc
= bool delegate (const(void)[] buf
);
326 nothrow /*@trusted @nogc*/:
328 alias sample_array_t
= int;
332 ubyte m_num_components
;
333 ubyte[3] m_comp_h_samp
;
334 ubyte[3] m_comp_v_samp
;
335 int m_image_x
, m_image_y
, m_image_bpp
, m_image_bpl
;
336 int m_image_x_mcu
, m_image_y_mcu
;
337 int m_image_bpl_xlt
, m_image_bpl_mcu
;
339 int m_mcu_x
, m_mcu_y
;
340 ubyte*[16] m_mcu_lines
;
342 sample_array_t
[64] m_sample_array
;
343 short[64] m_coefficient_array
;
344 int[64][2] m_quantization_tables
;
345 uint[256][4] m_huff_codes
;
346 ubyte[256][4] m_huff_code_sizes
;
347 ubyte[17][4] m_huff_bits
;
348 ubyte[256][4] m_huff_val
;
349 uint[256][4] m_huff_count
;
350 int[3] m_last_dc_val
;
351 enum JPGE_OUT_BUF_SIZE
= 2048;
352 ubyte[JPGE_OUT_BUF_SIZE
] m_out_buf
;
358 bool m_all_stream_writes_succeeded
= true;
361 // Generates an optimized offman table.
362 void optimize_huffman_table (int table_num
, int table_len
) {
363 sym_freq
[MAX_HUFF_SYMBOLS
] syms0
;
364 sym_freq
[MAX_HUFF_SYMBOLS
] syms1
;
365 syms0
[0].m_key
= 1; syms0
[0].m_sym_index
= 0; // dummy symbol, assures that no valid code contains all 1's
366 int num_used_syms
= 1;
367 const uint *pSym_count
= &m_huff_count
[table_num
][0];
368 for (int i
= 0; i
< table_len
; i
++) {
369 if (pSym_count
[i
]) { syms0
[num_used_syms
].m_key
= pSym_count
[i
]; syms0
[num_used_syms
++].m_sym_index
= i
+1; }
371 sym_freq
* pSyms
= radix_sort_syms(num_used_syms
, syms0
.ptr
, syms1
.ptr
);
372 calculate_minimum_redundancy(pSyms
, num_used_syms
);
374 // Count the # of symbols of each code size.
375 int[1+MAX_HUFF_CODESIZE
] num_codes
;
376 //clear_obj(num_codes);
377 for (int i
= 0; i
< num_used_syms
; i
++) num_codes
[pSyms
[i
].m_key
]++;
379 enum JPGE_CODE_SIZE_LIMIT
= 16u; // the maximum possible size of a JPEG Huffman code (valid range is [9,16] - 9 vs. 8 because of the dummy symbol)
380 huffman_enforce_max_code_size(num_codes
.ptr
, num_used_syms
, JPGE_CODE_SIZE_LIMIT
);
382 // Compute m_huff_bits array, which contains the # of symbols per code size.
383 //clear_obj(m_huff_bits[table_num]);
384 m_huff_bits
[table_num
][] = 0;
385 for (int i
= 1; i
<= cast(int)JPGE_CODE_SIZE_LIMIT
; i
++) m_huff_bits
[table_num
][i
] = cast(ubyte)(num_codes
[i
]);
387 // Remove the dummy symbol added above, which must be in largest bucket.
388 for (int i
= JPGE_CODE_SIZE_LIMIT
; i
>= 1; i
--) {
389 if (m_huff_bits
[table_num
][i
]) { m_huff_bits
[table_num
][i
]--; break; }
392 // Compute the m_huff_val array, which contains the symbol indices sorted by code size (smallest to largest).
393 for (int i
= num_used_syms
-1; i
>= 1; i
--) m_huff_val
[table_num
][num_used_syms
-1-i
] = cast(ubyte)(pSyms
[i
].m_sym_index
-1);
396 bool put_obj(T
) (T v
) {
398 return (m_pStream
!is null && m_pStream((&v
)[0..1]));
399 } catch (Exception
) {}
403 bool put_buf() (const(void)* v
, uint len
) {
405 return (m_pStream
!is null && m_pStream(v
[0..len
]));
406 } catch (Exception
) {}
410 // JPEG marker generation.
411 void emit_byte (ubyte i
) {
412 m_all_stream_writes_succeeded
= m_all_stream_writes_succeeded
&& put_obj(i
);
415 void emit_word(uint i
) {
416 emit_byte(cast(ubyte)(i
>>8));
417 emit_byte(cast(ubyte)(i
&0xFF));
420 void emit_marker (int marker
) {
421 emit_byte(cast(ubyte)(0xFF));
422 emit_byte(cast(ubyte)(marker
));
426 void emit_jfif_app0 () {
428 emit_word(2+4+1+2+1+2+2+1+1);
429 emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */
431 emit_byte(1); /* Major version */
432 emit_byte(1); /* Minor version */
433 emit_byte(0); /* Density unit */
436 emit_byte(0); /* No thumbnail image */
440 // Emit quantization tables
442 for (int i
= 0; i
< (m_num_components
== 3 ?
2 : 1); i
++) {
445 emit_byte(cast(ubyte)(i
));
446 for (int j
= 0; j
< 64; j
++) emit_byte(cast(ubyte)(m_quantization_tables
[i
][j
]));
450 // Emit start of frame marker
452 emit_marker(M_SOF0
); /* baseline */
453 emit_word(3*m_num_components
+2+5+1);
454 emit_byte(8); /* precision */
455 emit_word(m_image_y
);
456 emit_word(m_image_x
);
457 emit_byte(m_num_components
);
458 for (int i
= 0; i
< m_num_components
; i
++) {
459 emit_byte(cast(ubyte)(i
+1)); /* component ID */
460 emit_byte(cast(ubyte)((m_comp_h_samp
[i
]<<4)+m_comp_v_samp
[i
])); /* h and v sampling */
461 emit_byte(i
> 0); /* quant. table num */
465 // Emit Huffman table.
466 void emit_dht (ubyte* bits
, ubyte* val
, int index
, bool ac_flag
) {
469 for (int i
= 1; i
<= 16; i
++) length
+= bits
[i
];
470 emit_word(length
+2+1+16);
471 emit_byte(cast(ubyte)(index
+(ac_flag
<<4)));
472 for (int i
= 1; i
<= 16; i
++) emit_byte(bits
[i
]);
473 for (int i
= 0; i
< length
; i
++) emit_byte(val
[i
]);
476 // Emit all Huffman tables.
478 emit_dht(m_huff_bits
[0+0].ptr
, m_huff_val
[0+0].ptr
, 0, false);
479 emit_dht(m_huff_bits
[2+0].ptr
, m_huff_val
[2+0].ptr
, 0, true);
480 if (m_num_components
== 3) {
481 emit_dht(m_huff_bits
[0+1].ptr
, m_huff_val
[0+1].ptr
, 1, false);
482 emit_dht(m_huff_bits
[2+1].ptr
, m_huff_val
[2+1].ptr
, 1, true);
486 // emit start of scan
489 emit_word(2*m_num_components
+2+1+3);
490 emit_byte(m_num_components
);
491 for (int i
= 0; i
< m_num_components
; i
++) {
492 emit_byte(cast(ubyte)(i
+1));
498 emit_byte(0); /* spectral selection */
503 // Emit all markers at beginning of image file.
504 void emit_markers () {
513 // Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays.
514 void compute_huffman_table (uint* codes
, ubyte* code_sizes
, ubyte* bits
, ubyte* val
) {
515 import core
.stdc
.string
: memset
;
517 int i
, l
, last_p
, si
;
518 ubyte[257] huff_size
;
523 for (l
= 1; l
<= 16; l
++)
524 for (i
= 1; i
<= bits
[l
]; i
++)
525 huff_size
[p
++] = cast(ubyte)l
;
527 huff_size
[p
] = 0; last_p
= p
; // write sentinel
529 code
= 0; si
= huff_size
[0]; p
= 0;
533 while (huff_size
[p
] == si
)
534 huff_code
[p
++] = code
++;
539 memset(codes
, 0, codes
[0].sizeof
*256);
540 memset(code_sizes
, 0, code_sizes
[0].sizeof
*256);
541 for (p
= 0; p
< last_p
; p
++)
543 codes
[val
[p
]] = huff_code
[p
];
544 code_sizes
[val
[p
]] = huff_size
[p
];
548 // Quantization table generation.
549 void compute_quant_table (int* pDst
, const(short)* pSrc
) {
551 if (m_params
.quality
< 50)
552 q
= 5000/m_params
.quality
;
554 q
= 200-m_params
.quality
*2;
555 for (int i
= 0; i
< 64; i
++) {
556 int j
= *pSrc
++; j
= (j
*q
+50L)/100L;
557 *pDst
++ = JPGE_MIN(JPGE_MAX(j
, 1), 255);
561 // Higher-level methods.
562 void first_pass_init () {
563 import core
.stdc
.string
: memset
;
564 m_bit_buffer
= 0; m_bits_in
= 0;
565 memset(m_last_dc_val
.ptr
, 0, 3*m_last_dc_val
[0].sizeof
);
570 bool second_pass_init () {
571 compute_huffman_table(&m_huff_codes
[0+0][0], &m_huff_code_sizes
[0+0][0], m_huff_bits
[0+0].ptr
, m_huff_val
[0+0].ptr
);
572 compute_huffman_table(&m_huff_codes
[2+0][0], &m_huff_code_sizes
[2+0][0], m_huff_bits
[2+0].ptr
, m_huff_val
[2+0].ptr
);
573 if (m_num_components
> 1)
575 compute_huffman_table(&m_huff_codes
[0+1][0], &m_huff_code_sizes
[0+1][0], m_huff_bits
[0+1].ptr
, m_huff_val
[0+1].ptr
);
576 compute_huffman_table(&m_huff_codes
[2+1][0], &m_huff_code_sizes
[2+1][0], m_huff_bits
[2+1].ptr
, m_huff_val
[2+1].ptr
);
584 bool jpg_open (int p_x_res
, int p_y_res
, int src_channels
) {
585 m_num_components
= 3;
586 switch (m_params
.subsampling
) {
587 case JpegSubsampling
.Y_ONLY
:
588 m_num_components
= 1;
589 m_comp_h_samp
[0] = 1; m_comp_v_samp
[0] = 1;
590 m_mcu_x
= 8; m_mcu_y
= 8;
592 case JpegSubsampling
.H1V1
:
593 m_comp_h_samp
[0] = 1; m_comp_v_samp
[0] = 1;
594 m_comp_h_samp
[1] = 1; m_comp_v_samp
[1] = 1;
595 m_comp_h_samp
[2] = 1; m_comp_v_samp
[2] = 1;
596 m_mcu_x
= 8; m_mcu_y
= 8;
598 case JpegSubsampling
.H2V1
:
599 m_comp_h_samp
[0] = 2; m_comp_v_samp
[0] = 1;
600 m_comp_h_samp
[1] = 1; m_comp_v_samp
[1] = 1;
601 m_comp_h_samp
[2] = 1; m_comp_v_samp
[2] = 1;
602 m_mcu_x
= 16; m_mcu_y
= 8;
604 case JpegSubsampling
.H2V2
:
605 m_comp_h_samp
[0] = 2; m_comp_v_samp
[0] = 2;
606 m_comp_h_samp
[1] = 1; m_comp_v_samp
[1] = 1;
607 m_comp_h_samp
[2] = 1; m_comp_v_samp
[2] = 1;
608 m_mcu_x
= 16; m_mcu_y
= 16;
613 m_image_x
= p_x_res
; m_image_y
= p_y_res
;
614 m_image_bpp
= src_channels
;
615 m_image_bpl
= m_image_x
*src_channels
;
616 m_image_x_mcu
= (m_image_x
+m_mcu_x
-1)&(~(m_mcu_x
-1));
617 m_image_y_mcu
= (m_image_y
+m_mcu_y
-1)&(~(m_mcu_y
-1));
618 m_image_bpl_xlt
= m_image_x
*m_num_components
;
619 m_image_bpl_mcu
= m_image_x_mcu
*m_num_components
;
620 m_mcus_per_row
= m_image_x_mcu
/m_mcu_x
;
622 if ((m_mcu_lines
[0] = cast(ubyte*)(jpge_malloc(m_image_bpl_mcu
*m_mcu_y
))) is null) return false;
623 for (int i
= 1; i
< m_mcu_y
; i
++)
624 m_mcu_lines
[i
] = m_mcu_lines
[i
-1]+m_image_bpl_mcu
;
626 compute_quant_table(m_quantization_tables
[0].ptr
, s_std_lum_quant
.ptr
);
627 compute_quant_table(m_quantization_tables
[1].ptr
, (m_params
.noChromaDiscrimFlag ? s_std_lum_quant
.ptr
: s_std_croma_quant
.ptr
));
629 m_out_buf_left
= JPGE_OUT_BUF_SIZE
;
630 m_pOut_buf
= m_out_buf
.ptr
;
632 if (m_params
.twoPass
)
634 //clear_obj(m_huff_count);
635 import core
.stdc
.string
: memset
;
636 memset(m_huff_count
.ptr
, 0, m_huff_count
.sizeof
);
641 import core
.stdc
.string
: memcpy
;
642 memcpy(m_huff_bits
[0+0].ptr
, s_dc_lum_bits
.ptr
, 17); memcpy(m_huff_val
[0+0].ptr
, s_dc_lum_val
.ptr
, DC_LUM_CODES
);
643 memcpy(m_huff_bits
[2+0].ptr
, s_ac_lum_bits
.ptr
, 17); memcpy(m_huff_val
[2+0].ptr
, s_ac_lum_val
.ptr
, AC_LUM_CODES
);
644 memcpy(m_huff_bits
[0+1].ptr
, s_dc_chroma_bits
.ptr
, 17); memcpy(m_huff_val
[0+1].ptr
, s_dc_chroma_val
.ptr
, DC_CHROMA_CODES
);
645 memcpy(m_huff_bits
[2+1].ptr
, s_ac_chroma_bits
.ptr
, 17); memcpy(m_huff_val
[2+1].ptr
, s_ac_chroma_val
.ptr
, AC_CHROMA_CODES
);
646 if (!second_pass_init()) return false; // in effect, skip over the first pass
648 return m_all_stream_writes_succeeded
;
651 void load_block_8_8_grey (int x
) {
653 sample_array_t
*pDst
= m_sample_array
.ptr
;
655 for (int i
= 0; i
< 8; i
++, pDst
+= 8)
657 pSrc
= m_mcu_lines
[i
]+x
;
658 pDst
[0] = pSrc
[0]-128; pDst
[1] = pSrc
[1]-128; pDst
[2] = pSrc
[2]-128; pDst
[3] = pSrc
[3]-128;
659 pDst
[4] = pSrc
[4]-128; pDst
[5] = pSrc
[5]-128; pDst
[6] = pSrc
[6]-128; pDst
[7] = pSrc
[7]-128;
663 void load_block_8_8 (int x
, int y
, int c
) {
665 sample_array_t
*pDst
= m_sample_array
.ptr
;
668 for (int i
= 0; i
< 8; i
++, pDst
+= 8)
670 pSrc
= m_mcu_lines
[y
+i
]+x
;
671 pDst
[0] = pSrc
[0*3]-128; pDst
[1] = pSrc
[1*3]-128; pDst
[2] = pSrc
[2*3]-128; pDst
[3] = pSrc
[3*3]-128;
672 pDst
[4] = pSrc
[4*3]-128; pDst
[5] = pSrc
[5*3]-128; pDst
[6] = pSrc
[6*3]-128; pDst
[7] = pSrc
[7*3]-128;
676 void load_block_16_8 (int x
, int c
) {
679 sample_array_t
*pDst
= m_sample_array
.ptr
;
682 for (int i
= 0; i
< 16; i
+= 2, pDst
+= 8)
684 pSrc1
= m_mcu_lines
[i
+0]+x
;
685 pSrc2
= m_mcu_lines
[i
+1]+x
;
686 pDst
[0] = ((pSrc1
[ 0*3]+pSrc1
[ 1*3]+pSrc2
[ 0*3]+pSrc2
[ 1*3]+a
)>>2)-128; pDst
[1] = ((pSrc1
[ 2*3]+pSrc1
[ 3*3]+pSrc2
[ 2*3]+pSrc2
[ 3*3]+b
)>>2)-128;
687 pDst
[2] = ((pSrc1
[ 4*3]+pSrc1
[ 5*3]+pSrc2
[ 4*3]+pSrc2
[ 5*3]+a
)>>2)-128; pDst
[3] = ((pSrc1
[ 6*3]+pSrc1
[ 7*3]+pSrc2
[ 6*3]+pSrc2
[ 7*3]+b
)>>2)-128;
688 pDst
[4] = ((pSrc1
[ 8*3]+pSrc1
[ 9*3]+pSrc2
[ 8*3]+pSrc2
[ 9*3]+a
)>>2)-128; pDst
[5] = ((pSrc1
[10*3]+pSrc1
[11*3]+pSrc2
[10*3]+pSrc2
[11*3]+b
)>>2)-128;
689 pDst
[6] = ((pSrc1
[12*3]+pSrc1
[13*3]+pSrc2
[12*3]+pSrc2
[13*3]+a
)>>2)-128; pDst
[7] = ((pSrc1
[14*3]+pSrc1
[15*3]+pSrc2
[14*3]+pSrc2
[15*3]+b
)>>2)-128;
690 int temp
= a
; a
= b
; b
= temp
;
694 void load_block_16_8_8 (int x
, int c
) {
696 sample_array_t
*pDst
= m_sample_array
.ptr
;
698 for (int i
= 0; i
< 8; i
++, pDst
+= 8) {
699 pSrc1
= m_mcu_lines
[i
+0]+x
;
700 pDst
[0] = ((pSrc1
[ 0*3]+pSrc1
[ 1*3])>>1)-128; pDst
[1] = ((pSrc1
[ 2*3]+pSrc1
[ 3*3])>>1)-128;
701 pDst
[2] = ((pSrc1
[ 4*3]+pSrc1
[ 5*3])>>1)-128; pDst
[3] = ((pSrc1
[ 6*3]+pSrc1
[ 7*3])>>1)-128;
702 pDst
[4] = ((pSrc1
[ 8*3]+pSrc1
[ 9*3])>>1)-128; pDst
[5] = ((pSrc1
[10*3]+pSrc1
[11*3])>>1)-128;
703 pDst
[6] = ((pSrc1
[12*3]+pSrc1
[13*3])>>1)-128; pDst
[7] = ((pSrc1
[14*3]+pSrc1
[15*3])>>1)-128;
707 void load_quantized_coefficients (int component_num
) {
708 int *q
= m_quantization_tables
[component_num
> 0].ptr
;
709 short *pDst
= m_coefficient_array
.ptr
;
710 for (int i
= 0; i
< 64; i
++)
712 sample_array_t j
= m_sample_array
[s_zag
[i
]];
715 if ((j
= -j
+(*q
>>1)) < *q
)
718 *pDst
++ = cast(short)(-(j
/ *q
));
722 if ((j
= j
+(*q
>>1)) < *q
)
725 *pDst
++ = cast(short)((j
/ *q
));
731 void flush_output_buffer () {
732 if (m_out_buf_left
!= JPGE_OUT_BUF_SIZE
) m_all_stream_writes_succeeded
= m_all_stream_writes_succeeded
&& put_buf(m_out_buf
.ptr
, JPGE_OUT_BUF_SIZE
-m_out_buf_left
);
733 m_pOut_buf
= m_out_buf
.ptr
;
734 m_out_buf_left
= JPGE_OUT_BUF_SIZE
;
737 void put_bits (uint bits
, uint len
) {
738 m_bit_buffer |
= (cast(uint)bits
<<(24-(m_bits_in
+= len
)));
739 while (m_bits_in
>= 8) {
741 //#define JPGE_PUT_BYTE(c) { *m_pOut_buf++ = (c); if (--m_out_buf_left == 0) flush_output_buffer(); }
742 //JPGE_PUT_BYTE(c = (ubyte)((m_bit_buffer>>16)&0xFF));
743 //if (c == 0xFF) JPGE_PUT_BYTE(0);
744 c
= cast(ubyte)((m_bit_buffer
>>16)&0xFF);
746 if (--m_out_buf_left
== 0) flush_output_buffer();
749 if (--m_out_buf_left
== 0) flush_output_buffer();
756 void code_coefficients_pass_one (int component_num
) {
757 if (component_num
>= 3) return; // just to shut up static analysis
758 int i
, run_len
, nbits
, temp1
;
759 short *src
= m_coefficient_array
.ptr
;
760 uint *dc_count
= (component_num ? m_huff_count
[0+1].ptr
: m_huff_count
[0+0].ptr
);
761 uint *ac_count
= (component_num ? m_huff_count
[2+1].ptr
: m_huff_count
[2+0].ptr
);
763 temp1
= src
[0]-m_last_dc_val
[component_num
];
764 m_last_dc_val
[component_num
] = src
[0];
765 if (temp1
< 0) temp1
= -temp1
;
770 nbits
++; temp1
>>= 1;
774 for (run_len
= 0, i
= 1; i
< 64; i
++)
776 if ((temp1
= m_coefficient_array
[i
]) == 0)
780 while (run_len
>= 16)
785 if (temp1
< 0) temp1
= -temp1
;
787 while (temp1
>>= 1) nbits
++;
788 ac_count
[(run_len
<<4)+nbits
]++;
792 if (run_len
) ac_count
[0]++;
795 void code_coefficients_pass_two (int component_num
) {
796 int i
, j
, run_len
, nbits
, temp1
, temp2
;
797 short *pSrc
= m_coefficient_array
.ptr
;
799 ubyte*[2] code_sizes
;
801 if (component_num
== 0)
803 codes
[0] = m_huff_codes
[0+0].ptr
; codes
[1] = m_huff_codes
[2+0].ptr
;
804 code_sizes
[0] = m_huff_code_sizes
[0+0].ptr
; code_sizes
[1] = m_huff_code_sizes
[2+0].ptr
;
808 codes
[0] = m_huff_codes
[0+1].ptr
; codes
[1] = m_huff_codes
[2+1].ptr
;
809 code_sizes
[0] = m_huff_code_sizes
[0+1].ptr
; code_sizes
[1] = m_huff_code_sizes
[2+1].ptr
;
812 temp1
= temp2
= pSrc
[0]-m_last_dc_val
[component_num
];
813 m_last_dc_val
[component_num
] = pSrc
[0];
817 temp1
= -temp1
; temp2
--;
823 nbits
++; temp1
>>= 1;
826 put_bits(codes
[0][nbits
], code_sizes
[0][nbits
]);
827 if (nbits
) put_bits(temp2
&((1<<nbits
)-1), nbits
);
829 for (run_len
= 0, i
= 1; i
< 64; i
++)
831 if ((temp1
= m_coefficient_array
[i
]) == 0)
835 while (run_len
>= 16)
837 put_bits(codes
[1][0xF0], code_sizes
[1][0xF0]);
840 if ((temp2
= temp1
) < 0)
848 j
= (run_len
<<4)+nbits
;
849 put_bits(codes
[1][j
], code_sizes
[1][j
]);
850 put_bits(temp2
&((1<<nbits
)-1), nbits
);
855 put_bits(codes
[1][0], code_sizes
[1][0]);
858 void code_block (int component_num
) {
859 DCT2D(m_sample_array
.ptr
);
860 load_quantized_coefficients(component_num
);
862 code_coefficients_pass_one(component_num
);
864 code_coefficients_pass_two(component_num
);
867 void process_mcu_row () {
868 if (m_num_components
== 1)
870 for (int i
= 0; i
< m_mcus_per_row
; i
++)
872 load_block_8_8_grey(i
); code_block(0);
875 else if ((m_comp_h_samp
[0] == 1) && (m_comp_v_samp
[0] == 1))
877 for (int i
= 0; i
< m_mcus_per_row
; i
++)
879 load_block_8_8(i
, 0, 0); code_block(0); load_block_8_8(i
, 0, 1); code_block(1); load_block_8_8(i
, 0, 2); code_block(2);
882 else if ((m_comp_h_samp
[0] == 2) && (m_comp_v_samp
[0] == 1))
884 for (int i
= 0; i
< m_mcus_per_row
; i
++)
886 load_block_8_8(i
*2+0, 0, 0); code_block(0); load_block_8_8(i
*2+1, 0, 0); code_block(0);
887 load_block_16_8_8(i
, 1); code_block(1); load_block_16_8_8(i
, 2); code_block(2);
890 else if ((m_comp_h_samp
[0] == 2) && (m_comp_v_samp
[0] == 2))
892 for (int i
= 0; i
< m_mcus_per_row
; i
++)
894 load_block_8_8(i
*2+0, 0, 0); code_block(0); load_block_8_8(i
*2+1, 0, 0); code_block(0);
895 load_block_8_8(i
*2+0, 1, 0); code_block(0); load_block_8_8(i
*2+1, 1, 0); code_block(0);
896 load_block_16_8(i
, 1); code_block(1); load_block_16_8(i
, 2); code_block(2);
901 bool terminate_pass_one () {
902 optimize_huffman_table(0+0, DC_LUM_CODES
); optimize_huffman_table(2+0, AC_LUM_CODES
);
903 if (m_num_components
> 1)
905 optimize_huffman_table(0+1, DC_CHROMA_CODES
); optimize_huffman_table(2+1, AC_CHROMA_CODES
);
907 return second_pass_init();
910 bool terminate_pass_two () {
912 flush_output_buffer();
914 m_pass_num
++; // purposely bump up m_pass_num, for debugging
918 bool process_end_of_image () {
921 if (m_mcu_y_ofs
< 16) // check here just to shut up static analysis
923 for (int i
= m_mcu_y_ofs
; i
< m_mcu_y
; i
++) {
924 import core
.stdc
.string
: memcpy
;
925 memcpy(m_mcu_lines
[i
], m_mcu_lines
[m_mcu_y_ofs
-1], m_image_bpl_mcu
);
932 return terminate_pass_one();
934 return terminate_pass_two();
937 void load_mcu (const(void)* pSrc
) {
938 import core
.stdc
.string
: memcpy
;
939 const(ubyte)* Psrc
= cast(const(ubyte)*)(pSrc
);
941 ubyte* pDst
= m_mcu_lines
[m_mcu_y_ofs
]; // OK to write up to m_image_bpl_xlt bytes to pDst
943 if (m_num_components
== 1)
945 if (m_image_bpp
== 4)
946 RGBA_to_Y(pDst
, Psrc
, m_image_x
);
947 else if (m_image_bpp
== 3)
948 RGB_to_Y(pDst
, Psrc
, m_image_x
);
950 memcpy(pDst
, Psrc
, m_image_x
);
954 if (m_image_bpp
== 4)
955 RGBA_to_YCC(pDst
, Psrc
, m_image_x
);
956 else if (m_image_bpp
== 3)
957 RGB_to_YCC(pDst
, Psrc
, m_image_x
);
959 Y_to_YCC(pDst
, Psrc
, m_image_x
);
962 // Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16
963 if (m_num_components
== 1) {
964 import core
.stdc
.string
: memset
;
965 memset(m_mcu_lines
[m_mcu_y_ofs
]+m_image_bpl_xlt
, pDst
[m_image_bpl_xlt
-1], m_image_x_mcu
-m_image_x
);
968 const ubyte y
= pDst
[m_image_bpl_xlt
-3+0], cb
= pDst
[m_image_bpl_xlt
-3+1], cr
= pDst
[m_image_bpl_xlt
-3+2];
969 ubyte *q
= m_mcu_lines
[m_mcu_y_ofs
]+m_image_bpl_xlt
;
970 for (int i
= m_image_x
; i
< m_image_x_mcu
; i
++)
972 *q
++ = y
; *q
++ = cb
; *q
++ = cr
;
976 if (++m_mcu_y_ofs
== m_mcu_y
)
984 m_mcu_lines
[0] = null;
986 m_all_stream_writes_succeeded
= true;
991 //this () { clear(); }
992 ~this () { deinit(); }
994 @disable this (this); // no copies
996 // Initializes the compressor.
997 // pStream: The stream object to use for writing compressed data.
998 // comp_params - Compression parameters structure, defined above.
999 // width, height - Image dimensions.
1000 // channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
1001 // Returns false on out of memory or if a stream write fails.
1002 bool setup() (WriteFunc pStream
, int width
, int height
, int src_channels
, in auto ref JpegParams comp_params
) {
1004 if ((pStream
is null || width
< 1 || height
< 1) ||
(src_channels
!= 1 && src_channels
!= 3 && src_channels
!= 4) ||
!comp_params
.check()) return false;
1005 m_pStream
= pStream
;
1006 m_params
= comp_params
;
1007 return jpg_open(width
, height
, src_channels
);
1010 bool setup() (WriteFunc pStream
, int width
, int height
, int src_channels
) { return setup(pStream
, width
, height
, src_channels
, JpegParams()); }
1012 @property ref const(JpegParams
) params () const pure nothrow @safe @nogc { pragma(inline
, true); return m_params
; }
1014 // Deinitializes the compressor, freeing any allocated memory. May be called at any time.
1016 jpge_free(m_mcu_lines
[0]);
1020 @property uint total_passes () const pure nothrow @safe @nogc { pragma(inline
, true); return (m_params
.twoPass ?
2 : 1); }
1021 @property uint cur_pass () const pure nothrow @safe @nogc { pragma(inline
, true); return m_pass_num
; }
1023 // Call this method with each source scanline.
1024 // width*src_channels bytes per scanline is expected (RGB or Y format).
1025 // You must call with null after all scanlines are processed to finish compression.
1026 // Returns false on out of memory or if a stream write fails.
1027 bool process_scanline (const(void)* pScanline
) {
1028 if (m_pass_num
< 1 || m_pass_num
> 2) return false;
1029 if (m_all_stream_writes_succeeded
) {
1030 if (pScanline
is null) {
1031 if (!process_end_of_image()) return false;
1033 load_mcu(pScanline
);
1036 return m_all_stream_writes_succeeded
;