JPEG图像的压缩与解压缩解读.docx
《JPEG图像的压缩与解压缩解读.docx》由会员分享,可在线阅读,更多相关《JPEG图像的压缩与解压缩解读.docx(13页珍藏版)》请在冰豆网上搜索。
JPEG图像的压缩与解压缩解读
JPEG压缩操作过程
1.为JPEG对象分配空间并初始化
2.指定图像输出目标
3.为压缩设定参数,包括图像大小,颜色空间
4.开始压缩
5.写入数据
6.压缩完毕
7.释放资源
为JPEG对象分配空间并初始化
压缩过程中使用的JPEG对象是一个jpeg_compress_struct的结构体。
同时还需要定义一个用于错误处理的结构体对象,IJG中标准的错误结构体是jpeg_error_mgr。
structjpeg_compress_structcinfo;
structjpeg_error_mgrjerr;
然后是将错误处理结构对象绑定在JPEG对象上。
cinfo.err=jpeg_std_error(&jerr);
这个标准的错误处理结构将使程序在出现错误时调用exit()退出程序,如果不希望使用标准的错误处理方式,则可以通过自定义退出函数的方法自定义错误处理结构,详情见文章后面的专门章节。
初始化cinfo结构。
jpeg_create_compress(&cinfo);
指定图像输出目标
利用标准C中的文件指针传递要输出的jpg文件。
FILE*outfile;
if((outfile=fopen(filename,"wb"))==NULL)
{
return0;
}
jpeg_stdio_dest(&cinfo,outfile);
为压缩设定参数
在开始压缩数据之前需要为压缩指定几个参数和缺省参数。
设定缺省参数之前需要指定的几个参数是:
图像宽度cinfo.image_width,图像高度cinfo.image_height,图像的颜色通道数cinfo.input_components(比如RGB图像为3,灰度图为1),图像颜色空间cinfo.in_color_space(比如真彩色JCS_RGB,灰度图JCS_GRAYSCALE)。
如:
cinfo.image_width=800;
cinfo.image_height=600;
cinfo.input_components=3;
cinfo.in_color_space=JCS_RGB;//JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像
然后是设定缺省设置
jpeg_set_defaults(&cinfo);
注意此处,在setdefault之前,必须设定in_color_space,因为某些缺省参数的设定需要正确的colorspace值。
在此之后还可以对其他的一些参数进行设定。
具体有哪些参数可以查询libjpeg.doc文档。
比如最常用的一个参数就是压缩比。
jpeg_set_quality(&cinfo,quality,TRUE);
quality是个0~100之间的整数,表示压缩比率。
开始压缩
根据设定的压缩参数进行图像压缩操作。
jpeg_start_compress(&cinfo,TRUE);
开始压缩过程后就不可以修改cinfo对象参数。
写入数据
row_stride=image_width*3;//假设用到的图示RGB真彩色三通道
同上文介绍的解压缩操作中介绍的,要写入的数据是按照行写入的,数据像素按照scanline来存储,与读取数据的不同是使用jpeg_write_scanlines。
类似于解压缩操作中的cinfo.output_scanline在此,假设image_buffer是个JSAMPARRAY类型变量,其中保存的是要输出的图像数据,比如可以是用上文中的解压缩操作从某JPEG文件中获得的数据。JSAMPROWrow_pointer;while(cinfo.next_scanline{//找到图像中的某一行,写入目标文件row_pointer=image_buffer[cinfo.next_scanline];(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);}压缩完毕jpeg_finish_compress(&cinfo);释放资源fclose(outfile);jpeg_destroy_compress(&cinfo);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_compress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_compress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_compress_structcinfo;structjpeg_error_mgrjerr;FILE*outfile;JSAMPROWrow_pointer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_compress(&cinfo);//指定目标图像文件if((outfile=fopen("dest.jpg","wb"))==NULL){return;}jpeg_stdio_dest(&cinfo,outfile);//设定压缩参数cinfo.image_width=image_width;cinfo.image_height=image_height;cinfo.input_components=3;cinfo.in_color_space=JCS_RGB;jpeg_set_defaults(&cinfo);//此处设压缩比为90%jpeg_set_quality(&cinfo,90,TRUE);//开始压缩jpeg_start_compress(&cinfo,TRUE);//假设使用的是RGB图像row_stride=image_width*3;//写入数据while(cinfo.next_scanline{row_pointer=image_buffer[cinfo.next_scanline];(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);}//压缩完毕jpeg_finish_compress(&cinfo);//释放资源fclose(outfile);jpeg_destroy_compress(&cinfo);错误处理在使用默认错误处理结构jpeg_error_mgr的情况下,程序在遇到错误后将调用exit直接退出程序,用户如果不希望使用这种直接退出的方式处理错误的话就需要自定义错误处理结构。依照example.c中的例子,IJG推荐使用C语言的setjmp和longjmp机制来重写错误处理结构。首先,需要定义一个包含标准错误处理结构类型变量的自定义结构。同时,程序将需要引入头文件setjmp.h。#includestructmy_error_mgr{structjpeg_error_mgrpub;jmp_bufsetjmp_buffer;};typedefstructmy_error_mgr*my_error_ptr;以及一个错误处理函数。在出现错误时程序将跳转到本函数中,而本函数将跳转到setjmp设定的程序位置。METHODDEF(void)my_error_exit(j_common_ptrcinfo){my_error_ptrmyerr=(my_error_ptr)cinfo->err;(*cinfo->err->output_message)(cinfo);longjmp(myerr->setjmp_buffer,1);}解压缩操作过程1.为JPEG对象分配空间并初始化2.指定解压缩数据源3.获取文件信息4.为解压缩设定参数,包括图像大小,颜色空间5.开始解压缩6.取出数据7.解压缩完毕8.释放资源为JPEG对象分配空间并初始化解压缩过程中使用的JPEG对象是一个jpeg_decompress_struct的结构体。同时还需要定义一个用于错误处理的结构体对象,IJG中标准的错误结构体是jpeg_error_mgr。structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;然后是将错误处理结构对象绑定在JPEG对象上。cinfo.err=jpeg_std_error(&jerr);这个标准的错误处理结构将使程序在出现错误时调用exit()退出程序,如果不希望使用标准的错误处理方式,则可以通过自定义退出函数的方法自定义错误处理结构,详情见文章后面的专门章节。初始化cinfo结构。jpeg_create_decompress(&cinfo);指定解压缩数据源利用标准C中的文件指针传递要打开的jpg文件。FILE*infile;if((infile=fopen("sample.jpg","rb"))==NULL){return0;}jpeg_stdio_src(&cinfo,infile);获取文件信息IJG将图像的缺省信息填充到cinfo结构中以便程序使用。(void)jpeg_read_header(&cinfo,TRUE);此时,常见的可用信息包括图像的宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等。为解压缩设定参数在完成jpeg_read_header调用后,开始解压缩之前就可以进行解压缩参数的设定,也就是为cinfo结构的成员赋值。比如可以设定解出来的图像的大小,也就是与原图的比例。使用scale_num和scale_denom两个参数,解出来的图像大小就是scale_num/scale_denom,但是IJG当前仅支持1/1,1/2,1/4,和1/8这几种缩小比例。比如要取得1/2原图的图像,需要如下设定:cinfo.scale_num=1;cinfo.scale_denom=2;也可以设定输出图像的色彩空间,即cinfo.out_color_space,可以把一个原本彩色的图像由真彩色JCS_RGB变为灰度JCS_GRAYSCALE。如:cinfo.out_color_space=JCS_GRAYSCALE;开始解压缩根据设定的解压缩参数进行图像解压缩操作。(void)jpeg_start_decompress(&cinfo);在完成解压缩操作后,IJG就会将解压后的图像信息填充至cinfo结构中。比如,输出图像宽度cinfo.output_width,输出图像高度cinfo.output_height,每个像素中的颜色通道数cinfo.output_components(比如灰度为1,全彩色为3)等。一般情况下,这些参数是在jpeg_start_decompress后才被填充到cinfo中的,如果希望在调用jpeg_start_decompress之前就获得这些参数,可以通过调用jpeg_calc_output_dimensions()的方法来实现。取出数据解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素对应的各颜色或灰度通道数据是依次存储,比如一个24-bitRGB真彩色的图像中,一个scanline中的数据存储模式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsignedchar,定义于jmorecfg.h中。除了JSAMPLE,IJG还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。在此,我们定义一个JSAMPARRAY类型的缓冲区变量来存放图像数据。JSAMPARRAYbuffer;然后是计算每行需要的空间大小,比如RGB图像就是宽度×3,灰度图就是宽度×1row_stride=cinfo.output_width*cinfo.output_components;为缓冲区分配空间,这里使用了IJG的内存管理器来完成分配。JPOOL_IMAGE表示分配的内存空间将在调用jpeg_finish_compress,jpeg_finish_decompress,jpeg_abort后被释放,而如果此参数改为JPOOL_PERMANENT则表示内存将一直到JPEG对象被销毁时才被释放。row_stride如上所说,是每行数据的实际大小。最后一个参数是要分配多少行数据。此处只分配了一行。buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);output_scanline表示当前已经读取的行数,如此即可依次读出图像的所有数据,并填充到缓冲区中,参数1表示的是每次读取的行数。while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//dosomething}解压缩完毕(void)jpeg_finish_decompress(&cinfo);释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_decompress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_decompress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;FILE*infile;JSAMPARRAYbuffer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_decompress(&cinfo);//指定图像文件if((infile=fopen("sample.jpg","rb"))==NULL){return;}jpeg_stdio_src(&cinfo,infile);//读取图像信息(void)jpeg_read_header(&cinfo,TRUE);//设定解压缩参数,此处我们将图像长宽缩小为原图的1/2cinfo.scale_num=1;cinfo.scale_denom=2;//开始解压缩图像(void)jpeg_start_decompress(&cinfo);//本程序功能是应用GDI+在客户区绘制图像CClientDCdc(this);Bitmapbm(cinfo.output_width,cinfo.output_height);Graphicsgraphics(dc.GetSafeHdc());Graphicsgdc(&bm);//分配缓冲区空间row_stride=cinfo.output_width*cinfo.output_components;buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);//读取数据while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//output_scanline是从1开始,所以需要减1intline=cinfo.output_scanline-1;for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
在此,假设image_buffer是个JSAMPARRAY类型变量,其中保存的是要输出的图像数据,比如可以是用上文中的解压缩操作从某JPEG文件中获得的数据。
JSAMPROWrow_pointer;
while(cinfo.next_scanline{//找到图像中的某一行,写入目标文件row_pointer=image_buffer[cinfo.next_scanline];(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);}压缩完毕jpeg_finish_compress(&cinfo);释放资源fclose(outfile);jpeg_destroy_compress(&cinfo);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_compress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_compress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_compress_structcinfo;structjpeg_error_mgrjerr;FILE*outfile;JSAMPROWrow_pointer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_compress(&cinfo);//指定目标图像文件if((outfile=fopen("dest.jpg","wb"))==NULL){return;}jpeg_stdio_dest(&cinfo,outfile);//设定压缩参数cinfo.image_width=image_width;cinfo.image_height=image_height;cinfo.input_components=3;cinfo.in_color_space=JCS_RGB;jpeg_set_defaults(&cinfo);//此处设压缩比为90%jpeg_set_quality(&cinfo,90,TRUE);//开始压缩jpeg_start_compress(&cinfo,TRUE);//假设使用的是RGB图像row_stride=image_width*3;//写入数据while(cinfo.next_scanline{row_pointer=image_buffer[cinfo.next_scanline];(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);}//压缩完毕jpeg_finish_compress(&cinfo);//释放资源fclose(outfile);jpeg_destroy_compress(&cinfo);错误处理在使用默认错误处理结构jpeg_error_mgr的情况下,程序在遇到错误后将调用exit直接退出程序,用户如果不希望使用这种直接退出的方式处理错误的话就需要自定义错误处理结构。依照example.c中的例子,IJG推荐使用C语言的setjmp和longjmp机制来重写错误处理结构。首先,需要定义一个包含标准错误处理结构类型变量的自定义结构。同时,程序将需要引入头文件setjmp.h。#includestructmy_error_mgr{structjpeg_error_mgrpub;jmp_bufsetjmp_buffer;};typedefstructmy_error_mgr*my_error_ptr;以及一个错误处理函数。在出现错误时程序将跳转到本函数中,而本函数将跳转到setjmp设定的程序位置。METHODDEF(void)my_error_exit(j_common_ptrcinfo){my_error_ptrmyerr=(my_error_ptr)cinfo->err;(*cinfo->err->output_message)(cinfo);longjmp(myerr->setjmp_buffer,1);}解压缩操作过程1.为JPEG对象分配空间并初始化2.指定解压缩数据源3.获取文件信息4.为解压缩设定参数,包括图像大小,颜色空间5.开始解压缩6.取出数据7.解压缩完毕8.释放资源为JPEG对象分配空间并初始化解压缩过程中使用的JPEG对象是一个jpeg_decompress_struct的结构体。同时还需要定义一个用于错误处理的结构体对象,IJG中标准的错误结构体是jpeg_error_mgr。structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;然后是将错误处理结构对象绑定在JPEG对象上。cinfo.err=jpeg_std_error(&jerr);这个标准的错误处理结构将使程序在出现错误时调用exit()退出程序,如果不希望使用标准的错误处理方式,则可以通过自定义退出函数的方法自定义错误处理结构,详情见文章后面的专门章节。初始化cinfo结构。jpeg_create_decompress(&cinfo);指定解压缩数据源利用标准C中的文件指针传递要打开的jpg文件。FILE*infile;if((infile=fopen("sample.jpg","rb"))==NULL){return0;}jpeg_stdio_src(&cinfo,infile);获取文件信息IJG将图像的缺省信息填充到cinfo结构中以便程序使用。(void)jpeg_read_header(&cinfo,TRUE);此时,常见的可用信息包括图像的宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等。为解压缩设定参数在完成jpeg_read_header调用后,开始解压缩之前就可以进行解压缩参数的设定,也就是为cinfo结构的成员赋值。比如可以设定解出来的图像的大小,也就是与原图的比例。使用scale_num和scale_denom两个参数,解出来的图像大小就是scale_num/scale_denom,但是IJG当前仅支持1/1,1/2,1/4,和1/8这几种缩小比例。比如要取得1/2原图的图像,需要如下设定:cinfo.scale_num=1;cinfo.scale_denom=2;也可以设定输出图像的色彩空间,即cinfo.out_color_space,可以把一个原本彩色的图像由真彩色JCS_RGB变为灰度JCS_GRAYSCALE。如:cinfo.out_color_space=JCS_GRAYSCALE;开始解压缩根据设定的解压缩参数进行图像解压缩操作。(void)jpeg_start_decompress(&cinfo);在完成解压缩操作后,IJG就会将解压后的图像信息填充至cinfo结构中。比如,输出图像宽度cinfo.output_width,输出图像高度cinfo.output_height,每个像素中的颜色通道数cinfo.output_components(比如灰度为1,全彩色为3)等。一般情况下,这些参数是在jpeg_start_decompress后才被填充到cinfo中的,如果希望在调用jpeg_start_decompress之前就获得这些参数,可以通过调用jpeg_calc_output_dimensions()的方法来实现。取出数据解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素对应的各颜色或灰度通道数据是依次存储,比如一个24-bitRGB真彩色的图像中,一个scanline中的数据存储模式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsignedchar,定义于jmorecfg.h中。除了JSAMPLE,IJG还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。在此,我们定义一个JSAMPARRAY类型的缓冲区变量来存放图像数据。JSAMPARRAYbuffer;然后是计算每行需要的空间大小,比如RGB图像就是宽度×3,灰度图就是宽度×1row_stride=cinfo.output_width*cinfo.output_components;为缓冲区分配空间,这里使用了IJG的内存管理器来完成分配。JPOOL_IMAGE表示分配的内存空间将在调用jpeg_finish_compress,jpeg_finish_decompress,jpeg_abort后被释放,而如果此参数改为JPOOL_PERMANENT则表示内存将一直到JPEG对象被销毁时才被释放。row_stride如上所说,是每行数据的实际大小。最后一个参数是要分配多少行数据。此处只分配了一行。buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);output_scanline表示当前已经读取的行数,如此即可依次读出图像的所有数据,并填充到缓冲区中,参数1表示的是每次读取的行数。while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//dosomething}解压缩完毕(void)jpeg_finish_decompress(&cinfo);释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_decompress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_decompress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;FILE*infile;JSAMPARRAYbuffer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_decompress(&cinfo);//指定图像文件if((infile=fopen("sample.jpg","rb"))==NULL){return;}jpeg_stdio_src(&cinfo,infile);//读取图像信息(void)jpeg_read_header(&cinfo,TRUE);//设定解压缩参数,此处我们将图像长宽缩小为原图的1/2cinfo.scale_num=1;cinfo.scale_denom=2;//开始解压缩图像(void)jpeg_start_decompress(&cinfo);//本程序功能是应用GDI+在客户区绘制图像CClientDCdc(this);Bitmapbm(cinfo.output_width,cinfo.output_height);Graphicsgraphics(dc.GetSafeHdc());Graphicsgdc(&bm);//分配缓冲区空间row_stride=cinfo.output_width*cinfo.output_components;buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);//读取数据while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//output_scanline是从1开始,所以需要减1intline=cinfo.output_scanline-1;for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
//找到图像中的某一行,写入目标文件
row_pointer=image_buffer[cinfo.next_scanline];
(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);
压缩完毕
jpeg_finish_compress(&cinfo);
释放资源
fclose(outfile);
jpeg_destroy_compress(&cinfo);
退出程序
如果不再需要JPEG对象,则使用
或
jpeg_destroy(&cinfo);
而如果还希望继续使用JPEG对象,则可使用
jpeg_abort_compress(&cinfo);
jpeg_abort(&cinfo);
完整例程
//变量定义
introw_stride;
//绑定标准错误处理结构
//初始化JPEG对象
//指定目标图像文件
if((outfile=fopen("dest.jpg","wb"))==NULL)
return;
//设定压缩参数
cinfo.image_width=image_width;
cinfo.image_height=image_height;
cinfo.in_color_space=JCS_RGB;
//此处设压缩比为90%
jpeg_set_quality(&cinfo,90,TRUE);
//开始压缩
//假设使用的是RGB图像
row_stride=image_width*3;
//写入数据
while(cinfo.next_scanline{row_pointer=image_buffer[cinfo.next_scanline];(void)jpeg_write_scanlines(&cinfo,&row_pointer,1);}//压缩完毕jpeg_finish_compress(&cinfo);//释放资源fclose(outfile);jpeg_destroy_compress(&cinfo);错误处理在使用默认错误处理结构jpeg_error_mgr的情况下,程序在遇到错误后将调用exit直接退出程序,用户如果不希望使用这种直接退出的方式处理错误的话就需要自定义错误处理结构。依照example.c中的例子,IJG推荐使用C语言的setjmp和longjmp机制来重写错误处理结构。首先,需要定义一个包含标准错误处理结构类型变量的自定义结构。同时,程序将需要引入头文件setjmp.h。#includestructmy_error_mgr{structjpeg_error_mgrpub;jmp_bufsetjmp_buffer;};typedefstructmy_error_mgr*my_error_ptr;以及一个错误处理函数。在出现错误时程序将跳转到本函数中,而本函数将跳转到setjmp设定的程序位置。METHODDEF(void)my_error_exit(j_common_ptrcinfo){my_error_ptrmyerr=(my_error_ptr)cinfo->err;(*cinfo->err->output_message)(cinfo);longjmp(myerr->setjmp_buffer,1);}解压缩操作过程1.为JPEG对象分配空间并初始化2.指定解压缩数据源3.获取文件信息4.为解压缩设定参数,包括图像大小,颜色空间5.开始解压缩6.取出数据7.解压缩完毕8.释放资源为JPEG对象分配空间并初始化解压缩过程中使用的JPEG对象是一个jpeg_decompress_struct的结构体。同时还需要定义一个用于错误处理的结构体对象,IJG中标准的错误结构体是jpeg_error_mgr。structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;然后是将错误处理结构对象绑定在JPEG对象上。cinfo.err=jpeg_std_error(&jerr);这个标准的错误处理结构将使程序在出现错误时调用exit()退出程序,如果不希望使用标准的错误处理方式,则可以通过自定义退出函数的方法自定义错误处理结构,详情见文章后面的专门章节。初始化cinfo结构。jpeg_create_decompress(&cinfo);指定解压缩数据源利用标准C中的文件指针传递要打开的jpg文件。FILE*infile;if((infile=fopen("sample.jpg","rb"))==NULL){return0;}jpeg_stdio_src(&cinfo,infile);获取文件信息IJG将图像的缺省信息填充到cinfo结构中以便程序使用。(void)jpeg_read_header(&cinfo,TRUE);此时,常见的可用信息包括图像的宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等。为解压缩设定参数在完成jpeg_read_header调用后,开始解压缩之前就可以进行解压缩参数的设定,也就是为cinfo结构的成员赋值。比如可以设定解出来的图像的大小,也就是与原图的比例。使用scale_num和scale_denom两个参数,解出来的图像大小就是scale_num/scale_denom,但是IJG当前仅支持1/1,1/2,1/4,和1/8这几种缩小比例。比如要取得1/2原图的图像,需要如下设定:cinfo.scale_num=1;cinfo.scale_denom=2;也可以设定输出图像的色彩空间,即cinfo.out_color_space,可以把一个原本彩色的图像由真彩色JCS_RGB变为灰度JCS_GRAYSCALE。如:cinfo.out_color_space=JCS_GRAYSCALE;开始解压缩根据设定的解压缩参数进行图像解压缩操作。(void)jpeg_start_decompress(&cinfo);在完成解压缩操作后,IJG就会将解压后的图像信息填充至cinfo结构中。比如,输出图像宽度cinfo.output_width,输出图像高度cinfo.output_height,每个像素中的颜色通道数cinfo.output_components(比如灰度为1,全彩色为3)等。一般情况下,这些参数是在jpeg_start_decompress后才被填充到cinfo中的,如果希望在调用jpeg_start_decompress之前就获得这些参数,可以通过调用jpeg_calc_output_dimensions()的方法来实现。取出数据解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素对应的各颜色或灰度通道数据是依次存储,比如一个24-bitRGB真彩色的图像中,一个scanline中的数据存储模式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsignedchar,定义于jmorecfg.h中。除了JSAMPLE,IJG还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。在此,我们定义一个JSAMPARRAY类型的缓冲区变量来存放图像数据。JSAMPARRAYbuffer;然后是计算每行需要的空间大小,比如RGB图像就是宽度×3,灰度图就是宽度×1row_stride=cinfo.output_width*cinfo.output_components;为缓冲区分配空间,这里使用了IJG的内存管理器来完成分配。JPOOL_IMAGE表示分配的内存空间将在调用jpeg_finish_compress,jpeg_finish_decompress,jpeg_abort后被释放,而如果此参数改为JPOOL_PERMANENT则表示内存将一直到JPEG对象被销毁时才被释放。row_stride如上所说,是每行数据的实际大小。最后一个参数是要分配多少行数据。此处只分配了一行。buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);output_scanline表示当前已经读取的行数,如此即可依次读出图像的所有数据,并填充到缓冲区中,参数1表示的是每次读取的行数。while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//dosomething}解压缩完毕(void)jpeg_finish_decompress(&cinfo);释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_decompress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_decompress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;FILE*infile;JSAMPARRAYbuffer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_decompress(&cinfo);//指定图像文件if((infile=fopen("sample.jpg","rb"))==NULL){return;}jpeg_stdio_src(&cinfo,infile);//读取图像信息(void)jpeg_read_header(&cinfo,TRUE);//设定解压缩参数,此处我们将图像长宽缩小为原图的1/2cinfo.scale_num=1;cinfo.scale_denom=2;//开始解压缩图像(void)jpeg_start_decompress(&cinfo);//本程序功能是应用GDI+在客户区绘制图像CClientDCdc(this);Bitmapbm(cinfo.output_width,cinfo.output_height);Graphicsgraphics(dc.GetSafeHdc());Graphicsgdc(&bm);//分配缓冲区空间row_stride=cinfo.output_width*cinfo.output_components;buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);//读取数据while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//output_scanline是从1开始,所以需要减1intline=cinfo.output_scanline-1;for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
//压缩完毕
//释放资源
错误处理
在使用默认错误处理结构jpeg_error_mgr的情况下,程序在遇到错误后将调用exit直接退出程序,用户如果不希望使用这种直接退出的方式处理错误的话就需要自定义错误处理结构。
依照example.c中的例子,IJG推荐使用C语言的setjmp和longjmp机制来重写错误处理结构。
首先,需要定义一个包含标准错误处理结构类型变量的自定义结构。
同时,程序将需要引入头文件setjmp.h。
#include
structmy_error_mgr
structjpeg_error_mgrpub;
jmp_bufsetjmp_buffer;
};
typedefstructmy_error_mgr*my_error_ptr;
以及一个错误处理函数。
在出现错误时程序将跳转到本函数中,而本函数将跳转到setjmp设定的程序位置。
METHODDEF(void)my_error_exit(j_common_ptrcinfo)
my_error_ptrmyerr=(my_error_ptr)cinfo->err;
(*cinfo->err->output_message)(cinfo);
longjmp(myerr->setjmp_buffer,1);
解压缩操作过程
2.指定解压缩数据源
3.获取文件信息
4.为解压缩设定参数,包括图像大小,颜色空间
5.开始解压缩
6.取出数据
7.解压缩完毕
8.释放资源
解压缩过程中使用的JPEG对象是一个jpeg_decompress_struct的结构体。
structjpeg_decompress_structcinfo;
jpeg_create_decompress(&cinfo);
指定解压缩数据源
利用标准C中的文件指针传递要打开的jpg文件。
FILE*infile;
if((infile=fopen("sample.jpg","rb"))==NULL)
jpeg_stdio_src(&cinfo,infile);
获取文件信息
IJG将图像的缺省信息填充到cinfo结构中以便程序使用。
(void)jpeg_read_header(&cinfo,TRUE);
此时,常见的可用信息包括图像的宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等。
为解压缩设定参数
在完成jpeg_read_header调用后,开始解压缩之前就可以进行解压缩参数的设定,也就是为cinfo结构的成员赋值。
比如可以设定解出来的图像的大小,也就是与原图的比例。
使用scale_num和scale_denom两个参数,解出来的图像大小就是scale_num/scale_denom,但是IJG当前仅支持1/1,1/2,1/4,和1/8这几种缩小比例。
比如要取得1/2原图的图像,需要如下设定:
cinfo.scale_num=1;
cinfo.scale_denom=2;
也可以设定输出图像的色彩空间,即cinfo.out_color_space,可以把一个原本彩色的图像由真彩色JCS_RGB变为灰度JCS_GRAYSCALE。
cinfo.out_color_space=JCS_GRAYSCALE;
开始解压缩
根据设定的解压缩参数进行图像解压缩操作。
(void)jpeg_start_decompress(&cinfo);
在完成解压缩操作后,IJG就会将解压后的图像信息填充至cinfo结构中。
比如,输出图像宽度cinfo.output_width,输出图像高度cinfo.output_height,每个像素中的颜色通道数cinfo.output_components(比如灰度为1,全彩色为3)等。
一般情况下,这些参数是在jpeg_start_decompress后才被填充到cinfo中的,如果希望在调用jpeg_start_decompress之前就获得这些参数,可以通过调用jpeg_calc_output_dimensions()的方法来实现。
取出数据
解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素对应的各颜色或灰度通道数据是依次存储,比如一个24-bitRGB真彩色的图像中,一个scanline中的数据存储模式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsignedchar,定义于jmorecfg.h中。
除了JSAMPLE,IJG还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。
在此,我们定义一个JSAMPARRAY类型的缓冲区变量来存放图像数据。
JSAMPARRAYbuffer;
然后是计算每行需要的空间大小,比如RGB图像就是宽度×3,灰度图就是宽度×1
row_stride=cinfo.output_width*cinfo.output_components;
为缓冲区分配空间,这里使用了IJG的内存管理器来完成分配。
JPOOL_IMAGE表示分配的内存空间将在调用jpeg_finish_compress,jpeg_finish_decompress,jpeg_abort后被释放,而如果此参数改为JPOOL_PERMANENT则表示内存将一直到JPEG对象被销毁时才被释放。
row_stride如上所说,是每行数据的实际大小。
最后一个参数是要分配多少行数据。
此处只分配了一行。
buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);
output_scanline表示当前已经读取的行数,如此即可依次读出图像的所有数据,并填充到缓冲区中,参数1表示的是每次读取的行数。
while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//dosomething}解压缩完毕(void)jpeg_finish_decompress(&cinfo);释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);退出程序如果不再需要JPEG对象,则使用jpeg_destroy_decompress(&cinfo);或jpeg_destroy(&cinfo);而如果还希望继续使用JPEG对象,则可使用jpeg_abort_decompress(&cinfo);或jpeg_abort(&cinfo);完整例程//变量定义structjpeg_decompress_structcinfo;structjpeg_error_mgrjerr;FILE*infile;JSAMPARRAYbuffer;introw_stride;//绑定标准错误处理结构cinfo.err=jpeg_std_error(&jerr);//初始化JPEG对象jpeg_create_decompress(&cinfo);//指定图像文件if((infile=fopen("sample.jpg","rb"))==NULL){return;}jpeg_stdio_src(&cinfo,infile);//读取图像信息(void)jpeg_read_header(&cinfo,TRUE);//设定解压缩参数,此处我们将图像长宽缩小为原图的1/2cinfo.scale_num=1;cinfo.scale_denom=2;//开始解压缩图像(void)jpeg_start_decompress(&cinfo);//本程序功能是应用GDI+在客户区绘制图像CClientDCdc(this);Bitmapbm(cinfo.output_width,cinfo.output_height);Graphicsgraphics(dc.GetSafeHdc());Graphicsgdc(&bm);//分配缓冲区空间row_stride=cinfo.output_width*cinfo.output_components;buffer=(*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,JPOOL_IMAGE,row_stride,1);//读取数据while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//output_scanline是从1开始,所以需要减1intline=cinfo.output_scanline-1;for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
(void)jpeg_read_scanlines(&cinfo,buffer,1);
//dosomething
解压缩完毕
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
jpeg_abort_decompress(&cinfo);
//指定图像文件
//读取图像信息
//设定解压缩参数,此处我们将图像长宽缩小为原图的1/2
//开始解压缩图像
//本程序功能是应用GDI+在客户区绘制图像
CClientDCdc(this);
Bitmapbm(cinfo.output_width,cinfo.output_height);
Graphicsgraphics(dc.GetSafeHdc());
Graphicsgdc(&bm);
//分配缓冲区空间
//读取数据
while(cinfo.output_scanline{(void)jpeg_read_scanlines(&cinfo,buffer,1);//output_scanline是从1开始,所以需要减1intline=cinfo.output_scanline-1;for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
//output_scanline是从1开始,所以需要减1
intline=cinfo.output_scanline-1;
for(inti=0;i{//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));}}//结束解压缩操作(void)jpeg_finish_decompress(&cinfo);//释放资源jpeg_destroy_decompress(&cinfo);fclose(infile);//在客户区绘制位图graphics.DrawImage(&bm,0,0);
//绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像
//因此,实际上cinfo.output_components就等于3,灰度图则需另作处理
bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));
//结束解压缩操作
//在客户区绘制位图
graphics.DrawImage(&bm,0,0);
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1