(2014-07-17 10:59:29)
unsigned char ** outbuffer,
unsigned long * outsize));
unsigned char * inbuffer,
unsigned long insize));
outbuf -=row_stride;//指针前移一行
jpeg_read_scanlines(&cinfo,buffer,1);解压出一行数据
memcpy(outbuf,buffer[0],row_stride);将解压出的数据拷贝至outbuf
转载▼
这几天,在做一个项目,要求传输图像数据量小,对图像质量要求不高。我原来的图像是8位的灰度图像。要压缩之后才能传输。
在网上转了一圈,发现了这个开源库(话说开源的库最喜欢了)libjpeg,这个库十分小巧,而且高效。
之前的libjpeg6的版本,只能对针对图像文件进行压缩和解压缩,后来网上出现了很多通过修改源代码实现内存中图像压缩解压缩的方法。针对的都是老版本。
现在的libjpeg9的版本,已经将这个重要的函数加进来了。
jpeg_mem_dest、jpeg_mem_src
对应的是对内存中图像的操作。
EXTERN(void)jpeg_mem_dest JPP((j_compress_ptr cinfo,
EXTERN(void)jpeg_mem_src JPP((j_decompress_ptr cinfo,
利用上面的函数,不用修改源代码,可以直接在内存中压缩解压缩了。是不是很happy呢,这可要感谢那些辛苦更新这些开源库的小伙伴们!
这一篇文章,将主要讲windows下的这个库的使用。linux下的使用,稍后会在另一篇文章中细说。
好了废话不多说。上干货。
我的开发环境
系统是windows XP
IDE:VC6.0
第一步
下载libjpeg 下载地址:
http://www.ijg.org/
下载jpegsr9a.zip这个文件。解压这个压缩包到一个纯英文目录下。
我的位置是E:\C_example\jpeg-9a
第二步
打开cmd命令行窗口,将目录切换到你刚才解压的那个目录下面
如图
然后输入下面的命令
NMAKE /f makefile.vc
setup-vc6
第三步
打开刚才解压的目录找到
jpeg.dsw这个工程。点击Build。就可以生成lib文件。
需要注意的地方,
jpeg.dsw这个工程中
工程->设置->c/c++下拉菜单codegeneration 中的
Processor选项和
Use run-timelibrary选项,这两个选项必须要你自己的工程设置成相同的。以你自己的工程为准,修改
jpeg.dsw工程中的上述两个选项。
这么做的是确保编译出来的lib库文件和你自己的工程能够兼容,否则将会出现下面的错误
warning LNK4098: defaultlib"libcmt.lib" conflicts with use of other libs; use/NODEFAULTLIB:library
第四步
还是刚才的解压目录,刚才build,会产生一个Release文件夹,这里面就是生成的lib文件
将里面的jpeg.lib文件和解压目录下的jconfig.h、jmorecfg.h、jpeglib.h四个文件放在一个新建的名字为libjpeg文件夹下面。把这个文件夹拷贝到你的工程目录下面
第五步
在你要调用这个库的工程中添加下面的语句
extern "C" {
#include "jpeglib.h"
#include
}
#pragma comment(lib,"libjpeg/jpeg.lib")
然后你就可以调用下面的代码进行解压缩了。
structmy_error_mgr {
structjpeg_error_mgr pub;
jmp_bufsetjmp_buffer;
};
把下面的程序拷贝到你的工程中,直接调用jpeg_decompress这个函数就能实现解压缩。
typedef structmy_error_mgr * my_error_ptr;
METHODDEF(void)
my_error_exit(j_common_ptr cinfo)
{
my_error_ptrmyerr = (my_error_ptr) cinfo->err;
(*cinfo->err->output_message)(cinfo);
longjmp(myerr->setjmp_buffer,1);
}
GLOBAL(int)jpeg_decompress(unsigned char *inbuf,unsigned char *outbuf,unsignedint size)
{
structjpeg_decompress_struct cinfo;
structmy_error_mgr jerr;
JSAMPARRAYbuffer;
int row_stride;
cinfo.err =jpeg_std_error(&jerr.pub);
jerr.pub.error_exit =my_error_exit;
if(setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
return0;
}
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo,inbuf,size);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
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 < cinfo.output_height)
{
jpeg_read_scanlines(&cinfo,buffer,1);//解压出一行数据
memcpy(outbuf,buffer[0],row_stride);//将解压出的数据拷贝至outbuf
outbuf +=row_stride;//指针前移一行
}
//以上这些都是固定的调用步骤,不知道每句的意思的话千万别改动
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return1;
}
“解压时,libjpeg是以图片的一行为单位解压的,也就是图片水平的一条线,jpeg存储时左上角是坐标原点,bmp存储时左下角是原点,因此转化时要把上下顺序颠倒一下才是正确的,所以outbuf传入的是最后一个字节的地址,从最后一个字节往前顺序拷贝jpg解压缩出来的数据才能得到正确的图片。
解压出来的bmp文件是24位图片,每个像素占用8位,因此如果图片大小为640*480,则outbuf大小应该为921654=640*480*3+54,其中54位为bmp文件头,则传入的outbuf应该是开辟的内存空间起始地址+921654,至于bmp头的制作我就不讲了,大家自己看吧,就那么点东西”
根据这段话,调用的时候outbuf应该是指向输出缓存区的最后一个字节,但是我在实际使用的时候,解压出来的图像时反的,所以我就把outbuf设置为指向输出缓存区的第一个字节了,然后把程序中的下面语句
修改为
jpeg_read_scanlines(&cinfo,buffer,1);//解压出一行数据
memcpy(outbuf,buffer[0],row_stride);//将解压出的数据拷贝至outbuf
outbuf += row_stride;//指针前移一行
改完之后发现图像正常了。
ps如果碰到下面的问题
fatal error:C1083:can not open include file:jpeglib.h:no suchfile or directory
请查看你的工程
Project->setting->c/c++/preprocessor页面里面的
Additionalinclude directory这个栏目,如果是空的,需要添加一个头文件的目录。
请填写libjpeg(就是放头文件那个目录名字)