原文地址:http://www.codeproject.com/KB/graphics/cximage.aspx
1.简介及许可
CxImage 是一个免费的C++类,可以简单而快速的加载、保存、显示,转换BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K 等格式图像。CxImage是开源的,和zlib的许可协议一致,你可以在任何想使用的地方使用它。
2.移植性
该类和项目在多个编译器下进行过测试,从vc6.0至vs2008,borland c++3至6,部分的wxDev c++ 和MinGw。
所有库都提供了UNICODE和非UNICODE配置。
3.CxImage结构
一个CxImage对象基本是一个bitmap,另外增加一些成员变量保存有用的信息。
class CxImage
{
...
protected:
void* pDib; //contains the header, the palette, the pixels
BITMAPINFOHEADER head; //standard header
CXIMAGEINFO info; //extended information
BYTE* pSelection; //selected region
BYTE* pAlpha; //alpha channel
CxImage** pLayers; //generic layers
}
CxImage::head 是一个位图头,CxImage::pDib 是通常的位图。CxImage::info 是一个存储在不同格式之间的许多共享信息,在所有成员函数中使用。
typedef struct tagCxImageInfo {
DWORD dwEffWidth; //DWORD aligned scan line width
BYTE* pImage; //THE IMAGE BITS
void* pGhost; //if this is a ghost, pGhost point to the body
DWORD dwType; //original image format
char szLastError[256]; //debugging
long nProgress; //monitor
long nEscape; //escape
long nBkgndIndex; //used for GIF, PNG, MNG
RGBQUAD nBkgndColor; //used for RGB transparency
BYTE nQuality; //used for JPEG
long nFrame; //used for TIF, GIF, MNG : actual frame
long nNumFrames; //used for TIF, GIF, MNG : total number of
//frames
DWORD dwFrameDelay; //used for GIF, MNG
long xDPI; //horizontal resolution
long yDPI; //vertical resolution
RECT rSelectionBox; //bounding rectangle
BYTE nAlphaMax; //max opacity (fade)
bool bAlphaPaletteEnabled; //true if alpha values in the palette are
// enabled.
bool bEnabled; //enables the painting functions
long xOffset;
long yOffset;
DWORD dwEncodeOption; //for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,
// 4=pack,5=jpg
RGBQUAD last_c; //for GetNearestIndex optimization
BYTE last_c_index;
bool last_c_isvalid;
long nNumLayers;
DWORD dwFlags;
} CXIMAGEINFO;
CxImage对象还是多层的集合。每层的缓冲只在必要的时候才被分配。
CxImage::pDib是背景图,CxImage::pAlpha 是透明层,CxImage::pSelection 是选择层,用于创建图像处理的感兴趣的区域。在这三层外,你还可以定义,然后存储在CxImage::pLayers中。CxImage::ppFrames为动态图像(gif)保留.
4.支持的格式和选项:
整个库是非常大的,在主要的头文件ximcfg.h中你将找到一些开放或禁止一些特定的图形格式或特征的开关,每个JPG、PNG、TIFF库将使最终的应用程序增加大约100K的容量,cximage会影响50K的容量大小,所以你应当只支持和链接你的应用程序真正需要的格式。
5.如何使用cximage
工作区CxImagelib.dsw展示了建立一个应用程序所需要的库,在连接最终的应用程序之前你必须编译所有的库。在这个工作区中你将发现建立不同的库和应用程序的工程。
CxImage: cximage.lib -static library
CxImageCrtDll: cximagecrt.dll -DLL not using mfc
CxImageMfcDll: cximage.dll -DLL using mfc
Demo: demo.exe -program linked with cximage.lib and C Libraries
DemoDll: demodll.exe -program linked with cximagecrt.dll
j2k,jasper,jbig,jpeg,png,tiff,zlib: -static C Libraries
在你的项目中使用CxImage,必须作如下设置
在你的程序中添加#include ”ximage.h”
使用CxImage写一个图像处理的新函数也很容易,下面描述怎样添加CxImage::Jitter
函数:首先声明该函数bool Jitter(long radius=2),在文件ximage.h的CXIMAGE_SUPPORT_DSP的部分公有函数的任何区域,然后如下代码进行定义
bool CxImage::Jitter(long radius)
{
// check if the image is valid, this should be always the first line in
// the function
if (!pDib) return false;
// local variables
long nx,ny;
// temporary image to store the partial results of the algorithm
CxImage tmp(*this,pSelection!=0,true,true);
// limit the effects of the functions only in the smallest rectangle that
// holds the selected region (defined with the Selection...() functions ),
// this will speed up the loops.
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
// main loop : scan the image in vertical direction
for(long y=ymin; y <ymax; y++){
// monitor the progress of the loops
info.nProgress = (long)(100*y/head.biHeight);
// let the application a way to exit quickly
if (info.nEscape) break;
// main loop : scan the image in horizontal direction
for(long x=xmin; x<xmax; x++){
// if the feature is enabled, process only the pixels inside the
// selected region
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
// main algorithm
nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
if (!IsInside(nx,ny)) {
nx=x;
ny=y;
}
// save the result in the temporary image.
// if you can, use PixelColor only for 24 bpp images,
// and PixelIndex for 8, 4 and 1 bpp images : it's faster
if (head.biClrUsed==0){
tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));
} else {
tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));
}
// if the feature is enabled, process also the pixels
// in the alpha layer
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaSet(x,y,AlphaGet(nx,ny));
#endif //CXIMAGE_SUPPORT_ALPHA
}
}
}
// save the result and exit
Transfer(tmp);
return true;
}
应用实例
格式转换
Code:
CxImage image;
// bmp -> jpg
image.Load("image.bmp", CXIMAGE_FORMAT_BMP);
if (image.IsValid()){
if(!image.IsGrayScale()) image.IncreaseBpp(24);
image.SetJpegQuality(99);
image.Save("image.jpg",CXIMAGE_FORMAT_JPG);
}
// png -> tif
image.Load("image.png", CXIMAGE_FORMAT_PNG);
if (image.IsValid()){
image.Save("image.tif",CXIMAGE_FORMAT_TIF);
}
加载图像资源
Code:
//Load the resource IDR_PNG1 from the PNG resource type
CxImage* newImage = new CxImage();
newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1),
"PNG"),CXIMAGE_FORMAT_PNG);
or
Code:
//Load the resource IDR_JPG1 from DLL
CxImage* newImage = new CxImage();
HINSTANCE hdll=LoadLibrary("imagelib.dll");
if (hdll){
HRSRC hres=FindResource(hdll,MAKEINTRESOURCE(IDR_JPG1),"JPG");
newImage->LoadResource(hres,CXIMAGE_FORMAT_JPG,hdll);
FreeLibrary(hdll);
}
or
Code:
//Load a bitmap resource;
HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1)));
CxImage *newImage = new CxImage();
newImage->CreateFromHBITMAP(bitmap);
解码内存中的图像
Code:
CxImage image((BYTE*)buffer,size,image_type);
or
Code:
CxMemFile memfile((BYTE*)buffer,size);
CxImage image(&memfile,image_type);
or
Code:
CxMemFile memfile((BYTE*)buffer,size);
CxImage* image = new CxImage();
image->Decode(&memfile,type);
编码内存中的图像
Code:
long size=0;
BYTE* buffer=0;
image.Encode(buffer,size,image_type);
...
free(buffer);
or
Code:
CxMemFile memfile;
memfile.Open();
image.Encode(&memfile,image_type);
BYTE* buffer = memfile.GetBuffer();
long size = memfile.Size();
...
free(buffer);
创建一个多页的TIFF
Code:
CxImage *pimage[3];
pimage[0]=&image1;
pimage[1]=&image2;
pimage[2]=&image3;
FILE* hFile;
hFile = fopen("multipage.tif","w+b");
CxImageTIF multiimage;
multiimage.Encode(hFile,pimage,3);
fclose(hFile);
or
Code:
FILE* hFile;
hFile = fopen("c:\\multi.tif","w+b");
CxImageTIF image;
image.Load("c:\\1.tif",CXIMAGE_FORMAT_TIF);
image.Encode(hFile,true);
image.Load("c:\\2.bmp",CXIMAGE_FORMAT_BMP);
image.Encode(hFile,true);
image.Load("c:\\3.png",CXIMAGE_FORMAT_PNG);
image.Encode(hFile);
fclose(hFile);
拷贝粘贴图像
Code:
//copy
HANDLE hDIB = image->CopyToHandle();
if (::OpenClipboard(AfxGetApp()->m_pMainWnd->GetSafeHwnd())) {
if(::EmptyClipboard()) {
if (::SetClipboardData(CF_DIB,hDIB) == NULL ) {
AfxMessageBox( "Unable to set Clipboard data" );
} } }
CloseClipboard();
//paste
HANDLE hBitmap=NULL;
CxImage *newima = new CxImage();
if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);
if (hBitmap) newima->CreateFromHANDLE(hBitmap);
CloseClipboard();
在picture框中显示图像文件
Code:
HBITMAP m_bitmap = NULL;
CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);
...
m_bitmap = image.MakeBitmap(m_picture.GetDC()->m_hDC);
m_picture.SetBitmap(m_bitmap);
...
if (m_bitmap) DeleteObject(m_bitmap);