大多的开源或不开源的软件处理jpg图像的时候均使用libjpeg开源库,目前最新版本为libjpeg-8b,下载链接为
http://freshmeat.net/projects/libjpeg
里面很多makefile文件,linux下不多说,在win32下,构建vc6工程只要将.vc6后缀名搜索出,将make*dsp.vc6修改为make*dsp.dsp,所有make*dsw.vc6修改为make*dsw.dsw,这里得到makeadsw.dsw和makejdsw.dsw,前者为所有编解码及测试程序工程,后者为简单的libjpeg工程。对于libjpeg的makejdsw生成了一个win32的的.lib库,这里可将库名称修改为libjpeg.lib。这样我们可参考编码程序将图片编码为jpeg图片了。
比如,现在我们利用GDI+打开任意格式图片,而后得到图片的解码数据,便可编译为jpeg图片了。
ps:为何不用GDI+直接保存jpg图片,因GDI+中生成的jpeg质量不满意,嘿嘿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
//
jpeg void write_my_jpeg() { //
初始化数据 Bitmap
bitmap(_T( "a.bmp" )); int iWidth
= bitmap.GetWidth(); int iHeight
= bitmap.GetHeight(); unsigned
char *pDataConv
= new unsigned
char [iWidth
* iHeight * 3]; init_data(bitmap,
pDataConv); struct jpeg_compress_struct
jcs; //
声明错误处理器,并赋值给jcs.err域 struct jpeg_error_mgr
jem; jcs.err
= jpeg_std_error(&jem); jpeg_create_compress(&jcs); FILE *
f = _wfopen(_T( "my.jpg" ),
_T( "wb" )); if (f==NULL) { delete []
pDataConv; return ; } jpeg_stdio_dest(&jcs,
f); jcs.image_width
= iWidth; //
为图的宽和高,单位为像素 jcs.image_height
= iHeight; jcs.input_components
= 3; //
在此为1,表示灰度图, 如果是彩色位图,则为3 jcs.in_color_space
= JCS_RGB; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像 jpeg_set_defaults(&jcs);
//
指定亮度及色度质量 jcs.q_scale_factor[0]
= jpeg_quality_scaling(100); jcs.q_scale_factor[1]
= jpeg_quality_scaling(100); //
图像采样率,默认为2 * 2
jcs.comp_info[0].v_samp_factor = 1; jcs.comp_info[0].h_samp_factor
= 1; //
设定编码jpeg质量 jpeg_set_quality
(&jcs, 100, true ); jpeg_start_compress(&jcs,
TRUE); JSAMPROW
row_pointer[1]; //
一行位图 int row_stride;
//
每一行的字节数 row_stride
= jcs.image_width * 3; //
如果不是索引图,此处需要乘以3 //
对每一行进行压缩 while (jcs.next_scanline
< jcs.image_height) { row_pointer[0]
= (JSAMPROW)(pDataConv + jcs.next_scanline * row_stride); jpeg_write_scanlines(&jcs,
row_pointer, 1); } jpeg_finish_compress(&jcs); jpeg_destroy_compress(&jcs); // delete []
pDataConv; } |
// 数据转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
//
data void init_data(Bitmap
&bitmap, unsigned char *pDataConv) {
//
Btimap int iWidth
= bitmap.GetWidth(); int iHeight
= bitmap.GetHeight(); Gdiplus::BitmapData
bitmapData; Gdiplus::Rect
rectPiece(0, 0, iWidth, iHeight); //
lock,获取Bitmap数据 bitmap.LockBits(&rectPiece,
Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB,
&bitmapData); int iBitmapPieceStride
= bitmapData.Stride; unsigned
long *pBitmapPiecePixels
= (unsigned long *)bitmapData.Scan0; //
获取像素点数据 unsigned
long ulColorValueTemp
= 0; unsigned
char usR,
usG, usB; for ( int y
= 0; y != iHeight; ++y) { for ( int x
= 0; x != iWidth; ++x) { ulColorValueTemp
= pBitmapPiecePixels[y * iBitmapPieceStride / 4 + x]; usR
= (ulColorValueTemp >> 16); usG
= (ulColorValueTemp >> 8); usB
= ulColorValueTemp; *pDataConv
= usR; ++pDataConv; *pDataConv
= usG; ++pDataConv; *pDataConv
= usB; ++pDataConv; } }
//
//
memcpy(pDataConv, pBitmapPiecePixels, iWidth * iHeight * 3); bitmap.UnlockBits(&bitmapData); } |
默认情况下,不管是GDI+,还是CxImage,OpenCV等常见的开源库均只提供了设定质量的函数,即
1
|
jpeg_set_quality() |
正常情况下,这样也可以满足我们的基本需求,但对于有些图片,比如黑色背景,写白色字体的图片,在压缩时,基本设定质量最高为100,但压缩质量仍不满意,原因便在压缩时的图像采样率上,ASDSee保存jpeg图片格式时,有选择采样率的2 * 1和1* 2,而libjpeg默认为2 * 2,因此会发现ACDSee质量要好些的缘故,如果不介意,可以直接设定为1 * 1,质量会更好些,不过对于这样的图片压缩后的图片大小可能大于原bmp图片大小,具体情况请读者自行参考。