C++图像处理 -- 数据类型及公用函数

本文介绍了一个C++头文件BmpData.h,它包含了Gdiplus.h文件,并提供了处理图像的基础函数。通过使用GDI+位图数据结构BitmapData,可以实现图像的读取、修改和保存。文章详细解释了如何设置和获取图像的插值模式、Alpha通道标志,以及如何锁定和解锁GDI+位图扫描线。此外,还提供了获取32位子位图数据结构的方法,以及如何释放分配的扫描线内存。本文旨在提供一种简单且高效的图像处理方式,适用于C++编程环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



阅读提示

    《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

    《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

    尽可能保持二者内容一致,可相互对照。

    因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

    这里可访问《C++图像处理 -- 文章索引

http://blog.youkuaiyun.com/maozefa/article/details/7188505

 

    不经意间,用C++写了不少有关图像处理的文章,与《Delphi图像处理》系列文章相比,文章之间缺乏必要的联系性,因此有必要进行一些调整,并都纳入《C++图像处理系列》。

    本文写了一个C++头文件BmpData.h,它包含了Gdiplus.h文件,并提供了几个最基础的函数。

    以后,所有《C++图像处理》系列的文章都包含此头文件,并直接使用GDI+位图数据结构BitmapData类型处理图像。例子也以GDI+位图为主。

