之前的libjpeg6的版本,只能对针对图像文件进行压缩和解压缩,后来网上出现了很多通过修改源代码实现内存中图像压缩解压缩的方法。针对的都是老版本。
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,
unsigned char * inbuffer,
unsigned long insize));
利用上面的函数,不用修改源代码,可以直接在内存中压缩解压缩了。是不是很happy呢,这可要感谢那些辛苦更新这些开源库的小伙伴们!
好了废话不多说。上干货。
我的开发环境
系统是windows XP
IDE:VC6.0
第一步
下载libjpeg 下载地址: http://www.ijg.org/(若下载不顺畅可在直接下载)
下载jpegsr9a.zip这个文件。解压这个压缩包到一个纯英文目录下。
我的位置是E:\C_example\jpeg-9a
第二步
打开cmd命令行窗口,将目录切换到你刚才解压的那个目录下面
如图
然后输入下面的命令
setup-vc6
第三步
jpeg.dsw这个工程。点击Build。就可以生成lib文件。
jpeg.dsw 这个工程中 工程->设置->c/c++下拉菜单code generation
Processor选项和 Use run-time library选项,这两个选项必须要你自己的工程设置成相同的。以你自己的工程为准,修改 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"
}
然后你就可以调用下面的代码进行解压缩了。
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
把下面的程序拷贝到你的工程中,直接调用
jpeg_decompress这个函数就能实现解压缩。
typedef struct my_error_mgr * my_error_ptr;
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
my_error_ptr myerr = (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,unsigned int size)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
JSAMPARRAY buffer;
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);
return 0;
}
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);
return 1;
}
“解压时,libjpeg是以图片的一行为单位解压的,也就是图片水平的一条线,jpeg存储时左上角是坐标原点,bmp存储时左下角是原点,因此转化时要把上下顺序颠倒一下才是正确的,所以outbuf传入的是最后一个字节的地址,从最后一个字节往前顺序拷贝jpg解压缩出来的数据才能得到正确的图片。
解压出来的bmp文件是24位图片,每个像素占用8位,因此如果图片大小为640*480,则outbuf大小应该为921654 = 640*480*3+54,其中54位为bmp文件头,则传入的outbuf应该是开辟的内存空间起始地址+921654,至于bmp头的制作我就不讲了,大家自己看吧,就那么点东西”
根据这段话,调用的时候outbuf应该是指向输出缓存区的最后一个字节,但是我在实际使用的时候,解压出来的图像时反的,所以我就把outbuf设置为指向输出缓存区的第一个字节了,然后把程序中的下面语句
outbuf -= row_stride;//指针前移一行
jpeg_read_scanlines(&cinfo,buffer,1);解压出一行数据
memcpy(outbuf,buffer[0],row_stride);将解压出的数据拷贝至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 such file or directory
请查看你的工程
Project->setting->c/c++/preprocessor页面里面的
Additional include directory这个栏目,如果是空的,需要添加一个头文件的目录。
请填写libjpeg(就是放头文件那个目录名字)
完整的工程下载