前面几篇文章中已经实现了将 CBitmap 对象保存为 bmp 格式文件,以及将 bmp 格式转换成 jpg 格式,中间绕了一道弯,为什么不直接将 CBitmap 对象直接存为 jpg 格式呢?
可以借鉴下面的资料,该文中实现了先将 bmp 文件加载为 CBitmap 对象,然后使用 IJG jpeg 库函数保存为 jpg 格式文件:
VC中利用IJG库实现图片由BMP转JPG格式
http://hi.baidu.com/andyleesoft/blog/item/d6f354003fcbbe024bfb5113.html
我对该文中的代码进行了测试和调整,分解成两个函数:
1. 将CBitmap对象存为jpg格式文件,命名为 IJG_bmp2jpg;
1. 将bmp文件加载为CBitmap对象,然后调用第一个函数来保存为jpg格式文件。
/****函数功能:CBitmap存为JPG******/ /*入口:CBitmap对象,目标文件地址,压缩质量*/ bool IJG_bmp2jpg(CBitmap& cbmp, CString Dfilepath,int quality) { BITMAP bmp; cbmp.GetBitmap(&bmp);//获取图像信息 if (bmp.bmBitsPixel<8) { AfxMessageBox("不支持8位以下图像转换。"); return false; } byte * p = new byte[bmp.bmWidth * bmp.bmHeight*bmp.bmBitsPixel/8];//创建空间,大小=像素*每像素所占字节数 cbmp.GetBitmapBits(bmp.bmWidth * bmp.bmHeight*bmp.bmBitsPixel/8,p);//将图像数据复制到内存 if (bmp.bmBitsPixel==32)//32位需要特殊处理,去掉其中透明字节,并且需要改变RGB顺序 { for (long i=0, j=0;j<bmp.bmWidth * bmp.bmHeight*4 ;i+=3,j+=4) { *(p+i)=*(p+j+2); *(p+i+1)=*(p+j+1); *(p+i+2)=*(p+j); } } /************以下利用IJG库进行格式转换******************/ struct jpeg_compress_struct jcs; /*声明JPEG压缩对象*/ struct jpeg_error_mgr jem; /*声明错误处理器*/ JSAMPLE *image_buffer=(JSAMPLE *)p; /*转换的源图像缓冲区指向之前申请的内存*/ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /*每行字节数*/ jcs.err=jpeg_std_error(&jem); jpeg_create_compress(&jcs); /*initialize the JPEG compression object.*/ FILE* f=fopen(Dfilepath,"wb"); /*建立JPEG文件*/ if(f==NULL) { AfxMessageBox("建立JPEG文件失败。"); fclose(f); delete []p; return false ; } jpeg_stdio_dest(&jcs, f); /*将目标文件与转换结果相关联*/ jcs.image_width = bmp.bmWidth; /* image width and height, in pixels */ jcs.image_height = bmp.bmHeight; jcs.input_components = (bmp.bmBitsPixel/8>=3?3:bmp.bmBitsPixel/8); /* # of color components per pixel */ jcs.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&jcs); jpeg_set_quality(&jcs, quality, TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&jcs, TRUE); /*开始压缩*/ row_stride=jcs.image_width*jcs.input_components; while (jcs.next_scanline<jcs.image_height) { row_pointer[0] = & image_buffer[jcs.next_scanline * row_stride]; (void) jpeg_write_scanlines(&jcs, row_pointer, 1); } jpeg_finish_compress(&jcs); fclose(f); jpeg_destroy_compress(&jcs); delete []p; return true; } /****函数功能:bmp转JPG******/ /*入口:源文件地址,目标文件地址,压缩质量*/ bool IJG_bmp2jpg(CString Sfilepath,CString Dfilepath,int quality) { CBitmap cbmp; HBITMAP hbitmap=(HBITMAP)::LoadImage(NULL,Sfilepath,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//位图句柄,读取外部位图 if (hbitmap==NULL) { AfxMessageBox("源图像读取错误"); return false; } cbmp.Attach(hbitmap);//将外部图像引入CBITMAP return IJG_bmp2jpg(cbmp, Dfilepath, quality); }
调用方式如下:
//bool IJG_bmp2jpg(CString Sfilepath,CString Dfilepath,int quality) IJG_bmp2jpg("clipboard.bmp", "clipboard2.jpg", 60); //bool IJG_bmp2jpg(CBitmap cbm,CString Dfilepath,int quality) IJG_bmp2jpg(*cbm, "clipboard3.jpg", 60);