LibJpeg作爲常用開源庫,已有很多相關介紹。
其中值得一提的是,早先的版本里沒有對內存中的Jpeg圖像編解碼的接口,而是使用Jpeg_stdio_src和jpeg_stdio_dest,這兩個都是直接針對File類對象操作,跳過了內存中圖像的這一步。有些文章介紹過如何在LibJpeg中添加針對內存圖像的解碼接口,但是沒有人添加過內存圖像的編碼接口。我直接把原有的jpeg_stdio_dest覆蓋成對內存中RGB圖像的編碼接口,輸出爲內存中的jpeg圖像。
頭文件和靜態庫已上傳到CSDN資源庫中,源碼也已經上傳,(添加對內存中Jpeg圖像編解碼接口的LibJpeg)可以自行編譯使用。
不過後來的turbo libjpeg將此問題解決了(上面上傳的代碼價值也就不大了),我沒有去看是不是新版本的LibJpeg也已經完善了這個問題。
turbo libjpeg的價值是利用SIMD指令集,加速了編解碼過程。官網上的介紹中提到某個案例中從原來的0.3左右降低到0.1,時間只有原來的1/3,在我的工程中,時間減少到原來LibJpeg的一半左右。而它的使用與之前的LibJpeg完全相同,只是添加完善了部分功能,完全可以直接替換,使用很方便。
下面的代碼既是使用LibJpeg做編解碼的方法,也是Turbo LibJpeg的使用方法(區別僅僅在於jpeg_mem_src和jpeg_mem_dst的使用):
值得注意的是,解碼的時候空間是由內部分配的,因爲這樣能夠準確分配內存空間,而不會造成浪費;
但是編碼的時候空間需要由外部分配,因爲準確的編碼後的空間大小不能獲知,當然完全可以分配一段和編碼前一樣大小的空間,這肯定是足夠的了,並且也不會造成太大的空間浪費。
turbo libjpeg可以在官網上去下載,目前的最新版本是1.3.1.
typedef unsigned char BYTE;
bool ReadJPEG(
/*IN*/BYTE *src, int srcLen,
/*OUT*/BYTE **_dst, int *dstLen, int *width, int *height, int *depth
)
{
// 【注意】dst空間由內部分配
//定義JPEG文件的解壓信息
struct jpeg_decompress_struct cinfo;
//定義JPEG文件的錯誤信息
struct jpeg_error_mgr jerr;
cinfo.err=jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo,src,srcLen);
jpeg_read_header(&cinfo,TRUE);
jpeg_start_decompress(&cinfo);
(*width) = cinfo.output_width;
(*height) = cinfo.output_height;
(*depth) = cinfo.num_components;
(*dstLen) = (*width)*(*height)*(*depth);
BYTE *dst = new BYTE[*dstLen];
JSAMPROW row_pointer[1];
while (cinfo.output_scanline<cinfo.output_height)
{
row_pointer[0] = &dst[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
jpeg_read_scanlines(&cinfo,row_pointer,1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
*_dst = dst;
return true;
}
bool WriteJPEG(
/*IN*/BYTE *src, int width, int height, int depth,
/*OUT*/BYTE **dst, int *dstLen
)
{
// 【注意】dst空間由外部分配,確保空間足夠
unsigned long act_len = 0;
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
jpeg_mem_dest(&jcs, dst, &act_len);
jcs.image_width = width;
jcs.image_height = height;
jcs.input_components = depth;
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs,80,true);
jcs.jpeg_color_space = JCS_YCbCr;
jcs.comp_info[0].h_samp_factor = 2;
jcs.comp_info[0].v_samp_factor = 2;
jpeg_start_compress(&jcs,TRUE);
JSAMPROW row_pointer[1];
int row_stride = jcs.image_width*jcs.num_components;
while (jcs.next_scanline<jcs.image_height)
{
row_pointer[0] = &src[jcs.next_scanline*row_stride];
jpeg_write_scanlines(&jcs,row_pointer,1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
*dstLen = act_len;
return true;
}