2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
20 * - a simple baseline encoder
21 * - created exactly after the specs
22 * - no optimization or anything like that :)
30 #include "jpeg_tables.h"
32 bool CJpegEncoder::PutBit(int b
, int n
)
34 if(n
> 24 || n
<= 0) return(false);
37 m_bbuff
|= b
& ((1 << n
) - 1);
42 BYTE c
= (BYTE
)(m_bbuff
>> (m_bwidth
- 8));
44 if(c
== 0xff) PutByte(0);
51 void CJpegEncoder::Flush()
55 BYTE c
= m_bbuff
<< (8 - m_bwidth
);
57 if(c
== 0xff) PutByte(0);
60 m_bbuff
= m_bwidth
= 0;
65 int CJpegEncoder::GetBitWidth(short q
)
71 for(; !(q
&0x4000); q
<<= 1, width
--);
77 void CJpegEncoder::WriteSOI()
83 void CJpegEncoder::WriteDQT()
88 WORD size
= 2 + 2*(65 + 64*0);
92 for(int c
= 0; c
< 2; c
++)
95 PutBytes(quanttbl
[c
], 64);
99 void CJpegEncoder::WriteSOF0()
104 WORD size
= 8 + 3*ColorComponents
;
108 PutByte(8); // precision
115 PutByte(ColorComponents
); // color components
117 PutByte(1); // component id
118 PutByte(0x11); // hor | ver sampling factor
119 PutByte(0); // quant. tbl. id
121 PutByte(2); // component id
122 PutByte(0x11); // hor | ver sampling factor
123 PutByte(1); // quant. tbl. id
125 PutByte(3); // component id
126 PutByte(0x11); // hor | ver sampling factor
127 PutByte(1); // quant. tbl. id
130 void CJpegEncoder::WriteDHT()
135 WORD size
= 0x01A2; // 2 + n*(17+mi);
139 PutByte(0x00); // tbl class (DC) | tbl id
140 PutBytes(DCVLC_NumByLength
[0], 16);
141 for(int i
= 0; i
< 12; i
++) PutByte(i
);
143 PutByte(0x01); // tbl class (DC) | tbl id
144 PutBytes(DCVLC_NumByLength
[1], 16);
145 for(int i
= 0; i
< 12; i
++) PutByte(i
);
147 PutByte(0x10); // tbl class (AC) | tbl id
148 PutBytes(ACVLC_NumByLength
[0], 16);
149 PutBytes(ACVLC_Data
[0], sizeof(ACVLC_Data
[0]));
151 PutByte(0x11); // tbl class (AC) | tbl id
152 PutBytes(ACVLC_NumByLength
[1], 16);
153 PutBytes(ACVLC_Data
[1], sizeof(ACVLC_Data
[1]));
156 // float(1.0 / sqrt(2.0))
157 #define invsq2 0.70710678118654f
158 #define PI 3.14159265358979
160 void CJpegEncoder::WriteSOS()
165 WORD size
= 6 + 2*ColorComponents
;
169 PutByte(ColorComponents
); // color components: 3
171 PutByte(1); // component id
172 PutByte(0x00); // DC | AC huff tbl
174 PutByte(2); // component id
175 PutByte(0x11); // DC | AC huff tbl
177 PutByte(3); // component id
178 PutByte(0x11); // DC | AC huff tbl
180 PutByte(0); // ss, first AC
181 PutByte(63); // se, last AC
183 PutByte(0); // ah | al
185 static float cosuv
[8][8][8][8];
187 // oh yeah, we don't need no fast dct :)
188 for(int v
= 0; v
< 8; v
++)
189 for(int u
= 0; u
< 8; u
++)
190 for(int j
= 0; j
< 8; j
++)
191 for(int i
= 0; i
< 8; i
++)
192 cosuv
[v
][u
][j
][i
] = (float)(cos((2*i
+1)*u
*PI
/16) * cos((2*j
+1)*v
*PI
/16));
194 int prevDC
[3] = {0, 0, 0};
196 for(int y
= 0; y
< m_h
; y
+= 8)
198 int jj
= min(m_h
- y
, 8);
200 for(int x
= 0; x
< m_w
; x
+= 8)
202 int ii
= min(m_w
- x
, 8);
204 for(int c
= 0; c
< ColorComponents
; c
++)
210 static short block
[64];
212 for(int zigzag
= 0; zigzag
< 64; zigzag
++)
214 BYTE u
= zigzagU
[zigzag
];
215 BYTE v
= zigzagV
[zigzag
];
219 for(int j = 0; j < jj; j++)
220 for(int i = 0; i < ii; i++)
221 F += (signed char)m_p[((y+j)*m_w + (x+i))*4 + c] * cosuv[v][u][j][i];
223 for(int j
= 0; j
< jj
; j
++)
225 signed char* p
= (signed char*)&m_p
[((y
+j
)*m_w
+ x
)*4 + c
];
226 for(int i
= 0; i
< ii
; i
++, p
+= 4)
227 F
+= *p
* cosuv
[v
][u
][j
][i
];
230 float cu
= !u
? invsq2
: 1.0f
;
231 float cv
= !v
? invsq2
: 1.0f
;
233 block
[zigzag
] = short(2.0 / 8.0 * cu
* cv
* F
) / quanttbl
[cc
][zigzag
];
236 short DC
= block
[0] - prevDC
[c
];
237 prevDC
[c
] = block
[0];
239 int size
= GetBitWidth(DC
);
240 PutBit(DCVLC
[cc
][size
], DCVLC_Size
[cc
][size
]);
242 if(DC
< 0) DC
= DC
- 1;
246 for(j
= 64; j
> 1 && !block
[j
-1]; j
--);
248 for(int i
= 1; i
< j
; i
++)
256 PutBit(ACVLC
[cc
][15][0], ACVLC_Size
[cc
][15][0]);
262 int size
= GetBitWidth(AC
);
263 PutBit(ACVLC
[cc
][ACs
][size
], ACVLC_Size
[cc
][ACs
][size
]);
272 if(j
< 64) PutBit(ACVLC
[cc
][0][0], ACVLC_Size
[cc
][0][0]);
280 void CJpegEncoder::WriteEOI()
288 CJpegEncoder::CJpegEncoder()
292 bool CJpegEncoder::Encode(const BYTE
* dib
)
294 m_bbuff
= m_bwidth
= 0;
296 BITMAPINFO
* bi
= (BITMAPINFO
*)dib
;
298 int bpp
= bi
->bmiHeader
.biBitCount
;
300 if(bpp
!= 16 && bpp
!= 24 && bpp
!= 32) // 16 & 24 not tested!!! there may be some alignment problems when the row size is not 4*something in bytes
303 m_w
= bi
->bmiHeader
.biWidth
;
304 m_h
= abs(bi
->bmiHeader
.biHeight
);
305 m_p
= new BYTE
[m_w
*m_h
*4];
307 const BYTE
* src
= dib
+ sizeof(bi
->bmiHeader
);
308 if(bi
->bmiHeader
.biBitCount
<= 8)
310 if(bi
->bmiHeader
.biClrUsed
) src
+= bi
->bmiHeader
.biClrUsed
* sizeof(bi
->bmiColors
[0]);
311 else src
+= (1 << bi
->bmiHeader
.biBitCount
) * sizeof(bi
->bmiColors
[0]);
314 int srcpitch
= m_w
*(bpp
>>3);
315 int dstpitch
= m_w
*4;
320 (BYTE
*)src
+ srcpitch
*(m_h
-1), -srcpitch
, bpp
);
323 for(BYTE
* e
= p
+ m_h
*dstpitch
; p
< e
; p
+= 4)
325 int r
= p
[2], g
= p
[1], b
= p
[0];
327 p
[0] = (BYTE
)min(max(0.2990*r
+0.5870*g
+0.1140*b
, 0), 255) - 128;
328 p
[1] = (BYTE
)min(max(-0.1687*r
-0.3313*g
+0.5000*b
+ 128, 0), 255) - 128;
329 p
[2] = (BYTE
)min(max(0.5000*r
-0.4187*g
-0.0813*b
+ 128, 0), 255) - 128;
332 if(quanttbl
[0][0] == 16)
334 for(int i
= 0; i
< countof(quanttbl
); i
++)
335 for(int j
= 0; j
< countof(quanttbl
[0]); j
++)
336 quanttbl
[i
][j
] >>= 2; // the default quantization table contains a little too large values
353 CJpegEncoderFile::CJpegEncoderFile(LPCTSTR fn
)
359 bool CJpegEncoderFile::PutByte(BYTE b
)
361 return fputc(b
, m_file
) != EOF
;
364 bool CJpegEncoderFile::PutBytes(const void* pData
, int len
)
366 return fwrite(pData
, 1, len
, m_file
) == len
;
369 bool CJpegEncoderFile::Encode(const BYTE
* dib
)
371 if(!(m_file
= _tfopen(m_fn
, _T("wb")))) return false;
372 bool ret
= __super::Encode(dib
);
380 CJpegEncoderMem::CJpegEncoderMem()
384 bool CJpegEncoderMem::PutByte(BYTE b
)
386 m_pdata
->Add(b
); // yeah... a bit unbuffered, for now
390 bool CJpegEncoderMem::PutBytes(const void* pData
, int len
)
392 CAtlArray
<BYTE
> moredata
;
393 moredata
.SetCount(len
);
394 memcpy(moredata
.GetData(), pData
, len
);
395 m_pdata
->Append(moredata
);
399 bool CJpegEncoderMem::Encode(const BYTE
* dib
, CAtlArray
<BYTE
>& data
)
402 return __super::Encode(dib
);