阅读提示:
《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++图像处理 -- 图像合成》例子效果是一样的,截图如下:
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com
这里可访问《C++图像处理 -- 文章索引》。