00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdafx.h"
00028 #include <math.h>
00029 #include "jpeg.h"
00030 #include "jpeg_tables.h"
00031
00032 bool CJpegEncoder::PutBit(int b, int n)
00033 {
00034 if(n > 24 || n <= 0) return(false);
00035
00036 m_bbuff <<= n;
00037 m_bbuff |= b & ((1 << n) - 1);
00038 m_bwidth += n;
00039
00040 while(m_bwidth >= 8)
00041 {
00042 BYTE c = (BYTE)(m_bbuff >> (m_bwidth - 8));
00043 PutByte(c);
00044 if(c == 0xff) PutByte(0);
00045 m_bwidth -= 8;
00046 }
00047
00048 return(true);
00049 }
00050
00051 void CJpegEncoder::Flush()
00052 {
00053 if(m_bwidth > 0)
00054 {
00055 BYTE c = m_bbuff << (8 - m_bwidth);
00056 PutByte(c);
00057 if(c == 0xff) PutByte(0);
00058 }
00059
00060 m_bbuff = m_bwidth = 0;
00061 }
00062
00064
00065 int CJpegEncoder::GetBitWidth(short q)
00066 {
00067 if(q == 0) return(0);
00068 if(q < 0) q = -q;
00069
00070 int width = 15;
00071 for(; !(q&0x4000); q <<= 1, width--);
00072 return(width);
00073 }
00074
00076
00077 void CJpegEncoder::WriteSOI()
00078 {
00079 PutByte(0xff);
00080 PutByte(0xd8);
00081 }
00082
00083 void CJpegEncoder::WriteDQT()
00084 {
00085 PutByte(0xff);
00086 PutByte(0xdb);
00087
00088 WORD size = 2 + 2*(65 + 64*0);
00089 PutByte(size>>8);
00090 PutByte(size&0xff);
00091
00092 for(int c = 0; c < 2; c++)
00093 {
00094 PutByte(c);
00095 PutBytes(quanttbl[c], 64);
00096 }
00097 }
00098
00099 void CJpegEncoder::WriteSOF0()
00100 {
00101 PutByte(0xff);
00102 PutByte(0xc0);
00103
00104 WORD size = 8 + 3*ColorComponents;
00105 PutByte(size>>8);
00106 PutByte(size&0xff);
00107
00108 PutByte(8);
00109
00110 PutByte(m_h>>8);
00111 PutByte(m_h&0xff);
00112 PutByte(m_w>>8);
00113 PutByte(m_w&0xff);
00114
00115 PutByte(ColorComponents);
00116
00117 PutByte(1);
00118 PutByte(0x11);
00119 PutByte(0);
00120
00121 PutByte(2);
00122 PutByte(0x11);
00123 PutByte(1);
00124
00125 PutByte(3);
00126 PutByte(0x11);
00127 PutByte(1);
00128 }
00129
00130 void CJpegEncoder::WriteDHT()
00131 {
00132 PutByte(0xff);
00133 PutByte(0xc4);
00134
00135 WORD size = 0x01A2;
00136 PutByte(size>>8);
00137 PutByte(size&0xff);
00138
00139 PutByte(0x00);
00140 PutBytes(DCVLC_NumByLength[0], 16);
00141 for(int i = 0; i < 12; i++) PutByte(i);
00142
00143 PutByte(0x01);
00144 PutBytes(DCVLC_NumByLength[1], 16);
00145 for(int i = 0; i < 12; i++) PutByte(i);
00146
00147 PutByte(0x10);
00148 PutBytes(ACVLC_NumByLength[0], 16);
00149 PutBytes(ACVLC_Data[0], sizeof(ACVLC_Data[0]));
00150
00151 PutByte(0x11);
00152 PutBytes(ACVLC_NumByLength[1], 16);
00153 PutBytes(ACVLC_Data[1], sizeof(ACVLC_Data[1]));
00154 }
00155
00156
00157 #define invsq2 0.70710678118654f
00158 #define PI 3.14159265358979
00159
00160 void CJpegEncoder::WriteSOS()
00161 {
00162 PutByte(0xff);
00163 PutByte(0xda);
00164
00165 WORD size = 6 + 2*ColorComponents;
00166 PutByte(size>>8);
00167 PutByte(size&0xff);
00168
00169 PutByte(ColorComponents);
00170
00171 PutByte(1);
00172 PutByte(0x00);
00173
00174 PutByte(2);
00175 PutByte(0x11);
00176
00177 PutByte(3);
00178 PutByte(0x11);
00179
00180 PutByte(0);
00181 PutByte(63);
00182
00183 PutByte(0);
00184
00185 static float cosuv[8][8][8][8];
00186
00187
00188 for(int v = 0; v < 8; v++)
00189 for(int u = 0; u < 8; u++)
00190 for(int j = 0; j < 8; j++)
00191 for(int i = 0; i < 8; i++)
00192 cosuv[v][u][j][i] = (float)(cos((2*i+1)*u*PI/16) * cos((2*j+1)*v*PI/16));
00193
00194 int prevDC[3] = {0, 0, 0};
00195
00196 for(int y = 0; y < m_h; y += 8)
00197 {
00198 int jj = min(m_h - y, 8);
00199
00200 for(int x = 0; x < m_w; x += 8)
00201 {
00202 int ii = min(m_w - x, 8);
00203
00204 for(int c = 0; c < ColorComponents; c++)
00205 {
00206 int cc = !!c;
00207
00208 int ACs = 0;
00209
00210 static short block[64];
00211
00212 for(int zigzag = 0; zigzag < 64; zigzag++)
00213 {
00214 BYTE u = zigzagU[zigzag];
00215 BYTE v = zigzagV[zigzag];
00216
00217 float F = 0;
00218
00219
00220
00221
00222
00223 for(int j = 0; j < jj; j++)
00224 {
00225 signed char* p = (signed char*)&m_p[((y+j)*m_w + x)*4 + c];
00226 for(int i = 0; i < ii; i++, p += 4)
00227 F += *p * cosuv[v][u][j][i];
00228 }
00229
00230 float cu = !u ? invsq2 : 1.0f;
00231 float cv = !v ? invsq2 : 1.0f;
00232
00233 block[zigzag] = short(2.0 / 8.0 * cu * cv * F) / quanttbl[cc][zigzag];
00234 }
00235
00236 short DC = block[0] - prevDC[c];
00237 prevDC[c] = block[0];
00238
00239 int size = GetBitWidth(DC);
00240 PutBit(DCVLC[cc][size], DCVLC_Size[cc][size]);
00241
00242 if(DC < 0) DC = DC - 1;
00243 PutBit(DC, size);
00244
00245 int j;
00246 for(j = 64; j > 1 && !block[j-1]; j--);
00247
00248 for(int i = 1; i < j; i++)
00249 {
00250 short AC = block[i];
00251
00252 if(AC == 0)
00253 {
00254 if(++ACs == 16)
00255 {
00256 PutBit(ACVLC[cc][15][0], ACVLC_Size[cc][15][0]);
00257 ACs = 0;
00258 }
00259 }
00260 else
00261 {
00262 int size = GetBitWidth(AC);
00263 PutBit(ACVLC[cc][ACs][size], ACVLC_Size[cc][ACs][size]);
00264
00265 if(AC < 0) AC--;
00266 PutBit(AC, size);
00267
00268 ACs = 0;
00269 }
00270 }
00271
00272 if(j < 64) PutBit(ACVLC[cc][0][0], ACVLC_Size[cc][0][0]);
00273 }
00274 }
00275 }
00276
00277 Flush();
00278 }
00279
00280 void CJpegEncoder::WriteEOI()
00281 {
00282 PutByte(0xff);
00283 PutByte(0xd9);
00284 }
00285
00286
00287
00288 CJpegEncoder::CJpegEncoder()
00289 {
00290 }
00291
00292 bool CJpegEncoder::Encode(const BYTE* dib)
00293 {
00294 m_bbuff = m_bwidth = 0;
00295
00296 BITMAPINFO* bi = (BITMAPINFO*)dib;
00297
00298 int bpp = bi->bmiHeader.biBitCount;
00299
00300 if(bpp != 16 && bpp != 24 && bpp != 32)
00301 return false;
00302
00303 m_w = bi->bmiHeader.biWidth;
00304 m_h = abs(bi->bmiHeader.biHeight);
00305 m_p = new BYTE[m_w*m_h*4];
00306
00307 const BYTE* src = dib + sizeof(bi->bmiHeader);
00308 if(bi->bmiHeader.biBitCount <= 8)
00309 {
00310 if(bi->bmiHeader.biClrUsed) src += bi->bmiHeader.biClrUsed * sizeof(bi->bmiColors[0]);
00311 else src += (1 << bi->bmiHeader.biBitCount) * sizeof(bi->bmiColors[0]);
00312 }
00313
00314 int srcpitch = m_w*(bpp>>3);
00315 int dstpitch = m_w*4;
00316
00317 BitBltFromRGBToRGB(
00318 m_w, m_h,
00319 m_p, dstpitch, 32,
00320 (BYTE*)src + srcpitch*(m_h-1), -srcpitch, bpp);
00321
00322 BYTE* p = m_p;
00323 for(BYTE* e = p + m_h*dstpitch; p < e; p += 4)
00324 {
00325 int r = p[2], g = p[1], b = p[0];
00326
00327 p[0] = (BYTE)min(max(0.2990*r+0.5870*g+0.1140*b, 0), 255) - 128;
00328 p[1] = (BYTE)min(max(-0.1687*r-0.3313*g+0.5000*b + 128, 0), 255) - 128;
00329 p[2] = (BYTE)min(max(0.5000*r-0.4187*g-0.0813*b + 128, 0), 255) - 128;
00330 }
00331
00332 if(quanttbl[0][0] == 16)
00333 {
00334 for(int i = 0; i < countof(quanttbl); i++)
00335 for(int j = 0; j < countof(quanttbl[0]); j++)
00336 quanttbl[i][j] >>= 2;
00337 }
00338
00339 WriteSOI();
00340 WriteDQT();
00341 WriteSOF0();
00342 WriteDHT();
00343 WriteSOS();
00344 WriteEOI();
00345
00346 delete [] m_p;
00347
00348 return true;
00349 }
00350
00352
00353 CJpegEncoderFile::CJpegEncoderFile(LPCTSTR fn)
00354 {
00355 m_fn = fn;
00356 m_file = NULL;
00357 }
00358
00359 bool CJpegEncoderFile::PutByte(BYTE b)
00360 {
00361 return fputc(b, m_file) != EOF;
00362 }
00363
00364 bool CJpegEncoderFile::PutBytes(const void* pData, int len)
00365 {
00366 return fwrite(pData, 1, len, m_file) == len;
00367 }
00368
00369 bool CJpegEncoderFile::Encode(const BYTE* dib)
00370 {
00371 if(!(m_file = _tfopen(m_fn, _T("wb")))) return false;
00372 bool ret = __super::Encode(dib);
00373 fclose(m_file);
00374 m_file = NULL;
00375 return ret;
00376 }
00377
00379
00380 CJpegEncoderMem::CJpegEncoderMem()
00381 {
00382 }
00383
00384 bool CJpegEncoderMem::PutByte(BYTE b)
00385 {
00386 m_pdata->Add(b);
00387 return true;
00388 }
00389
00390 bool CJpegEncoderMem::PutBytes(const void* pData, int len)
00391 {
00392 CArray<BYTE> moredata;
00393 moredata.SetSize(len);
00394 memcpy(moredata.GetData(), pData, len);
00395 m_pdata->Append(moredata);
00396 return true;
00397 }
00398
00399 bool CJpegEncoderMem::Encode(const BYTE* dib, CArray<BYTE>& data)
00400 {
00401 m_pdata = &data;
00402 return __super::Encode(dib);
00403 }
00404