文章目录
- 核心功能特点
- 局限性与替代方案
- 常用方法
- 构造函数
- 从数组创建图像
- 访问属性
- 访问像素点
- Windows平台支持
- 常用方法迁移至OpenCV
CxImage 是一款功能强大的图像处理类库,主要用于 Windows 平台的图像处理任务。它支持多种图像格式的加载、保存、编辑及特效处理,在早期的 Windows 应用开发中较为常见,尤其是在需要处理图像的桌面应用程序中。
源码下载 :https://sourceforge.net/projects/cximage/files/7.02/cximage702_full.7z/download
编译使用:Win32图片库CxImage在vs2022下的编译和使用
核心功能特点
- 多格式支持:
- 支持 BMP、JPEG、PNG、GIF、TIFF、ICO、WMF、EMF 等常见图像格式的读写操作。
- 可处理动画 GIF、多帧图像等特殊格式。
- 图像处理能力:
- 基础操作:缩放、旋转、裁剪、翻转、镜像等。
- 像素级编辑:调整亮度、对比度、饱和度,支持色彩空间转换(如 RGB 与 HSV 互转)。
- 特效处理:模糊、锐化、边缘检测、浮雕、素描等滤镜效果。
- 图像变换:透视变换、扭曲变形等几何操作。
- 实用功能:
- 图像叠加与混合:支持 alpha 通道处理,实现图像透明叠加。
- 缩略图生成:可快速生成指定尺寸的缩略图,保持比例或强制缩放。
- 图像信息获取:读取图像分辨率、色彩深度、文件大小等元数据。
- Windows平台的特殊支持
- 可以直接与DC交互。
局限性与替代方案
- 局限性:
- 仅支持 Windows 平台,跨平台兼容性差。
- 开发维护逐渐停滞,对新图像格式(如 WebP、HEIC)支持有限。
- 相比现代图像处理库,性能和内存管理存在优化空间。
- 现代替代方案:
- OpenCV:跨平台、功能全面的计算机视觉库,支持深度学习集成。
- libpng/libjpeg/tiff:专注于单一格式处理的底层库,稳定性高。
- Qt Image Processing:Qt 框架内置的图像处理模块,适合 Qt 应用开发。
- Magick++:ImageMagick 的 C++ 封装,支持丰富的图像特效与批处理。
常用方法
构造函数
CxImage(uint32_t imagetype = 0);
CxImage(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype = 0);
CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);
从数组创建图像
bool CreateFromArray(uint8_t* pArray,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);
bool CreateFromMatrix(uint8_t** ppMatrix,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);
访问属性
/** \addtogroup Attributes */ //@{int32_t GetSize();uint8_t* GetBits(uint32_t row = 0);uint8_t GetColorType();void* GetDIB() const;uint32_t GetHeight() const;uint32_t GetWidth() const;uint16_t GetBpp() const;uint32_t GetType() const;const char* GetLastError();void GetOffset(int32_t *x,int32_t *y);void SetOffset(int32_t x,int32_t y);
访问像素点
/** \addtogroup Pixel */ //@{bool IsInside(int32_t x, int32_t y);bool IsTransparent(int32_t x,int32_t y);bool GetTransparentMask(CxImage* iDst = 0);RGBQUAD GetPixelColor(int32_t x,int32_t y, bool bGetAlpha = true);uint8_t GetPixelIndex(int32_t x,int32_t y);uint8_t GetPixelGray(int32_t x, int32_t y);void SetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha = false);void SetPixelColor(int32_t x,int32_t y,COLORREF cr);void SetPixelIndex(int32_t x,int32_t y,uint8_t i);void DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, RGBQUAD color, bool bSetAlpha=false);void DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, COLORREF cr);void BlendPixelColor(int32_t x,int32_t y,RGBQUAD c, float blend, bool bSetAlpha = false);bool SetRectColor(int32_t left, int32_t top, int32_t right, int32_t bottom, RGBQUAD color, bool bSetAlpha = false);bool SetRectColor(RECT& rect, RGBQUAD color, bool bSetAlpha = false);
//@}
Windows平台支持
#if CXIMAGE_SUPPORT_WINDOWSint32_t Blt(HDC pDC, int32_t x=0, int32_t y=0);HBITMAP Draw2HBITMAP(HDC hdc, int32_t x, int32_t y, int32_t cx, int32_t cy, RECT* pClipRect, bool bSmooth);HBITMAP MakeBitmap(HDC hdc = NULL, bool bTransparency = false);HICON MakeIcon(HDC hdc = NULL, bool bTransparency = false);HANDLE CopyToHandle();bool CreateFromHANDLE(HANDLE hMem); //Windows objects (clipboard)bool CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0, bool bTransparency = false); //Windows resourcebool CreateFromHICON(HICON hico, bool bTransparency = false);int32_t Draw(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1, RECT* pClipRect = 0, bool bSmooth = false, bool bFlipY = false);int32_t Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false, bool bFlipY = false);int32_t Stretch(HDC hdc, int32_t xoffset, int32_t yoffset, int32_t xsize, int32_t ysize, uint32_t dwRop = SRCCOPY);int32_t Stretch(HDC hdc, const RECT& rect, uint32_t dwRop = SRCCOPY);int32_t Tile(HDC hdc, RECT *rc);int32_t Draw2(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1);int32_t Draw2(HDC hdc, const RECT& rect);//int32_t DrawString(HDC hdc, int32_t x, int32_t y, const char* text, RGBQUAD color, const char* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);int32_t DrawString(HDC hdc, int32_t x, int32_t y, const TCHAR* text, RGBQUAD color, const TCHAR* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);// <VATI> extensionsint32_t DrawStringEx(HDC hdc, int32_t x, int32_t y, CXTEXTINFO *pTextType, bool bSetAlpha=false );void InitTextInfo( CXTEXTINFO *txt );
protected:bool IsHBITMAPAlphaValid( HBITMAP hbmp );
public:
#endif //CXIMAGE_SUPPORT_WINDOWS
//@}// file operations
#if CXIMAGE_SUPPORT_DECODE
/** \addtogroup Decode */ //@{
#ifdef WIN32//bool Load(LPCWSTR filename, uint32_t imagetype=0);bool LoadResource(HRSRC hRes, uint32_t imagetype, HMODULE hModule=NULL);
#endif
常用方法迁移至OpenCV
CxImage创建图像
CxImage* mpCxImage;
mpCxImage->CreateFromArray(pArray, width, height, BitCount, dwBytesPerLine, TRUE);
OpenCV创建图像
cv::Mat mCvImage;
mCvImage = cv::Mat(height, width, CV_8UC3, pArray);
CxImage访问像素
RGBQUAD rgb = mpCxImage->GetPixelColor(pt.x, pt.y, false);
mpCxImage->SetPixelColor((int32_t)logicPt.x, (int32_t)logicPt.y, refColor);
OpenCV访问像素
RGBQUAD rgb;
const cv::Vec3b& pixel = mCvImage.at<cv::Vec3b>(pt.y, pt.x);
rgb.rgbBlue = pixel[0];
rgb.rgbGreen = pixel[1];
rgb.rgbRed = pixel[2];cv::Vec3b& pixel = mCvImage.at<cv::Vec3b>(pt.Y, pt.X);
pixel[0] = GetBValue(refColor);
pixel[1] = GetGValue(refColor);
pixel[2] = GetRValue(refColor);
CxImage绘制文字
CxImage::CXTEXTINFO info;
mpCxImage->InitTextInfo(&info);
_stprintf(info.lfont.lfFaceName, _T("Times New Roman"));
info.lfont.lfCharSet = GB2312_CHARSET;
info.lfont.lfHeight = 10;
info.fcolor = rgb;
info.opaque = 0;
sprintf_s(info.text, "%s", strinfo.c_str());//Y方向要镜像
mpCxImage->DrawStringEx(0, (int32_t)logicPt.x, GetHeight() - (int32_t)logicPt.y, &info);
OpenCV绘制文字
// 绘制文本
COLORREF rgb = theApp.GetMainFrame().GetImageMeasureTextColor();
cv::Scalar bgr = cv::Scalar(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
cv::putText(mCvImage,strinfo,cv::Point(sOutput.ShowPt[i].X, sOutput.ShowPt[i].Y),cv::FONT_HERSHEY_SIMPLEX,0.4,bgr,1,cv::LINE_AA);// 绘制文本背景
cv::rectangle(mCvImage,pos + cv::Point(0, baseline),pos + cv::Point(textSize.width, -textSize.height),bgr,cv::FILLED);
CxImage绘制到DC
mpCxImage->Draw(dc.GetSafeHdc(), CRect(pos.x - imageWidth / 2, pos.y - imageHeight / 2, pos.x + imageWidth / 2, pos.y + imageHeight / 2), NULL, IsSmoothMode());
OpenCV绘制到DC
//if (IsSmoothMode()) {
// cv::resize(originalImage, resizedImage, cv::Size(imageWidth, imageHeight), 0, 0, cv::INTER_LINEAR);
//}
//else {
// cv::resize(originalImage, resizedImage, cv::Size(imageWidth, imageHeight), 0, 0, cv::INTER_NEAREST);
//}
// 禁用GDI的平滑,因为已在OpenCV处理
Draw(dc.GetSafeHdc(), CRect(pos.x - imageWidth / 2, pos.y - imageHeight / 2, pos.x + imageWidth / 2, pos.y + imageHeight / 2), IsSmoothMode());// 转换为 BGRA 格式(兼容 GDI 的 Alpha 混合)
cv::Mat bgraImage;
switch (mCvImage.channels()) {case 1: cv::cvtColor(mCvImage, bgraImage, cv::COLOR_GRAY2BGRA); break;case 3: cv::cvtColor(mCvImage, bgraImage, cv::COLOR_BGR2BGRA); break;case 4: bgraImage = mCvImage.clone(); break;default: return false;
}// 创建 BITMAPINFO 结构
BITMAPINFOHEADER bi = { 0 };
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bgraImage.cols;
bi.biHeight = -bgraImage.rows; // 负值表示从上到下布局
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;// 设置缩放模式
SetStretchBltMode(hdc, smooth ? HALFTONE : COLORONCOLOR);
SetBrushOrgEx(hdc, 0, 0, NULL); // HALFTONE 模式需要重置原点// 绘制图像
int result = StretchDIBits(hdc,destRect.left, destRect.top, // 目标左上角destRect.Width(), destRect.Height(), // 目标尺寸0, 0, // 源图像起点bgraImage.cols, bgraImage.rows, // 源图像尺寸bgraImage.data, // 图像数据(BITMAPINFO*)&bi, // BITMAPINFODIB_RGB_COLORS, // 颜色格式SRCCOPY // 直接拷贝);
CxImage从资源ID读取图像
//bool LoadResource(HRSRC hRes, uint32_t imagetype, HMODULE hModule=NULL);
mCxImage.LoadResource(FindResource(hModule, MAKEINTRESOURCE(IDB_xxxxxx), _T("PNG")), 0);
OpenCV从资源ID读取图像
// 替换为你的资源ID,例如 IDB_PNG1
HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(IDB_xxxxxx), _T("PNG"));
if (!hResource) {// 资源未找到return;
}DWORD imageSize = SizeofResource(hModule, hResource);
HGLOBAL hMemory = LoadResource(hModule, hResource);
if (!hMemory) {// 加载资源失败return;
}void* pData = LockResource(hMemory);
if (!pData) {// 锁定资源失败return;
}// 复制到 std::vector<uchar> 中
std::vector<uchar> buffer((uchar*)pData, (uchar*)pData + imageSize);// 使用 OpenCV 解码图像
cv::Mat image = cv::imdecode(buffer, cv::IMREAD_UNCHANGED);
if (image.empty()) {// 图像解码失败return;
}// 现在你可以使用 image 进行后续操作
cv::imshow("Loaded Image", image);
cv::waitKey(0);