//jenc.cpp
/*
这是一个简单的jpeg编码程序,支持1:1:1采样的baseline彩色jpeg,输入只能是24bit的BMP文件
代码结构只求能说明各步骤过程,并不做特别的优化,效率较为一般。jpeg的色彩是采用YCrCb模式
的,所以从BMP到jpeg要经过YUV的转换。
*/
#include "jenc.h"
// 存放VLI表
BYTE VLI_TAB[4096];
BYTE* pVLITAB; //VLI_TAB的别名,使下标在-2048-2048
// 存放2个量化表
BYTE YQT[DCTBLOCKSIZE];
BYTE UVQT[DCTBLOCKSIZE];
// 存放2个FDCT变换要求格式的量化表
FLOAT YQT_DCT[DCTBLOCKSIZE];
FLOAT UVQT_DCT[DCTBLOCKSIZE];
//存放4个Huffman表
HUFFCODE STD_DC_Y_HT[12];
HUFFCODE STD_DC_UV_HT[12];
HUFFCODE STD_AC_Y_HT[256];
HUFFCODE STD_AC_UV_HT[256];
// bmFile:输入文件
// jpgFile:输出文件
// Q:质量
void JEnc::Invoke(string bmFile, string jpgFile, long Q)
{
FILE* pFile; // 输入文件句柄
if ((pFile = fopen(bmFile.c_str(),"rb")) == NULL) // 打开文件
{
throw("open bmp file error.");
}
// 获取jpeg编码需要的bmp数据结构,jpeg要求数据缓冲区的高和宽为8或16的倍数(视采样方式而定)
BMBUFINFO bmBuffInfo = GetBMBuffSize(pFile);
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(pFile, bmData, bmBuffInfo); // 获取数据
fclose(pFile); // 关闭文件
//=====================================
// 计算编码需要的缓冲区,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(jpgFile.c_str(),"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();
fclose(pOutFile);
delete[] bmData;
}
// 获取BMP文件输出缓冲区信息
BMBUFINFO JEnc::GetBMBuffSize(FILE* pFile)
{
BITMAPFILEHEADER bmHead; //文件头信息块
BITMAPINFOHEADER bmInfo; //图像描述信息块
BMBUFINFO bmBuffInfo;
UINT colSize = 0;
UINT rowSize = 0;
fseek(pFile,0,SEEK_SET); //将读写指针指向文件头部
fread(&bmHead,sizeof(bmHead),1,pFile); //读取文件头信息块
fread(&bmInfo,sizeof(bmInfo),1,pFile); //读取位图信息块
// 计算填充后列数,jpeg编码要求缓冲区的高和宽为8或16的倍数
if (bmInfo.biWidth % 8 == 0)
{
colSize = bmInfo.biWidth;
}
else
{
colSize = bmInfo.biWidth + 8 - (bmInfo.biWidth % 8);
}
// 计算填充后行数
if (bmInfo.biHeight % 8 == 0)
{
rowSize = bmInfo.biHeight;
}
else
{
rowSize = bmInfo.biHeight + 8 - (bmInfo.biHeight % 8);
}
bmBuffInfo.BitCount = 24;
bmBuffInfo.buffHeight = rowSize; // 缓冲区高
bmBuffInfo.buffWidth = colSize; // 缓冲区宽
bmBuffInfo.imgHeight = bmInfo.biHeight; // 图像高
bmBuffInfo.imgWidth = bmInfo.biWidth; // 图像宽
return bmBuffInfo;
}
// 获取图像数据
void JEnc::GetBMData(FILE* pFile, BYTE* pBuff, BMBUFINFO buffInfo)
{
BITMAPFILEHEADER bmHead; // 文件头信息块
BITMAPINFOHEADER bmInfo; // 图像描述信息块
size_t dataLen = 0; // 文件数据区长度
long alignBytes = 0; // 为对齐4字节需要补足的字节数
UINT lineSize = 0;
fseek(pFile,0,SEEK_SET); // 将读写指针指向文件头部
fread(&bmHead,sizeof(bmHead),1,pFile); // 读取文件头信息块
fread(&bmInfo,sizeof(bmInfo),1,pFile); // 读取位图信息块
//计算对齐的字节数
alignBytes = (((bmInfo.biWidth * bmInfo.biBitCount) + 31) & ~31) / 8L
- (bmInfo.biWidth * bmInfo.biBitCount) / 8L; // 计算图象文件数据段行补齐字节数
//计算数据缓冲区长度
lineSize = bmInfo.biWidth * 3;
// 因为bmp文件数据是倒置的所以从最后一行开始读
for (int i = bmInfo.biHeight - 1; i >= 0; --i)
{
fread(&pBuff[buffInfo.buffWidth * i * 3],lineSize,1,pFile);
fseek(pFile,alignBytes,SEEK_CUR); // 跳过对齐字节
}
}
// 转换色彩空间BGR-YUV,111采样
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; //缓冲长度
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;
}
}
//********************************************************************
// 方法名称:DivBuff
// 最后修订日期:2003.5.3
//
// 参数说明:
// lpBuf:输入缓冲,处理后的数据也存储在这里
// width:缓冲X方向长度
// height:缓冲Y方向长度
// xLen:X方向切割长度
// yLen:Y方向切割长度
//********************************************************************
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; //删除临时缓冲
}
//********************************************************************
// 方法名称:SetQuantTable
//
// 方法说明:根据所需质量设置量化表
//
// 参数说明:
// std_QT:标准量化表
// QT:输出量化表
// Q:质量参数
//***
pathuang68
- 粉丝: 1820
- 资源: 15
最新资源
- 直流微电网设计(MATLAB SIMULINK源码) 本项目试图研究由风能、光伏电源和电池三种能源组成的混合系统 三个能源中的每一个都可以向负载提供源源不断的电源 讨论了直流微电网中利用太阳能和风
- 基于多时间尺度的冷热电联供综合能源系统优化调度模型 摘要:代码主要做的是冷热电联供综合能源微网的多时间尺度优化问题,其中,日前计划中通过多场景描述可再生能源的不确定性,侧重于一个运行优化周期内 综合能
- 多目标人工秃鹫优化算法(MATLAB源码分享,智能优化算法) 提出了一种多目标版本的人工秃鹫优化算法(AVOA),用于多目标优化问题 AVOA的灵感来源于非洲秃鹫的生活方式 档案、网格和领导者选择
- 最新微信拼车打车程序,完整无错直接运营版,对接微信支付
- 基于copula的风光联合场景生成代码 该代码考虑风电和光伏出力的空间相关性生成联合场景,用于风光不确定性分析,为配置规划调度提供基础,地理位置相近的风电机组和光伏机组具有极大的相关性
- C++、MFC制作的图像处理工具,包括图像灰度、采样、量化、灰度直方图、灰度线性变化、灰度非线性变化、阈值化、均衡化处理等 -2025
- MATLAB代码:分布式最优潮流 关键词:网络划分;分布式光伏;集群电压控制;分布式优化;有功缩减 参考文档:《含分布式光伏的配电网集群划分和集群电压协调控制》 仿真平台:MATLAB 主要内容:本文
- 3D视觉上传一个报告类资源
- 基于opencv和MFC的图像处理软件,图像的灰度化、二值化、滤波、边缘检测、直方图,视频的边缘检测和跟踪-2025
- Python-tslearn专用于时间序列数据的机器学习Python工具包
- 具备VSG功能的逆变器仿真模型,同步发电机,构网型逆变器,基于MATLAB Simulink建模仿真 具备一次调频,惯性阻尼,一次调压 可以运行于离网模式和并网模式 仿真模型使用MATLAB 2
- Video-2024-09-19晚上-教学案例课(1).wmv
- 基于人工神经网络的系统辩识(MATLAB源码分享) 该示例文件显示了使用高斯白噪声下2DOF系统的人工神经网络(ANN)进行系统辩识 神经网络由输入层,输出层,隐藏层组成: -输入层:2个节点使用当
- 毕业设计:交通信息网上查询系统的设计与实现(源代码+论文+开题报告)
- 基于C++ MFC实现的五子棋游戏,包括棋盘棋子绘制、输赢判定、新游戏、悔棋和修改棋盘背景样式等功能 .zip
- 大一的C++课程项目,使用MFC框架搭建外卖平台,实现买、卖、计算路径送货、签收等核心功能-2025
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
- 1
- 2
- 3
前往页