- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# jpeg.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  *  - a simple baseline encoder
    00021  *  - created exactly after the specs
    00022  *  - no optimization or anything like that :)
    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); // precision
    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); // color components
    00116
    00117         PutByte(1); // component id
    00118         PutByte(0x11); // hor | ver sampling factor
    00119         PutByte(0); // quant. tbl. id
    00120
    00121         PutByte(2); // component id
    00122         PutByte(0x11); // hor | ver sampling factor
    00123         PutByte(1); // quant. tbl. id
    00124
    00125         PutByte(3); // component id
    00126         PutByte(0x11); // hor | ver sampling factor
    00127         PutByte(1); // quant. tbl. id
    00128 }
    00129
    00130 void CJpegEncoder::WriteDHT()
    00131 {
    00132         PutByte(0xff);
    00133         PutByte(0xc4);
    00134
    00135         WORD size = 0x01A2; // 2 + n*(17+mi);
    00136         PutByte(size>>8);
    00137         PutByte(size&0xff);
    00138
    00139         PutByte(0x00); // tbl class (DC) | tbl id
    00140         PutBytes(DCVLC_NumByLength[0], 16);
    00141         for(int i = 0; i < 12; i++) PutByte(i);
    00142
    00143         PutByte(0x01); // tbl class (DC) | tbl id
    00144         PutBytes(DCVLC_NumByLength[1], 16);
    00145         for(int i = 0; i < 12; i++) PutByte(i);
    00146
    00147         PutByte(0x10); // tbl class (AC) | tbl id
    00148         PutBytes(ACVLC_NumByLength[0], 16);
    00149         PutBytes(ACVLC_Data[0], sizeof(ACVLC_Data[0]));
    00150
    00151         PutByte(0x11); // tbl class (AC) | tbl id
    00152         PutBytes(ACVLC_NumByLength[1], 16);
    00153         PutBytes(ACVLC_Data[1], sizeof(ACVLC_Data[1]));
    00154 }
    00155
    00156 // float(1.0 / sqrt(2.0))
    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); // color components: 3
    00170
    00171         PutByte(1); // component id
    00172         PutByte(0x00); // DC | AC huff tbl
    00173
    00174         PutByte(2); // component id
    00175         PutByte(0x11); // DC | AC huff tbl
    00176
    00177         PutByte(3); // component id
    00178         PutByte(0x11); // DC | AC huff tbl
    00179
    00180         PutByte(0); // ss, first AC
    00181         PutByte(63); // se, last AC
    00182
    00183         PutByte(0); // ah | al
    00184
    00185         static float cosuv[8][8][8][8];
    00186
    00187         // oh yeah, we don't need no fast dct :)
    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                                         for(int j = 0; j < jj; j++)
    00220                                                 for(int i = 0; i < ii; i++)
    00221                                                         F += (signed char)m_p[((y+j)*m_w + (x+i))*4 + c] * cosuv[v][u][j][i];
    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) // 16 & 24 not tested!!! there may be some alignment problems when the row size is not 4*something in bytes
    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; // the default quantization table contains a little too large values
    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); // yeah... a bit unbuffered, for now
    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