jpeg.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:8k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  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)
  8.  *  any later version.
  9.  *   
  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.
  14.  *   
  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
  19.  *
  20.  *  - a simple baseline encoder
  21.  *  - created exactly after the specs
  22.  *  - no optimization or anything like that :)
  23.  *
  24.  */
  25. #include "stdafx.h"
  26. #include <math.h>
  27. #include "jpeg.h"
  28. #include "jpeg_tables.h"
  29. bool CJpegEncoder::PutBit(int b, int n)
  30. {
  31. if(n > 24 || n <= 0) return(false);
  32. m_bbuff <<= n;
  33. m_bbuff |= b & ((1 << n) - 1);
  34. m_bwidth += n;
  35. while(m_bwidth >= 8)
  36. {
  37. BYTE c = (BYTE)(m_bbuff >> (m_bwidth - 8));
  38. PutByte(c);
  39. if(c == 0xff) PutByte(0);
  40. m_bwidth -= 8;
  41. }
  42. return(true);
  43. }
  44. void CJpegEncoder::Flush()
  45. {
  46. if(m_bwidth > 0)
  47. {
  48. BYTE c = m_bbuff << (8 - m_bwidth);
  49. PutByte(c);
  50. if(c == 0xff) PutByte(0);
  51. }
  52. m_bbuff = m_bwidth = 0;
  53. }
  54. ///////
  55. int CJpegEncoder::GetBitWidth(short q)
  56. {
  57. if(q == 0) return(0);
  58. if(q < 0) q = -q;
  59. int width = 15;
  60. for(; !(q&0x4000); q <<= 1, width--);
  61. return(width);
  62. }
  63. ///////
  64. void CJpegEncoder::WriteSOI()
  65. {
  66. PutByte(0xff);
  67. PutByte(0xd8);
  68. }
  69. void CJpegEncoder::WriteDQT()
  70. {
  71. PutByte(0xff);
  72. PutByte(0xdb);
  73. WORD size = 2 + 2*(65 + 64*0);
  74. PutByte(size>>8);
  75. PutByte(size&0xff);
  76. for(int c = 0; c < 2; c++)
  77. {
  78. PutByte(c);
  79. PutBytes(quanttbl[c], 64);
  80. }
  81. }
  82. void CJpegEncoder::WriteSOF0()
  83. {
  84. PutByte(0xff);
  85. PutByte(0xc0);
  86. WORD size = 8 + 3*ColorComponents;
  87. PutByte(size>>8);
  88. PutByte(size&0xff);
  89. PutByte(8); // precision
  90. PutByte(m_h>>8);
  91. PutByte(m_h&0xff);
  92. PutByte(m_w>>8);
  93. PutByte(m_w&0xff);
  94. PutByte(ColorComponents); // color components
  95. PutByte(1); // component id
  96. PutByte(0x11); // hor | ver sampling factor
  97. PutByte(0); // quant. tbl. id
  98. PutByte(2); // component id
  99. PutByte(0x11); // hor | ver sampling factor
  100. PutByte(1); // quant. tbl. id
  101. PutByte(3); // component id
  102. PutByte(0x11); // hor | ver sampling factor
  103. PutByte(1); // quant. tbl. id
  104. }
  105. void CJpegEncoder::WriteDHT()
  106. {
  107. PutByte(0xff);
  108. PutByte(0xc4);
  109. WORD size = 0x01A2; // 2 + n*(17+mi);
  110. PutByte(size>>8);
  111. PutByte(size&0xff);
  112. PutByte(0x00); // tbl class (DC) | tbl id
  113. PutBytes(DCVLC_NumByLength[0], 16);
  114. for(int i = 0; i < 12; i++) PutByte(i);
  115. PutByte(0x01); // tbl class (DC) | tbl id
  116. PutBytes(DCVLC_NumByLength[1], 16);
  117. for(int i = 0; i < 12; i++) PutByte(i);
  118. PutByte(0x10); // tbl class (AC) | tbl id
  119. PutBytes(ACVLC_NumByLength[0], 16);
  120. PutBytes(ACVLC_Data[0], sizeof(ACVLC_Data[0]));
  121. PutByte(0x11); // tbl class (AC) | tbl id
  122. PutBytes(ACVLC_NumByLength[1], 16);
  123. PutBytes(ACVLC_Data[1], sizeof(ACVLC_Data[1]));
  124. }
  125. // float(1.0 / sqrt(2.0))
  126. #define invsq2 0.70710678118654f
  127. #define PI 3.14159265358979
  128. void CJpegEncoder::WriteSOS()
  129. {
  130. PutByte(0xff);
  131. PutByte(0xda);
  132. WORD size = 6 + 2*ColorComponents;
  133. PutByte(size>>8);
  134. PutByte(size&0xff);
  135. PutByte(ColorComponents); // color components: 3
  136. PutByte(1); // component id
  137. PutByte(0x00); // DC | AC huff tbl
  138. PutByte(2); // component id
  139. PutByte(0x11); // DC | AC huff tbl
  140. PutByte(3); // component id
  141. PutByte(0x11); // DC | AC huff tbl
  142. PutByte(0); // ss, first AC
  143. PutByte(63); // se, last AC
  144. PutByte(0); // ah | al
  145. static float cosuv[8][8][8][8];
  146. // oh yeah, we don't need no fast dct :)
  147. for(int v = 0; v < 8; v++) 
  148. for(int u = 0; u < 8; u++)
  149. for(int j = 0; j < 8; j++) 
  150. for(int i = 0; i < 8; i++)
  151. cosuv[v][u][j][i] = (float)(cos((2*i+1)*u*PI/16) * cos((2*j+1)*v*PI/16));
  152. int prevDC[3] = {0, 0, 0};
  153. for(int y = 0; y < m_h; y += 8)
  154. {
  155. int jj = min(m_h - y, 8);
  156. for(int x = 0; x < m_w; x += 8)
  157. {
  158. int ii = min(m_w - x, 8);
  159. for(int c = 0; c < ColorComponents; c++)
  160. {
  161. int cc = !!c;
  162. int ACs = 0;
  163. static short block[64];
  164. for(int zigzag = 0; zigzag < 64; zigzag++) 
  165. {
  166. BYTE u = zigzagU[zigzag];
  167. BYTE v = zigzagV[zigzag];
  168. float F = 0;
  169. /*
  170. for(int j = 0; j < jj; j++)
  171. for(int i = 0; i < ii; i++) 
  172. F += (signed char)m_p[((y+j)*m_w + (x+i))*4 + c] * cosuv[v][u][j][i];
  173. */
  174. for(int j = 0; j < jj; j++)
  175. {
  176. signed char* p = (signed char*)&m_p[((y+j)*m_w + x)*4 + c];
  177. for(int i = 0; i < ii; i++, p += 4) 
  178. F += *p * cosuv[v][u][j][i];
  179. }
  180. float cu = !u ? invsq2 : 1.0f;
  181. float cv = !v ? invsq2 : 1.0f;
  182. block[zigzag] = short(2.0 / 8.0 * cu * cv * F) / quanttbl[cc][zigzag];
  183. }
  184. short DC = block[0] - prevDC[c];
  185. prevDC[c] = block[0];
  186. int size = GetBitWidth(DC);
  187. PutBit(DCVLC[cc][size], DCVLC_Size[cc][size]);
  188. if(DC < 0) DC = DC - 1;
  189. PutBit(DC, size);
  190. int j;
  191. for(j = 64; j > 1 && !block[j-1]; j--);
  192. for(int i = 1; i < j; i++)
  193. {
  194. short AC = block[i];
  195. if(AC == 0)
  196. {
  197. if(++ACs == 16)
  198. {
  199. PutBit(ACVLC[cc][15][0], ACVLC_Size[cc][15][0]);
  200. ACs = 0;
  201. }
  202. }
  203. else
  204. {
  205. int size = GetBitWidth(AC);
  206. PutBit(ACVLC[cc][ACs][size], ACVLC_Size[cc][ACs][size]);
  207. if(AC < 0) AC--;
  208. PutBit(AC, size);
  209. ACs = 0;
  210. }
  211. }
  212. if(j < 64) PutBit(ACVLC[cc][0][0], ACVLC_Size[cc][0][0]);
  213. }
  214. }
  215. }
  216. Flush();
  217. }
  218. void CJpegEncoder::WriteEOI()
  219. {
  220. PutByte(0xff);
  221. PutByte(0xd9);
  222. }
  223. //
  224. CJpegEncoder::CJpegEncoder()
  225. {
  226. }
  227. bool CJpegEncoder::Encode(const BYTE* dib)
  228. {
  229. m_bbuff = m_bwidth = 0;
  230. BITMAPINFO* bi = (BITMAPINFO*)dib;
  231. int bpp = bi->bmiHeader.biBitCount;
  232. 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
  233. return false;
  234. m_w = bi->bmiHeader.biWidth;
  235. m_h = abs(bi->bmiHeader.biHeight);
  236. m_p = new BYTE[m_w*m_h*4];
  237. const BYTE* src = dib + sizeof(bi->bmiHeader);
  238. if(bi->bmiHeader.biBitCount <= 8)
  239. {
  240. if(bi->bmiHeader.biClrUsed) src += bi->bmiHeader.biClrUsed * sizeof(bi->bmiColors[0]);
  241. else src += (1 << bi->bmiHeader.biBitCount) * sizeof(bi->bmiColors[0]);
  242. }
  243. int srcpitch = m_w*(bpp>>3);
  244. int dstpitch = m_w*4;
  245. BitBltFromRGBToRGB(
  246. m_w, m_h, 
  247. m_p, dstpitch, 32, 
  248. (BYTE*)src + srcpitch*(m_h-1), -srcpitch, bpp);
  249. BYTE* p = m_p;
  250. for(BYTE* e = p + m_h*dstpitch; p < e; p += 4)
  251. {
  252. int r = p[2], g = p[1], b = p[0];
  253. p[0] = (BYTE)min(max(0.2990*r+0.5870*g+0.1140*b, 0), 255) - 128;
  254. p[1] = (BYTE)min(max(-0.1687*r-0.3313*g+0.5000*b + 128, 0), 255) - 128;
  255. p[2] = (BYTE)min(max(0.5000*r-0.4187*g-0.0813*b + 128, 0), 255) - 128;
  256. }
  257. if(quanttbl[0][0] == 16)
  258. {
  259. for(int i = 0; i < countof(quanttbl); i++)
  260. for(int j = 0; j < countof(quanttbl[0]); j++)
  261. quanttbl[i][j] >>= 2; // the default quantization table contains a little too large values
  262. }
  263. WriteSOI();
  264. WriteDQT();
  265. WriteSOF0();
  266. WriteDHT();
  267. WriteSOS();
  268. WriteEOI();
  269. delete [] m_p;
  270. return true;
  271. }
  272. //////////
  273. CJpegEncoderFile::CJpegEncoderFile(LPCTSTR fn)
  274. {
  275. m_fn = fn;
  276. m_file = NULL;
  277. }
  278. bool CJpegEncoderFile::PutByte(BYTE b)
  279. {
  280. return fputc(b, m_file) != EOF;
  281. }
  282. bool CJpegEncoderFile::PutBytes(const void* pData, int len)
  283. {
  284. return fwrite(pData, 1, len, m_file) == len;
  285. }
  286. bool CJpegEncoderFile::Encode(const BYTE* dib)
  287. {
  288. if(!(m_file = _tfopen(m_fn, _T("wb")))) return false;
  289. bool ret = __super::Encode(dib);
  290. fclose(m_file);
  291. m_file = NULL;
  292. return ret;
  293. }
  294. //////////
  295. CJpegEncoderMem::CJpegEncoderMem()
  296. {
  297. }
  298. bool CJpegEncoderMem::PutByte(BYTE b)
  299. {
  300. m_pdata->Add(b); // yeah... a bit unbuffered, for now
  301. return true;
  302. }
  303. bool CJpegEncoderMem::PutBytes(const void* pData, int len)
  304. {
  305. CArray<BYTE> moredata;
  306. moredata.SetSize(len);
  307. memcpy(moredata.GetData(), pData, len);
  308. m_pdata->Append(moredata);
  309. return true;
  310. }
  311. bool CJpegEncoderMem::Encode(const BYTE* dib, CArray<BYTE>& data)
  312. {
  313. m_pdata = &data;
  314. return __super::Encode(dib);
  315. }