#include <stdio.h>
#include "BMP.h"
#include "Huffman.h"
#include "Coding.h"
int EncodeMarker(StrmType *strm, int mark, DWORD param1, DWORD param2)
{
static BYTE SOI[2] = { 0xff, 0xd8 };
static BYTE APP0[18] = { 0xff, 0xe0, 0x00, 0x10, 0x4A,
0x46, 0x49, 0x46, 0x00, 0x01,
0x01, 0x00, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00 };
static BYTE DQT[5] = { 0xff, 0xdb, 0x00, 0x43, 0 };
static BYTE SOF0[19] = { 0xff, 0xc0, 0x00, 0x11, 0x08,
0, 0, 0, 0,
0x03, 0x01, 0x22, 0x00, 0x02,
0x11, 0x01, 0x03, 0x11, 0x01 };
static BYTE DHT[5] = { 0xff, 0xc4, 0, 0, 0 };
static BYTE SOS[14] = { 0xff, 0xda, 0x00, 0x0c, 0x03,
0x01, 0x00, 0x02, 0x11, 0x03,
0x11, 0x00, 0x3f, 0x00 };
static BYTE EOI[2] = { 0xff, 0xd9 };
switch (mark)
{
case MARKER_SOI: WriteDirect(strm, SOI, sizeof(SOI));
break;
case MARKER_APP0: WriteDirect(strm, APP0, sizeof(APP0));
break;
case MARKER_DQT: DQT[4] = (BYTE)param1;
WriteDirect(strm, DQT, sizeof(DQT));
break;
case MARKER_SOF0: SOF0[5] = (BYTE)(param1/256);
SOF0[6] = (BYTE)(param1%256);
SOF0[7] = (BYTE)(param2/256);
SOF0[8] = (BYTE)(param2%256);
WriteDirect(strm, SOF0, sizeof(SOF0));
break;
case MARKER_DHT: DHT[2] = (BYTE)((3+param1)/256);
DHT[3] = (BYTE)((3+param1)%256);
DHT[4] = (BYTE)param2;
WriteDirect(strm, DHT, sizeof(DHT));
break;
case MARKER_SOS: WriteDirect(strm, SOS, sizeof(SOS));
break;
case MARKER_EOI: WriteDirect(strm, EOI, sizeof(EOI));
break;
default: return -1; //ERR_MARKER_INVALID
}
return 0;
}
int EncodeBlock8x8( StrmType *strm, int *preCompDC, BYTE block[][DCT_SIZE],
BYTE compQuantTablePtr[][DCT_SIZE],
DWORD *compDCHuffCodePtr, BYTE *compDCHuffSizePtr,
DWORD *compACHuffCodePtr, BYTE *compACHuffSizePtr )
{
int i, j, k;
double dct[DCT_SIZE][DCT_SIZE], arr[DCT_SIZE][DCT_SIZE];
int quant[DCT_SIZE][DCT_SIZE], scan[DCT_SIZE*DCT_SIZE];
int zlen[DCT_SIZE*DCT_SIZE], num[DCT_SIZE*DCT_SIZE], cnt;
int difCompDC, code, group, val;
for (i=0; i<DCT_SIZE; i++)
for (j=0; j<DCT_SIZE; j++)
arr[i][j] = (double)block[i][j];
DCT_8x8(dct, arr); //离散余弦变换调用函数
QuantDCTValue(quant, dct, compQuantTablePtr);
difCompDC = quant[0][0]-(*preCompDC); //差量 DC
(*preCompDC) = quant[0][0];
VLIntegerEncode(&code, &group, difCompDC); //查找出数据的位数,如果是负数还得进行一下转换
WriteStream(strm, compDCHuffCodePtr[group], compDCHuffSizePtr[group], 1);
if (difCompDC != 0) // 当差值为0是不把数据0写入文件中
WriteStream(strm, code, group, 1);
ZigZagScan(scan, quant); //z型扫描函数
RunLengthEncode(zlen, num, &cnt, scan); //行程编码函数
for (k=0; k<cnt; k++)
{
VLIntegerEncode(&code, &group, num[k]);
val = (zlen[k]<<4)|group;
WriteStream(strm, compACHuffCodePtr[val], compACHuffSizePtr[val], 1);
if (zlen[k]!=0 || num[k]!=0) //当数据为(0,0)时就不写入数据流了
WriteStream(strm, code, group, 1);
}
return 0;
}
BYTE g_R[MAX_HEIGHT][MAX_WIDTH];
BYTE g_G[MAX_HEIGHT][MAX_WIDTH];
BYTE g_B[MAX_HEIGHT][MAX_WIDTH];
BYTE g_Y[MAX_HEIGHT][MAX_WIDTH];
BYTE g_Cr[MAX_HEIGHT/2][MAX_WIDTH/2];
BYTE g_Cb[MAX_HEIGHT/2][MAX_WIDTH/2];
int EncodeToFile(char *destName, char *srcName, int QValue)
{
int i, j, k, l, m, n, width, height;
int preYDC, preCbDC, preCrDC;
BYTE block[DCT_SIZE][DCT_SIZE];
BYTE arr[DCT_SIZE*DCT_SIZE];
BMP_Header input;
DIB_Type DIB;
StrmType output;
LoadBMPHeader(&input, srcName); //读入BMP文件
CreateDIB(&DIB, &input);
InitStream(&output, destName);
InitEntropyCodec( g_lumDCHuffBitDef, g_lumDCHuffValDef, //产生墒编码表
g_lumACHuffBitDef, g_lumACHuffValDef,
g_chrDCHuffBitDef, g_chrDCHuffValDef,
g_chrACHuffBitDef, g_chrACHuffValDef );
Compact2Bitplane(g_R, g_G, g_B, (BYTE *)DIB.lpvbits, DIB.width, DIB.height, DIB.bpl); //获取RGB值
AlignBitplane16x16(g_R, g_G, g_B, &width, &height, DIB.width, DIB.height); //把图像转换成宽和高都是16字节的倍数长度
RGB2YCrCb(g_Y, g_Cr, g_Cb, g_R, g_G, g_B, width, height); //RGB转换成YCrCb
InitQuantTable(g_lumQuantTable, g_lumQuantTableDef, QValue); //根据压缩比生成亮度系数表
InitQuantTable(g_chrQuantTable, g_chrQuantTableDef, QValue); //根据压缩比生成色度系数表
EncodeMarker(&output, MARKER_SOI, 0xff, 0xff); //向JPEG中写入SOI图像开始标志
EncodeMarker(&output, MARKER_APP0, 0xff, 0xff);
EncodeMarker(&output, MARKER_DQT, 0, 0xff);
for (i=0; i<DCT_SIZE; i++)
for (j=0; j<DCT_SIZE; j++)
arr[g_rleZigZagTable[i][j]] = g_lumQuantTable[i][j];
WriteDirect(&output, arr, DCT_SIZE*DCT_SIZE); //向JPEG中写入亮度量化表(经过Z排序过)
EncodeMarker(&output, MARKER_DQT, 1, 0xff);
for (i=0; i<DCT_SIZE; i++)
for (j=0; j<DCT_SIZE; j++)
arr[g_rleZigZagTable[i][j]] = g_chrQuantTable[i][j];
WriteDirect(&output, arr, DCT_SIZE*DCT_SIZE); //向JPEG中写入色度量化表(经过Z排序过)
EncodeMarker(&output, MARKER_SOF0, DIB.height, DIB.width); //向JPEG中写入帧开始
EncodeMarker(&output, MARKER_DHT, sizeof(g_lumDCHuffBitDef)-1+sizeof(g_lumDCHuffValDef), 0x00);
WriteDirect(&output, g_lumDCHuffBitDef+1, sizeof(g_lumDCHuffBitDef)-1);
WriteDirect(&output, g_lumDCHuffValDef, sizeof(g_lumDCHuffValDef)); //向JPEG中写入亮度DC霍夫曼(Huffman)表
EncodeMarker(&output, MARKER_DHT, sizeof(g_lumACHuffBitDef)-1+sizeof(g_lumACHuffValDef), 0x10);
WriteDirect(&output, g_lumACHuffBitDef+1, sizeof(g_lumACHuffBitDef)-1);
WriteDirect(&output, g_lumACHuffValDef, sizeof(g_lumACHuffValDef)); //向JPEG中写入亮度AC霍夫曼(Huffman)表
EncodeMarker(&output, MARKER_DHT, sizeof(g_chrDCHuffBitDef)-1+sizeof(g_chrDCHuffValDef), 0x01);
WriteDirect(&output, g_chrDCHuffBitDef+1, sizeof(g_chrDCHuffBitDef)-1);
WriteDirect(&output, g_chrDCHuffValDef, sizeof(g_chrDCHuffValDef)); //向JPEG中写入色度DC霍夫曼(Huffman)表
EncodeMarker(&output, MARKER_DHT, sizeof(g_chrACHuffBitDef)-1+sizeof(g_chrACHuffValDef), 0x11);
WriteDirect(&output, g_chrACHuffBitDef+1, sizeof(g_chrACHuffBitDef)-1);
WriteDirect(&output, g_chrACHuffValDef, sizeof(g_chrACHuffValDef)); //向JPEG中写入色度DC霍夫曼(Huffman)表
EncodeMarker(&output, MARKER_SOS, 0xff, 0xff); //向JPEG中写入扫描线开始标志
preYDC = preCbDC = preCrDC = 0;
for (i=0; i<height; i+=(DCT_SIZE<<1)) //为什么上面是填充为16*16,从DCT_SIZE<<1也该看出了
for (j=0; j<width; j+=(DCT_SIZE<<1))
{
for (k=0; k<(DCT_SIZE<<1); k+=DCT_SIZE) //16*16取样
for (l=0; l<(DCT_SIZE<<1); l+=DCT_SIZE)
{
for (m=0; m<DCT_SIZE; m++) //8*8取样,循环4次
for (n=0; n<DCT_SIZE; n++)
block[m][n] = g_Y[i+k+m][j+l+n];
EncodeBlock8x8( &output, &preYDC, block,g_lumQuantTable,g_lumDCHuffCode, //以8X8的数据块进行编码
g_lumDCHuffSize,g_lumACHuffCode, g_lumACHuffSize );
}
for (m=0; m<DCT_SIZE; m++) //为什么只为8*8,不为16*16,因为在RGB在转YCbCr时,是4*4里取样一像素
for (n=0; n<DCT_SIZE; n++)
block[m][n] = g_Cb[(i>>1)+m][(j>>1)+n];
EncodeBlock8x8( &output, &preCbDC, block,g_chrQuantTable,g_chrDCHuffCode,
g_chrDCHuffSize,g_chrACHuffCode, g_chrACHuffSize );
for (m=0; m<DCT_SIZE; m++)
for (n=0; n<DCT_SIZE; n++)
block[m][n] = g_Cr[(i>>1)+m][(j>>1)+n];
EncodeBlock8x8( &output, &preCrDC, block,g_chrQuantTable,g_chrDCHuffCode,
g_chrDCHuffSize,g_chrACHuffCode, g_chrACHuffSize );
}
FlushStream(&output, 1);
EncodeMarker(&output, MARKER_EOI, 0xff, 0xff); //向JPEG中写入结束标志
FreeStream(&output, 0);
DeleteD