2411C++,CXImage简单使用
介绍
CxImage
是一个可非常简单快速
的加载,保存,显示和转换图像
的C++
类.
文件格式和链接的C库
Cximage
对象基本上是加了一些成员变量
来保存有用信息
的一个位图
:
class CxImage
{
...
protected:
void* pDib;
//包含标题,调色板,像素
BITMAPINFOHEADER head;
//标准头文件
CXIMAGEINFO info;
//扩展信息
BYTE* pSelection;
//所选区域
BYTE* pAlpha;
//`α`通道
CxImage** ppLayers;
//通用图层
CxImage** ppFrames;
//动画帧
}
CxImage::head
是位图头
,CxImage::pDib
是普通位图
(如CxImageBMP::Encode
的实现所示).
CxImage::info
是,包含不同格式间
共享的许多信息
及所有成员函数
.
typedef struct tagCxImageInfo {
DWORD dwEffWidth;
//`双字`对齐的扫描行宽度
BYTE* pImage;
//图像位
void* pGhost;
//如果这是重影,则`pGhost`指向身体
DWORD dwType;
//原图像格式
char szLastError[256];
//调试
long nProgress;
//监听
long nEscape;
//转义
long nBkgndIndex;
//`GIF,PNG,MNG`
RGBQUAD nBkgndColor;
//`RGB`透明
BYTE nQuality;
//`JPEG`
long nFrame;
//`TIF,GIF,MNG`:实际帧
long nNumFrames;
//`用于TIF,GIF,MNG`:总帧数
DWORD dwFrameDelay;
//`GIF,MNG`
long xDPI;
//水平分辨率
long yDPI;
//垂直分辨率
RECT rSelectionBox;
//约束矩形
BYTE nAlphaMax;
//最大暗度(淡化)
bool bAlphaPaletteEnabled;
//如果启用了调色板中的`α`值,则为`真`.
bool bEnabled;
//启用绘画函数
long xOffset;
long yOffset;
DWORD dwEncodeOption;
//对`GIF,TIF:0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg`
RGBQUAD last_c;
//用来`GetNearestIndex`优化
BYTE last_c_index;
bool last_c_isvalid;
long nNumLayers;
DWORD dwFlags;
} CXIMAGEINFO;
CxImage
对象也是一组层
.仅在必要
时才分配每层中的缓冲
.
CxImage::pDib
是背景图像
.CxImage::pAlpha
是透明图层
.CxImage::pSelection
是创建处理图像的感兴趣区域
的选择图层
.
在这3个特定平面
上,可添加在CxImage::ppLayers
中保存的其他通用图层
.通用层
是完整的CxImage
对象,因此可构建嵌套层的复杂结构
.
CxImage::ppFrames
用来保存(GIF
)动画图像.
CxImage
类成员和操作
CxImage
是使用Doxygen
记录的,但是因为历史原因,仍未记录许多不常见的功能
.
支持的格式和选项
整个库非常大,在ximcfg.h
主头文件中,可找到启用或禁止
特定图形格式
或特征
的开关.每个JPG,PNG
和TIFF
库都会对最终应用
增加约100KB
,而CxImage
影响约为50KB
.
因此,应该只支持和链接
应用真正需要的格式
.
格式 | #define | 必需的库 | [KB] 大小 |
---|---|---|---|
BMP,GIF,ICO,TGA,PCX,WBMP,WMF,SKA | CXIMAGE_SUPPORT_BMP ,CXIMAGE_SUPPORT_GIF ,CXIMAGE_SUPPORT_ICO ,CXIMAGE_SUPPORT_TGA ,CXIMAGE_SUPPORT_PCX ,CXIMAGE_SUPPORT_WBMP ,CXIMAGE_SUPPORT_WMF ,CXIMAGE_SUPPORT_SKA | 内置 | 24 |
JPEG 格式 | CXIMAGE_SUPPORT_JPG | jpeg | 88 |
PNG | CXIMAGE_SUPPORT_PNG | png,zlib | 104 |
MNG | CXIMAGE_SUPPORT_MNG | mng,zlib,jpeg | 148 |
TIFF | CXIMAGE_SUPPORT_TIF | TIFF,zlib,jpeg | 124 |
JBIG | CXIMAGE_SUPPORT_JBG | jbig | 28 |
PNM,PPM,PGM,RAS | CXIMAGE_SUPPORT_PNM ,CXIMAGE_SUPPORT_RAS | jasper | 176 |
JPEG-2000 格式 | CXIMAGE_SUPPORT_JP2``CXIMAGE_SUPPORT_JPC``CXIMAGE_SUPPORT_PGX | 同上 | 176 |
RAW | CXIMAGE_SUPPORT_RAW | libdcr | 132 |
选项 | #define | [KB] 大小 |
---|---|---|
CxImage 核心 | 所有开关 关闭 | 20 |
几何变换 | CXIMAGE_SUPPORT_TRANSFORMATION | 16 |
处理图像 | CXIMAGE_SUPPORT_DSP | 24 |
绘画和窗口相关功能 | CXIMAGE_SUPPORT_WINDOWS | 12 |
透明 | CXIMAGE_SUPPORT_ALPHA | 4 |
选区 | CXIMAGE_SUPPORT_SELECTION | 4 |
多层 | CXIMAGE_SUPPORT_LAYERS | <4 |
图形格式转换 | CXIMAGE_SUPPORT_DECODE ,CXIMAGE_SUPPORT_ENCODE | <4 |
插值功能 | CXIMAGE_SUPPORT_INTERPOLATION | <4 |
处理异常 | CXIMAGE_SUPPORT_EXCEPTION_HANDLING | <4 |
在项目中使用CxImage
CxImgLib.dsw
客户区显示了构建应用(demo.exe
)期望库,包括CxImage
中可用的几乎所有函数和格式
.必须先编译所有库
,才能链接最终应用
.
在源码中,你必须添加#include"ximage.h"
在CxImage
中添加自定义功能
使用CxImage
编写处理图像
的新功能并不难.在此,我描述了非常简单的CxImage::Jitter
,但它显示了在CxImage
中工作时注意的许多方面
.
首先,当然是声明:在ximage.h
的CXIMAGE_SUPPORT_DSP
部分中声明bool Jitter(longradius=2);
,你可在类的公
域中声明该函数
.
现在是定义:
bool CxImage::Jitter(long radius)
{
//检查图像是否有效,这应该总是是函数中的第一行
if (!pDib) return false;
//局部变量
long nx,ny;
//临时图像来保存算法的部分结果
CxImage tmp(*this,pSelection!=0,true,true);
//仅在包含所选区域的最小矩形中限制函数的效果(使用`Selection...()`函数),这加快循环速度.
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;
}
//`主循环`:在垂直方向扫描图像
for(long y=ymin; y <ymax; y++){
//监听循环的进度
info.nProgress = (long)(100*y/head.biHeight);
//让应用快速退出
if (info.nEscape) break;
//`主循环`:在水平方向扫描图像
for(long x=xmin; x<xmax; x++){
//如果启用该函数,则仅处理所选区域内的像素
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif
//`CXIMAGE_SUPPORT_SELECTION`
{
//主要算法
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;
}
//在临时图像中保存结果.如果可以,请仅对`24bpp`图像使用`PixelColor`,对`8,4`和`1bpp`图像使用`PixelIndex`:这样更快
if (head.biClrUsed==0){
tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));
} else {
tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));
}
//如果启用了该功能,则还要处理`α`图层中的像素
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaSet(x,y,AlphaGet(nx,ny));
#endif
//`CXIMAGE_SUPPORT_ALPHA`
}
}
}
//保存结果并退出
Transfer(tmp);
return true;
}
示例:如何…
…按另一个格式转换一个格式
.
CxImage image;
//`BMP->JPG`
image.Load("image.bmp", CXIMAGE_FORMAT_BMP);
if (image.IsValid()){
if(!image.IsGrayScale()) image.IncreaseBpp(24);
image.SetJpegQuality(80);
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);
}
…加载图像资源
//从`PNG`资源类型加载资源`IDR_PNG1`
CxImage* newImage = new CxImage();
newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1), "PNG"),CXIMAGE_FORMAT_PNG);
//或
//从`DLL`加载资源`IDR_JPG1`
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);
}
//或:
//加载位图资源;
HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1)));
CxImage *newImage = new CxImage();
newImage->CreateFromHBITMAP(bitmap);
… 从内存解码图片
CxImage image((BYTE*)buffer,size,image_type);
//或
CxMemFile memfile((BYTE*)buffer,size);
CxImage image(&memfile,image_type);
//或
CxMemFile memfile((BYTE*)buffer,size);
CxImage* image = new CxImage();
image->Decode(&memfile,type);
…在内存中编码图像
long size=0;
BYTE* buffer=0;
image.Encode(buffer,size,image_type);
...
image.FreeMemory(buffer);
//或
CxMemFile memfile;
memfile.Open();
image.Encode(&memfile,image_type);
BYTE* buffer = memfile.GetBuffer();
long size = memfile.Size();
...
image.FreeMemory(buffer);
… 创建多页TIFF
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);
//或
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);
…复制/粘贴图像
//复制
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();
//糊
HANDLE hBitmap=NULL;
CxImage *newima = new CxImage();
if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);
if (hBitmap) newima->CreateFromHANDLE(hBitmap);
CloseClipboard();
在图片框中显示文件
HBITMAP m_bitmap = NULL;
CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);
...
CDC* hdc = m_picture.GetDC();
HBITMAP m_bitmap = image.MakeBitmap(hdc->m_hDC);
HBITMAP hOldBmp = m_picture.SetBitmap(m_bitmap);
if (hOldBmp) DeleteObject(hOldBmp);
if (hdc->m_hDC) m_picture.ReleaseDC(hdc);
...
if (m_bitmap) DeleteObject(m_bitmap);