[cpp]   view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //---------------------------------------------------------------------------  
  2. #ifndef BmpDataH  
  3. #define BmpDataH  
  4.   
  5. #include <windows.h>  
  6. #include <algorithm>  
  7. using std::min;  
  8. using std::max;  
  9. #include <gdiplus.h>  
  10. using namespace Gdiplus;  
  11. //---------------------------------------------------------------------------  
  12.   
  13. #define ScanAllocFlag       0x00000100  
  14. #define PixelAlphaFlag      0x00010000  
  15. //---------------------------------------------------------------------------  
  16.   
  17. // 定义象素插值方式  
  18. typedef enum  
  19. {  
  20.     InterpolateModeDefault, // 缺省为线形插值  
  21.     InterpolateModeNear,    // 临近插值  
  22.     InterpolateModeBilinear,// 线形插值  
  23.     InterpolateModeBicubic  // 双立方插值  
  24. }InterpolateMode;  
  25.   
  26. typedef enum  
  27. {  
  28. //  PixelFormatInValid,  
  29.     PixelFormat1bit,  
  30.     PixelFormat4bit,  
  31.     PixelFormat8bit,  
  32.     PixelFormat15bit,  
  33.     PixelFormat16bit,  
  34.     PixelFormat24bit,  
  35.     PixelFormat32bit  
  36. }ImagePixelFormat;  
  37.   
  38. // 定义ARGB像素结构  
  39. typedef union  
  40. {  
  41.     ARGB Color;  
  42.     struct  
  43.     {  
  44.         BYTE Blue;  
  45.         BYTE Green;  
  46.         BYTE Red;  
  47.         BYTE Alpha;  
  48.     };  
  49. }ARGBQuad, *PARGBQuad;  
  50. //---------------------------------------------------------------------------  
  51.   
  52. FORCEINLINE  
  53.   
  54. VOID SetAlphaFlag(BitmapData *data, BOOL isAlpha)  
  55.   
  56. {  
  57.   
  58.     if (isAlpha) data->Reserved |= PixelAlphaFlag;  
  59.   
  60.     else data->Reserved &= ~PixelAlphaFlag;  
  61.   
  62. }  
  63.   
  64. //---------------------------------------------------------------------------  
  65.   
  66. FORCEINLINE  
  67. BOOL HasAlphaFlag(CONST BitmapData *data)  
  68. {  
  69.     return (data->Reserved & PixelAlphaFlag) != 0;  
  70. }  
  71. //---------------------------------------------------------------------------  
  72.   
  73. FORCEINLINE  
  74. VOID SetInterpolateMode(BitmapData *data, InterpolateMode mode)  
  75. {  
  76.     data->Reserved = (data->Reserved & 0xffffff) | (mode << 24);  
  77. }  
  78. //---------------------------------------------------------------------------  
  79.   
  80. FORCEINLINE  
  81. InterpolateMode GetInterpolateMode(CONST BitmapData *data)  
  82.   
  83. {  
  84.   
  85.     return (InterpolateMode)(data->Reserved >> 24);  
  86.   
  87. }  
  88.   
  89. //---------------------------------------------------------------------------  
  90.   
  91.   
  92. // 锁定GDI+32位位图扫描线到data  
  93. FORCEINLINE  
  94. VOID LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)  
  95. {  
  96.     Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight());  
  97.     BOOL hasAlpha = bmp->GetPixelFormat() & PixelFormatAlpha;  
  98.     bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite,  
  99.         PixelFormat32bppARGB, data);  
  100.     SetAlphaFlag(data, hasAlpha);  
  101. }  
  102. //---------------------------------------------------------------------------  
  103.   
  104. // GDI+位图扫描线解锁  
  105. FORCEINLINE  
  106. VOID UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)  
  107. {  
  108.     data->Reserved &= 0xff;  
  109.     bmp->UnlockBits(data);  
  110. }  
  111. //---------------------------------------------------------------------------  
  112.   
  113. // 用给定的图像数据制造并返回与GDI+兼容的32位位图数据结构。  
  114. // 参数;宽度,高度,扫描线宽度,扫描线首地址,alpha标记,返回的位图数据结构指针。  
  115. // 注:如果stride=0,自动计算扫描线宽度  
  116. FORCEINLINE  
  117. VOID GetBitmapData(INT width, INT height, INT stride, LPVOID scan0,  
  118.     ImagePixelFormat format, BOOL isAlpha, BitmapData *data)  
  119. {  
  120.     INT bits[] = {0x100, 0x400, 0x800, 0x1005, 0x1000, 0x1800, 0x2000};  
  121.   
  122.     data->Width = width;  
  123.     data->Height = height;  
  124.     data->Scan0 = scan0;  
  125.     data->PixelFormat = bits[format];  
  126.     if (stride)  
  127.         data->Stride = stride;  
  128.     else  
  129.         data->Stride = (INT)((width * (data->PixelFormat >> 8) + 31) & ~31) >> 3;  
  130.     SetAlphaFlag(data, isAlpha);  
  131. }  
  132. //---------------------------------------------------------------------------  
  133.   
  134. // 用给定的宽度、高度和像素位数制造并返回新的与GDI+兼容的位图数据结构。  
  135. // 必须用FreeBitmapData释放  
  136. FORCEINLINE  
  137. VOID GetBitmapData(INT width, INT height, ImagePixelFormat format, BitmapData *data)  
  138. {  
  139.     GetBitmapData(width, height, 0, NULL, format, format == PixelFormat32bit, data);  
  140.     data->Scan0 = GlobalLock(GlobalAlloc(GHND, data->Height * data->Stride));  
  141.     if (data->Scan0) data->Reserved |= ScanAllocFlag;  
  142. }  
  143. //---------------------------------------------------------------------------  
  144.   
  145. // 用给定的宽度和高度制造并返回新的与GDI+兼容的32位位图数据结构。  
  146. // 必须用FreeBitmapData释放  
  147. FORCEINLINE  
  148. VOID GetBitmapData(INT width, INT height, BitmapData *data)  
  149. {  
  150.     GetBitmapData(width, height, PixelFormat32bit, data);  
  151. }  
  152. //---------------------------------------------------------------------------  
  153.   
  154. // 获取32位子位图数据结构  
  155. FORCEINLINE  
  156. BOOL GetBitmapData(CONST BitmapData *data, INT x, INT y, INT width, INT height, BitmapData *sub)  
  157. {  
  158.     width += x;  
  159.     height += y;  
  160.     if (width > (INT)data->Width)  
  161.         width = data->Width;  
  162.     if (height > (INT)data->Height)  
  163.         height = data->Height;  
  164.     INT ScanOffset = 0;  
  165.     if (x > 0)  
  166.     {  
  167.         width -= x;  
  168.         ScanOffset += (x << 2);  
  169.     }  
  170.     if (y > 0)  
  171.     {  
  172.         height -= y;  
  173.         ScanOffset += (y * data->Stride);  
  174.     }  
  175.     sub->Scan0 = (LPBYTE)data->Scan0 + ScanOffset;  
  176.     if (width <= 0 || height <= 0)  
  177.         return FALSE;  
  178.     sub->Width = width;  
  179.     sub->Height = height;  
  180.     sub->Stride = data->Stride;  
  181.     sub->PixelFormat = data->PixelFormat;  
  182.     sub->Reserved = data->Reserved & ~ScanAllocFlag;  
  183.     return TRUE;  
  184. }  
  185. //---------------------------------------------------------------------------  
  186.   
  187. // 如果data分配了扫描线内存,释放扫描线内存  
  188. FORCEINLINE  
  189. VOID FreeBitmapData(BitmapData *data)  
  190. {  
  191.     if ((data->Reserved & ScanAllocFlag) && data->Scan0)  
  192.     {  
  193.         HGLOBAL handle = GlobalHandle(data->Scan0);  
  194.         if (handle)  
  195.         {  
  196.             GlobalUnlock(handle);  
  197.             GlobalFree(handle);  
  198.         }  
  199.         data->Reserved = 0;  
  200.     }  
  201. }  
  202. //---------------------------------------------------------------------------  
  203.   
  204. // 获取32位位图数据拷贝参数  
  205.   
  206. // 参数:目标数据,源数据,宽度,高度,目标扫描线,源扫描线,目标偏移,源偏移  
  207.   
  208. FORCEINLINE  
  209.   
  210. VOID GetDataCopyParams(CONST BitmapData *dest, CONST BitmapData *source,  
  211.   
  212.     UINT &width, UINT &height, PARGBQuad &dstScan0, PARGBQuad &srcScan0,  
  213.   
  214.     INT &dstOffset, INT &srcOffset)  
  215.   
  216. {  
  217.   
  218.     width = dest->Width < source->Width? dest->Width : source->Width;  
  219.   
  220.     height = dest->Height < source->Height? dest->Height : source->Height;  
  221.     dstScan0 = (PARGBQuad)dest->Scan0;  
  222.     srcScan0 = (PARGBQuad)source->Scan0;  
  223.   
  224.     dstOffset = (dest->Stride >> 2) - (INT)width;  
  225.     srcOffset = (source->Stride >> 2) - (INT)width;  
  226. }  
  227. //---------------------------------------------------------------------------  
  228.   
  229. // 获取并返回32位位图数据结构data的边框扩展图像数据结构。Radius:扩展半径  
  230. FORCEINLINE  
  231. VOID GetExpendData(CONST BitmapData *data, UINT radius, BitmapData *exp)  
  232. {  
  233.     GetBitmapData(data->Width + (radius << 1), data->Height + (radius << 1),  
  234.         PixelFormat32bit, exp);  
  235.     SetAlphaFlag(exp, HasAlphaFlag(data));  
  236.     BitmapData sub;  
  237.     PARGBQuad pd, ps;  
  238.     UINT width, height;  
  239.     INT dstOffset, srcOffset;  
  240.     GetBitmapData(exp, radius, radius, data->Width, data->Height, &sub);  
  241.     GetDataCopyParams(&sub, data, width, height, pd, ps, dstOffset, srcOffset);  
  242.     PARGBQuad pt = pd - radius;  
  243.     UINT x, y;  
  244.     // 如果图像数据含Alpha,转换为PARGB像素格式  
  245.     if (HasAlphaFlag(data))  
  246.     {  
  247.         for (y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset)  
  248.         {  
  249.             for (x = 0; x < width; x ++, pd ++, ps ++)  
  250.             {  
  251.                 pd->Blue = (ps->Blue * ps->Alpha + 127) / 255;  
  252.                 pd->Green = (ps->Green * ps->Alpha + 127) / 255;  
  253.                 pd->Red = (ps->Red * ps->Alpha + 127) / 255;  
  254.                 pd->Alpha = ps->Alpha;  
  255.             }  
  256.         }  
  257.     }  
  258.     // 否则, 直接像素拷贝  
  259.     else  
  260.     {  
  261.         for (y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset)  
  262.         {  
  263.             for (x = 0; x < width; *pd ++ = *ps ++, x ++);  
  264.         }  
  265.     }  
  266.     // 扩展左右边框像素  
  267.     for (y = 0, pd = pt; y < height; y ++)  
  268.     {  
  269.         for (x = 0, ps = pd + radius; x < radius; *pd ++ = *ps, x ++);  
  270.         for (x = 0, pd += width, ps = pd - 1; x < radius; *pd ++ = *ps, x ++);  
  271.     }  
  272.     // 扩展头尾边框像素  
  273.     PARGBQuad pb = (PARGBQuad)((LPBYTE)pd - exp->Stride);  
  274.     PARGBQuad pd0 = (PARGBQuad)exp->Scan0;  
  275.     for (y = 0; y < radius; y ++)  
  276.     {  
  277.         for (x = 0; x < exp->Width; *pd0 ++ = pt[x], *pd ++ = pb[x], x ++);  
  278.     }  
  279. }  
  280. //---------------------------------------------------------------------------  
  281.   
  282. // PARGB格式转换成ARGB格式  
  283. FORCEINLINE  
  284. VOID PArgbConvertArgb(BitmapData *data)  
  285. {  
  286.     PARGBQuad p = (PARGBQuad)data->Scan0;  
  287.     INT dataOffset = (data->Stride >> 2) - (INT)data->Width;  
  288.     for (UINT y = 0; y < data->Height; y ++, p += dataOffset)  
  289.     {  
  290.         for (UINT x = 0; x < data->Width; x ++, p ++)  
  291.         {  
  292.             p->Blue = p->Blue * 255 / p->Alpha;  
  293.             p->Green = p->Green * 255 / p->Alpha;  
  294.             p->Red = p->Red * 255 / p->Alpha;  
  295.         }  
  296.     }  
  297. }  
  298. //---------------------------------------------------------------------------  
  299.   
  300. // ARGB格式转换成PARGB格式  
  301. FORCEINLINE  
  302. VOID ArgbConvertPArgb(BitmapData *data)  
  303. {  
  304.     PARGBQuad p = (PARGBQuad)data->Scan0;  
  305.     INT dataOffset = (data->Stride >> 2) - (INT)data->Width;  
  306.     for (UINT y = 0; y < data->Height; y ++, p += dataOffset)  
  307.     {  
  308.         for (UINT x = 0; x < data->Width; x ++, p ++)  
  309.         {  
  310.             p->Blue = (p->Blue * p->Alpha + 127) / 255;  
  311.             p->Green = (p->Green * p->Alpha + 127) / 255;  
  312.             p->Red = (p->Red * p->Alpha + 127) / 255;  
  313.         }  
  314.     }  
  315. }  
  316. //---------------------------------------------------------------------------  
  317.   
  318.   
  319. #endif  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值