📄 jenc.cpp
字号:
#include "jenc.h"#include <stdlib.h>
JEnc::JEnc()
{
}
void JEnc::BuildVLITable(void)
{
int i = 0;
for (i = 0; i < DC_MAX_QUANTED; ++i)
{
pVLITAB[i] = ComputeVLI(i);
}
for (i = DC_MIN_QUANTED; i < 0; ++i)
{
pVLITAB[i] = ComputeVLI(i);
}
}
BYTE JEnc::ComputeVLI(SHORT val)
{
BYTE binStrLen = 0;
val = abs(val);
//获取二进制码长度
if(val == 1)
{
binStrLen = 1;
}
else if(val >= 2 && val <= 3)
{
binStrLen = 2;
}
else if(val >= 4 && val <= 7)
{
binStrLen = 3;
}
else if(val >= 8 && val <= 15)
{
binStrLen = 4;
}
else if(val >= 16 && val <= 31)
{
binStrLen = 5;
}
else if(val >= 32 && val <= 63)
{
binStrLen = 6;
}
else if(val >= 64 && val <= 127)
{
binStrLen = 7;
}
else if(val >= 128 && val <= 255)
{
binStrLen = 8;
}
else if(val >= 256 && val <= 511)
{
binStrLen = 9;
}
else if(val >= 512 && val <= 1023)
{
binStrLen = 10;
}
else if(val >= 1024 && val <= 2047)
{
binStrLen = 11;
}
return binStrLen;
}
void JEnc::Invoke(long Q)
{
// 获取jpeg编码需要的bmp数据结构,jpeg要求数据缓冲区的高和宽为8或16的倍数(视采样方式而定)
BMBUFINFO bmBuffInfo = GetBMBuffSize();
imgWidth = bmBuffInfo.imgWidth; // 图像宽
imgHeight = bmBuffInfo.imgHeight; // 图像高
buffWidth = bmBuffInfo.buffWidth; // 缓冲宽
buffHeight = bmBuffInfo.buffHeight; // 缓冲高
size_t buffSize = buffHeight * buffWidth * 3; // 缓冲长度,因为是24bits,所以*3
BYTE* bmData = new BYTE[buffSize]; // 申请内存空间
GetBMData(bmData, bmBuffInfo); // 获取数据
//=====================================
// 计算编码需要的缓冲区,RGB信号需要别分别编码,所以需要3个缓冲区,这里只是1:1:1所以是一样大
size_t yuvBuffSize = buffWidth * buffHeight;
BYTE* pYBuff = new BYTE[yuvBuffSize];
BYTE* pUBuff = new BYTE[yuvBuffSize];
BYTE* pVBuff = new BYTE[yuvBuffSize];
// 将RGB信号转换为YUV信号
BGR2YUV111(bmData,pYBuff,pUBuff,pVBuff);
// 将信号分割为8x8的块
DivBuff(pYBuff, buffWidth, buffHeight, DCTSIZE, DCTSIZE );
DivBuff(pUBuff, buffWidth, buffHeight, DCTSIZE, DCTSIZE );
DivBuff(pVBuff, buffWidth, buffHeight, DCTSIZE, DCTSIZE );
SetQuantTable(std_Y_QT,YQT, Q); // 设置Y量化表
SetQuantTable(std_UV_QT,UVQT, Q); // 设置UV量化表
InitQTForAANDCT(); // 初始化AA&N需要的量化表
pVLITAB=VLI_TAB + 2047; // 设置VLI_TAB的别名
BuildVLITable(); // 计算VLI表
pOutFile = fopen("test.jpeg","wb");
// 写入各段
WriteSOI();
WriteAPP0();
WriteDQT();
WriteSOF();
WriteDHT();
WriteSOS();
// 计算Y/UV信号的交直分量的huffman表,这里使用标准的huffman表,并不是计算得出,缺点是文件略长,但是速度快
BuildSTDHuffTab(STD_DC_Y_NRCODES,STD_DC_Y_VALUES,STD_DC_Y_HT);
BuildSTDHuffTab(STD_AC_Y_NRCODES,STD_AC_Y_VALUES,STD_AC_Y_HT);
BuildSTDHuffTab(STD_DC_UV_NRCODES,STD_DC_UV_VALUES,STD_DC_UV_HT);
BuildSTDHuffTab(STD_AC_UV_NRCODES,STD_AC_UV_VALUES,STD_AC_UV_HT);
// 处理单元数据
ProcessData(pYBuff,pUBuff,pVBuff);
WriteEOI();
delete[] bmData;
}
BMBUFINFO JEnc::GetBMBuffSize()
{
BMBUFINFO bmBuffInfo;
UINT colSize = WIDTH;
UINT rowSize = HEIGHT;
bmBuffInfo.BitCount = 24;
bmBuffInfo.buffHeight = rowSize; // 缓冲区高
bmBuffInfo.buffWidth = colSize; // 缓冲区宽
bmBuffInfo.imgHeight = rowSize; // 图像高
bmBuffInfo.imgWidth = colSize; // 图像宽
return bmBuffInfo;
}
void JEnc::GetBMData(BYTE* pBuff, BMBUFINFO buffInfo)
{
UINT lineSize = buffInfo.imgWidth*3;
pOutFile=fopen("BmpData","rb");
for (int i =0; i <= buffInfo.imgHeight - 1; ++i)
{
fread(&pBuff[buffInfo.buffWidth * i * 3],lineSize,1,pOutFile);
}
}
void JEnc::BGR2YUV111(BYTE* pBuf, BYTE* pYBuff, BYTE* pUBuff, BYTE* pVBuff)
{
DOUBLE tmpY = 0; //临时变量
DOUBLE tmpU = 0;
DOUBLE tmpV = 0;
BYTE tmpB = 0;
BYTE tmpG = 0;
BYTE tmpR = 0;
UINT i = 0;
//size_t elemNum = _msize(pBuf) / 3; //缓冲长度
size_t elemNum=imgWidth*imgHeight;
for (i = 0; i < elemNum; i++)
{
tmpB = pBuf[i * 3];
tmpG = pBuf[i * 3 + 1];
tmpR = pBuf[i * 3 + 2];
tmpY = 0.299 * tmpR + 0.587 * tmpG + 0.114 * tmpB;
tmpU = -0.1687 * tmpR - 0.3313 * tmpG + 0.5 * tmpB + 128;
tmpV = 0.5 * tmpR - 0.4187 * tmpG - 0.0813 * tmpB + 128;
//if(tmpY > 255){tmpY = 255;} //输出限制
//if(tmpU > 255){tmpU = 255;}
//if(tmpV > 255){tmpV = 255;}
//if(tmpY < 0){tmpY = 0;}
//if(tmpU < 0){tmpU = 0;}
//if(tmpV < 0){tmpV = 0;}
pYBuff[i] = tmpY; //放入输入缓冲
pUBuff[i] = tmpU;
pVBuff[i] = tmpV;
}
}
void JEnc::DivBuff(BYTE* pBuf,UINT width,UINT height,UINT xLen,UINT yLen)
{
UINT xBufs = width / xLen; //X轴方向上切割数量
UINT yBufs = height / yLen; //Y轴方向上切割数量
UINT tmpBufLen = xBufs * xLen * yLen; //计算临时缓冲区长度
BYTE* tmpBuf = new BYTE[tmpBufLen]; //创建临时缓冲
UINT i = 0; //临时变量
UINT j = 0;
UINT k = 0;
UINT n = 0;
UINT bufOffset = 0; //切割开始的偏移量
for (i = 0; i < yBufs; ++i) //循环Y方向切割数量
{
n = 0; //复位临时缓冲区偏移量
for (j = 0; j < xBufs; ++j) //循环X方向切割数量
{
bufOffset = yLen * xLen * i * xBufs + j * xLen; //计算单元信号块的首行偏移量
for (k = 0; k < yLen; ++k) //循环块的行数
{
memcpy(&tmpBuf[n],&pBuf[bufOffset],xLen); //复制一行到临时缓冲
n += xLen; //计算临时缓冲区偏移量
bufOffset += width; //计算输入缓冲区偏移量
}
}
memcpy(&pBuf[i * tmpBufLen],tmpBuf,tmpBufLen); //复制临时缓冲数据到输入缓冲
}
delete[] tmpBuf; //删除临时缓冲
}
void JEnc::SetQuantTable(const BYTE* std_QT,BYTE* QT, int Q)
{
INT tmpVal = 0; //临时变量
DWORD i = 0;
if (Q < 1) Q = 1; //限制质量系数
if (Q > 100) Q = 100;
//非线性映射 1->5000, 10->500, 25->200, 50->100, 75->50, 100->0
if (Q < 50)
{
Q = 5000 / Q;
}
else
{
Q = 200 - Q * 2;
}
for (i = 0; i < DCTBLOCKSIZE; ++i)
{
tmpVal = (std_QT[i] * Q + 50L) / 100L;
if (tmpVal < 1) //数值范围限定
{
tmpVal = 1L;
}
if (tmpVal > 255)
{
tmpVal = 255L;
}
QT[FZBT[i]] = static_cast<BYTE>(tmpVal);
}
}
void JEnc::InitQTForAANDCT()
{
UINT i = 0; //临时变量
UINT j = 0;
UINT k = 0;
for (i = 0; i < DCTSIZE; i++) //初始化亮度信号量化表
{
for (j = 0; j < DCTSIZE; j++)
{
YQT_DCT[k] = (FLOAT) (1.0 / ((DOUBLE) YQT[FZBT[k]] *
aanScaleFactor[i] * aanScaleFactor[j] * 8.0));
++k;
}
}
k = 0;
for (i = 0; i < DCTSIZE; i++) //初始化色差信号量化表
{
for (j = 0; j < DCTSIZE; j++)
{
UVQT_DCT[k] = (FLOAT) (1.0 / ((DOUBLE) UVQT[FZBT[k]] *
aanScaleFactor[i] * aanScaleFactor[j] * 8.0));
++k;
}
}
}
void JEnc::WriteSOI(void)
{
fwrite(&SOITAG,sizeof(SOITAG),1,this->pOutFile);
}
void JEnc::WriteAPP0(void)
{
JPEGAPP0 APP0;
APP0.segmentTag = 0xE0FF;
APP0.length = 0x1000;
APP0.id[0] = 'J';
APP0.id[1] = 'F';
APP0.id[2] = 'I';
APP0.id[3] = 'F';
APP0.id[4] = 0;
APP0.ver = 0x0101;
APP0.densityUnit = 0x00;
APP0.densityX = 0x0100;
APP0.densityY = 0x0100;
APP0.thp = 0x00;
APP0.tvp = 0x00;
fwrite(&APP0,sizeof(APP0),1,this->pOutFile);
}
void JEnc::WriteDQT(void)
{
UINT i = 0;
JPEGDQT_8BITS DQT_Y;
DQT_Y.segmentTag = 0xDBFF;
DQT_Y.length = 0x4300;
DQT_Y.tableInfo = 0x00;
for (i = 0; i < DCTBLOCKSIZE; i++)
{
DQT_Y.table[i] = YQT[i];
}
fwrite(&DQT_Y,sizeof(DQT_Y),1,this->pOutFile);
DQT_Y.tableInfo = 0x01;
for (i = 0; i < DCTBLOCKSIZE; i++)
{
DQT_Y.table[i] = UVQT[i];
}
fwrite(&DQT_Y,sizeof(DQT_Y),1,this->pOutFile);
}
void JEnc::WriteSOF(void)
{
JPEGSOF0_24BITS SOF;
SOF.segmentTag = 0xC0FF;
SOF.length = 0x1100;
SOF.precision = 0x08;
SOF.height = Intel2Moto(USHORT(this->imgHeight));
SOF.width = Intel2Moto(USHORT(this->imgWidth));
SOF.sigNum = 0x03;
SOF.YID = 0x01;
SOF.QTY = 0x00;
SOF.UID = 0x02;
SOF.QTU = 0x01;
SOF.VID = 0x03;
SOF.QTV = 0x01;
SOF.HVU = 0x11;
SOF.HVV = 0x11;
/*switch (this->SamplingType)
{
case 1:
SOF.HVY = 0x11;
break;
case 2:
SOF.HVY = 0x12;
break;
case 3:
SOF.HVY = 0x21;
break;
case 4:
SOF.HVY = 0x22;
break;
}*/
SOF.HVY = 0x11;
fwrite(&SOF,sizeof(SOF),1,this->pOutFile);
}
void JEnc::WriteDHT(void)
{
UINT i = 0;
JPEGDHT DHT;
DHT.segmentTag = 0xC4FF;
DHT.length = Intel2Moto(19 + 12);
DHT.tableInfo = 0x00;
for (i = 0; i < 16; i++)
{
DHT.huffCode[i] = STD_DC_Y_NRCODES[i + 1];
}
fwrite(&DHT,sizeof(DHT),1,this->pOutFile);
for (i = 0; i <= 11; i++)
{
WriteByte(STD_DC_Y_VALUES[i]);
}
//------------------------------------------------
DHT.tableInfo = 0x01;
for (i = 0; i < 16; i++)
{
DHT.huffCode[i] = STD_DC_UV_NRCODES[i + 1];
}
fwrite(&DHT,sizeof(DHT),1,this->pOutFile);
for (i = 0; i <= 11; i++)
{
WriteByte(STD_DC_UV_VALUES[i]);
}
//----------------------------------------------------
DHT.length = Intel2Moto(19 + 162);
DHT.tableInfo = 0x10;
for (i = 0; i < 16; i++)
{
DHT.huffCode[i] = STD_AC_Y_NRCODES[i + 1];
}
fwrite(&DHT,sizeof(DHT),1,this->pOutFile);
for (i = 0; i <= 161; i++)
{
WriteByte(STD_AC_Y_VALUES[i]);
}
//-----------------------------------------------------
DHT.tableInfo = 0x11;
for (i = 0; i < 16; i++)
{
DHT.huffCode[i] = STD_AC_UV_NRCODES[i + 1];
}
fwrite(&DHT,sizeof(DHT),1,this->pOutFile);
for (i = 0; i <= 161; i++)
{
WriteByte(STD_AC_UV_VALUES[i]);
}
}
void JEnc::WriteSOS(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -