libjpeg的使用及jpg图片的提取

显存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;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libjpeg是一个开源的JPEG图像压缩和解压缩库。它提供了一些函数,用于将JPEG格式图像转换为RGB格式图像。 首先,我们需要加载JPEG图像,并使用libjpeg的函数进行解压缩。我们可以使用`jpeg_create_decompress()`函数创建一个空的解压对象,并使用`jpeg_stdio_src()`函数将JPEG图像文件指定为输入源。 接下来,我们需要使用`jpeg_read_header()`函数读取JPEG图像文件的头信息,并使用`jpeg_start_decompress()`函数开始解压缩过程。然后,我们可以使用`jpeg_read_scanlines()`函数逐行读取解压缩后的图像数据。 由于RGB格式图像由红色、绿色和蓝色三个颜色通道组成,我们需要创建一个数组来存储解压缩后的RGB图像数据。对于每一行数据,我们可以使用`jpeg_read_scanlines()`函数将解压缩后的数据存储到数组中。 最后,我们需要使用`jpeg_finish_decompress()`函数完成解压缩过程,并使用`jpeg_destroy_decompress()`函数销毁解压对象。此时,我们已经成功将JPEG图像转换为RGB格式图像。 在使用libjpeg进行图像转换时,我们需要注意一些细节,如输入图像的路径、图像的尺寸和颜色空间等。此外,libjpeg还提供了一些其他函数,用于处理JPEG图像的压缩和处理。 总结起来,libjpeg是一个强大的图像处理库,它可以方便地将JPEG格式图像转换为RGB格式图像。通过使用它提供的函数,我们可以轻松地实现这一转换过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值