显存framebuffer中存放的是像素的RGB数据,jpg格式的图片是压缩的格式,用libjpeg把jpg图片解压为RGB原始数据。libjpeg是使用C语言实现的读、写JPEG文件的库,使用libjpeg的应用程序是以”scanline”为单位进行图像处理的。转换速度和质量可以平衡。
libjpeg处理的图片一般是矩形,矩形里是一行行数据,一行数据为”scanline”。每行数据是一个个像素,像素的值由component单元组成,RGB有三个component,灰度值有一个component。图片信息相当于一个二维数组,压缩是把二维数组压缩为一个jpeg图片,解压是把jpeg图片恢复为二维数组。
步骤:
1.分配和初始化一个decompression(解压结构体)对象 tDInfo
2.指定源文件
3.用jpeg_read_header获得jpg图片信息
4.设置解压参数,比如放大、缩小
5.启动解压:jpeg_start_decompress(…)
while( scan lines remain to be read)
6.循环调用jpeg_read_scanlines(…)
7.jpeg_finish_decompress(…)
8.释放decompress结构体
程序是参考libjpeg库的官方文档及示例。
static int GetPixelDatasFrmJPG(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
jpeg_read_header获得头文件信息,tDInfo结构体中含有图片格式信息(如image_width源宽,image_height源高,num_components源单元数,设置解压参数如放大缩小scale_num分子,scale_denom分母,启动解压后可获得output_width输出宽,output_height输出高,output_components输出单元数,若不放大缩小源和输出格式一致),循环调用jpeg_read_scanlines来一行行获得解压数据,并存入ptPixelDatas结构体。
一、交叉编译libjpeg
tar xzf libjpeg-turbo-1.2.1.tar.gz
cd libjpeg-turbo-1.2.1
./configure --prefix=/work/projects/13.libjpeg/libjpeg-turbo-1.2.1/tmp/ --host=arm-linux
make
make install
二、交叉编译jpg2rgb.c
2.1 指定头文件和库文件目录
arm-linux-gcc -o jpg2rgb jpg2rgb.c -I /work/projects/libjpeg-turbo-1.2.1/tmp/include -L /work/projects/libjpeg-turbo-1.2.1/tmp/lib -ljpeg
或者2.2 把头文件和库文件复制到相应目录
jpg.c中完成PicFileParser结构体(图片文件解析模块结构体),并向上注册,由picfmt_manager.c函数通过链表管理该结构体,重要的是通过该文件解析jpg格式图片得到PixelDatas结构体。
static T_PicFileParser g_tJPGParser = {
.name = "jpg",
.isSupport = isJPGFormat, //JPG模块是否支持该文件,即该文件是否为JPG文件
.GetPixelDatas = GetPixelDatasFrmJPG, //把JPG文件中的图像数据,取出并转换为能在显示设备上使用的格式
.FreePixelDatas = FreePixelDatasForJPG, //GetPixelDatasFrmJPG的反函数,把象素数据所占内存释放掉
};
JPG模块是否支持该文件,即该文件是否为JPG文件
static int isJPGFormat(PT_FileMap ptFileMap){
struct jpeg_decompress_struct tDInfo;
/* 默认的错误处理函数是让程序退出
* 我们参考libjpeg里的bmp.c编写自己的错误处理函数*/
T_MyErrorMgr tJerr;
int iRet;
fseek(ptFileMap->tFp, 0, SEEK_SET);
// 分配和初始化一个decompression结构体
tDInfo.err = jpeg_std_error(&tJerr.pub);
tJerr.pub.error_exit = MyErrorExit;
if(setjmp(tJerr.setjmp_buffer)){
/* 如果程序能运行到这里, 表示JPEG解码出错 */
jpeg_destroy_decompress(&tDInfo);
return 0;;
}
jpeg_create_decompress(&tDInfo);
jpeg_stdio_src(&tDInfo, ptFileMap->tFp); //指定源文件
iRet = jpeg_read_header(&tDInfo, TRUE); //用jpeg_read_header获得jpg信息
jpeg_abort_decompress(&tDInfo);
return (iRet == JPEG_HEADER_OK);
}
把JPG文件中的图像数据,取出并转换为能在显示设备上使用的格式,参数为图片文件,和PixelDatas结构体,其中PixelDatas结构体的源bpp为输入参数,其它为保存输出结果。
static int GetPixelDatasFrmJPG(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas){
struct jpeg_decompress_struct tDInfo;
int iRet;
int iRowStride;
unsigned char *aucLineBuffer = NULL;
unsigned char *pucDest;
T_MyErrorMgr tJerr;
fseek(ptFileMap->tFp, 0, SEEK_SET);
// 分配和初始化一个decompression结构体
tDInfo.err = jpeg_std_error(&tJerr.pub);
tJerr.pub.error_exit = MyErrorExit;
if(setjmp(tJerr.setjmp_buffer)){
/* 如果程序能运行到这里, 表示JPEG解码出错 */
jpeg_destroy_decompress(&tDInfo);
if (aucLineBuffer){
free(aucLineBuffer);
}
if (ptPixelDatas->aucPixelDatas){
free(ptPixelDatas->aucPixelDatas);
}
return -1;
}
jpeg_create_decompress(&tDInfo);
jpeg_stdio_src(&tDInfo, ptFileMap->tFp); //指定源文件
iRet = jpeg_read_header(&tDInfo, TRUE); // 获得jpg信息
tDInfo.scale_num = tDInfo.scale_denom = 1; // 设置解压参数,比如放大、缩小
jpeg_start_decompress(&tDInfo); // 启动解压
// 一行的数据长度:输出宽度像素*每个像素的单元数(每个单元8位表示)
//aucLineBuffer为分配的行缓存,因为图片是一行行解析的,解析得到的一行RGB数据存放在行缓存中
//在循环中将每次得到的行缓存数据存放到PixelDatas结构体的缓存中
iRowStride = tDInfo.output_width * tDInfo.output_components;
aucLineBuffer = malloc(iRowStride);
// 设置PixelDatas结构体信息
ptPixelDatas->iWidth = tDInfo.output_width; //图片宽度
ptPixelDatas->iHeight = tDInfo.output_height; //图片高度
ptPixelDatas->iLineBytes = ptPixelDatas->iWidth * ptPixelDatas->iBpp / 8; //图片一行字节数
ptPixelDatas->iTotalBytes = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes; //图片总字节数
ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes); //图片RGB数据存放地址
pucDest = ptPixelDatas->aucPixelDatas; //目的:图片RGB数据存放地址
// 循环调用jpeg_read_scanlines来一行一行地获得解压的数据,存放在aucLineBuffer行缓存
while (tDInfo.output_scanline < tDInfo.output_height) {
/* 得到一行数据,里面的颜色格式为0xRR, 0xGG, 0xBB */
(void) jpeg_read_scanlines(&tDInfo, &aucLineBuffer, 1);
// 将解压的每行aucLineBuffer内容转到ptPixelDatas的图片存放地址处,源bpp为3单元24位,目的bpp在为函数参数
CovertOneLine(ptPixelDatas->iWidth, 24, ptPixelDatas->iBpp, aucLineBuffer, pucDest);
pucDest += ptPixelDatas->iLineBytes; //目的地址加上一行长度
}
free(aucLineBuffer); //释放行缓存
jpeg_finish_decompress(&tDInfo); //完成解压
jpeg_destroy_decompress(&tDInfo); //释放decompress结构体
return 0;
}
GetPixelDatasFrmJPG的反函数,把象素数据所占内存释放掉
static int FreePixelDatasForJPG(PT_PixelDatas ptPixelDatas){
free(ptPixelDatas->aucPixelDatas);
return 0;
}
把已经从JPG文件取出的一行象素数据,转换为能在显示设备上使用的格式,可以转换bpp,源bpp为3单元24位。
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas){
unsigned int dwRed,dwGreen,dwBlue; //红绿蓝三单元
unsigned int dwColor;
unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas; //16bpp目的
unsigned int *pwDstDatas32bpp = (unsigned int *)pudDstDatas; //32bpp目的
int i;
int pos = 0; //源起始地址
if (iDstBpp == 24) //源bpp为3单元24位
memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
else{
for (i = 0; i < iWidth; i++){
dwRed = pudSrcDatas[pos++]; //获取源的红绿蓝三单元颜色数据
dwGreen = pudSrcDatas[pos++];
dwBlue = pudSrcDatas[pos++];
if (iDstBpp == 32){
dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue; //红绿蓝分别占8位
*pwDstDatas32bpp = dwColor;
pwDstDatas32bpp++;
}
else if (iDstBpp == 16){ /* 565 */
dwRed = dwRed >> 3;
dwGreen = dwGreen >> 2;
dwBlue = dwBlue >> 3;
dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue); //红绿蓝占565位
*pwDstDatas16bpp = dwColor;
pwDstDatas16bpp++;
}
}
}
return 0;
}