阅读提示:
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
尽可能保持二者内容一致,可相互对照。
本文代码必须包括《C++图像处理 -- 数据类型及公用函数》文章中的BmpData.h头文件以及《C++图像处理 -- 图像合成》中的有关代码。
在《C++图像处理 -- 图像合成》一文中开始时说过,图像的合成操作包括图像显示、图像拷贝、图像拼接以及的图层拼合叠加等,本文在《C++图像处理 -- 图像合成》代码基础上介绍如何在Windows环境下进行图像显示。
图像显示代码如下:
VOID GetBitmapInfoHeader(CONST BitmapData *data, CONST PBITMAPINFO pbi) { pbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbi->bmiHeader.biWidth = data->Width; pbi->bmiHeader.biHeight = data->Height; pbi->bmiHeader.biPlanes = 1; pbi->bmiHeader.biBitCount = (data->PixelFormat >> 8) & 0xff; pbi->bmiHeader.biCompression = BI_RGB; } //--------------------------------------------------------------------------- VOID GetDCImageData(HDC DC, INT x, INT y, BitmapData *data, PBITMAPINFO pbi) { HBITMAP bitmap = CreateCompatibleBitmap(DC, data->Width, data->Height); HDC memDC = CreateCompatibleDC(DC); HBITMAP saveBitmap = (HBITMAP)SelectObject(memDC, bitmap); BitBlt(memDC, 0, 0, data->Width, data->Height, DC, x, y, SRCCOPY); SelectObject(memDC, saveBitmap); DeleteDC(memDC); GetDIBits(DC, bitmap, 0, data->Height, data->Scan0, pbi, DIB_RGB_COLORS); DeleteObject(bitmap); } //--------------------------------------------------------------------------- VOID BitBltImageData(HDC DC, INT x, INT y, CONST BitmapData *data, PBITMAPINFO pbi) { HBITMAP bitmap = CreateDIBitmap(DC, &pbi->bmiHeader, CBM_INIT, data->Scan0, pbi, DIB_RGB_COLORS); HDC memDC = CreateCompatibleDC(DC); HBITMAP saveBitmap = (HBITMAP)SelectObject(memDC, bitmap); BitBlt(DC, x, y, data->Width, data->Height, memDC, 0, 0, SRCCOPY); SelectObject(memDC, saveBitmap); DeleteDC(memDC); DeleteObject(bitmap); } //--------------------------------------------------------------------------- // 显示图像。参数:设备句柄,x坐标,y坐标,图像数据,不透明度(0 - 1) VOID ImageDraw(HDC DC, INT x, INT y, CONST BitmapData *data, float alpha = 1.0f) { BITMAPINFO bi; RECT r, r2; LPVOID scan0; BitmapData dst, src; // 获取DC可见矩形 if (GetClipBox(DC, &r) <= NULLREGION) return; r.left = r.top = 0; r2.left = x; r2.top = y; r2.right = data->Width + x; r2.bottom = data->Height + y; // 计算data与DC的交集到r,同时获取实际显示的子图像数据src if (!IntersectRect(&r, &r, &r2)) return; GetBitmapData(data, x < 0? -x : 0, y < 0? -y : 0, r.right - r.left, r.bottom - r.top, &src); // 按src尺寸建立新的32位图像数据dst dst.Width = src.Width; dst.Height = src.Height; dst.Stride = dst.Width << 2; dst.Scan0 = scan0 = (LPVOID)new CHAR[dst.Height * dst.Stride]; dst.Reserved = 0; GetBitmapInfoHeader(&src, &bi); // 如果alpha<1,或者data含Alpha信息,获取DC可见区域图像到dst if (alpha < 1.0f || HasAlphaFlag(data)) GetDCImageData(DC, r.left, r.top, &dst, &bi); // dst扫描线内存转换成Windows位图格式 dst.Scan0 = (LPBYTE)scan0 + (dst.Height - 1) * dst.Stride; dst.Stride = -dst.Stride; // 图像混合 ImageMixer(&dst, &src, alpha); // 还原dst扫描线内存格式后,传输到DC dst.Scan0 = scan0; BitBltImageData(DC, r.left, r.top, &dst, &bi); delete[] scan0; } //---------------------------------------------------------------------------
从上面代码看,图像显示就是Windows API和《C++图像处理 -- 图像合成》几个图像合成函数的组合。
下面用《C++图像处理 -- 图像合成》中的例子,将其中的GDI+显示方法改为本文的ImageDraw函数:
void __fastcall TForm1::Button1Click(TObject *Sender) { Gdiplus::Bitmap *dest = new Gdiplus::Bitmap(L"..\\..\\media\\xmas_011.png"); Gdiplus::Bitmap *source = new Gdiplus::Bitmap(L"..\\..\\media\\Apple.png"); // Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle); // g->DrawImage(dest, 0, 0); // g->DrawImage(source, dest->GetWidth(), 0); BitmapData dst, src; LockBitmap(dest, &dst); LockBitmap(source, &src); ImageDraw(Canvas->Handle, 0, 0, &dst, 1); // ImageDraw(Canvas->Handle, dst.Width, 0, &src, 1); // ImageMixer(&dst, &src, 0.75); ImageDraw(Canvas->Handle, dst.Width << 1, 0, &dst, 1);// UnlockBitmap(source, &src); UnlockBitmap(dest, &dst); // g->DrawImage(dest, dest->GetWidth() << 1, 0); // delete g; delete source; delete dest; } //---------------------------------------------------------------------------
运行效果与《C++图像处理 -- 图像合成》例子效果是一样的,截图如下:
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:[email protected]
这里可访问《C++图像处理 -- 文章索引》。