GDI中控制绘图的单元测试

3
我有一个使用WinAPI编写的C++控件,我希望能够自动测试它是否正确绘制。我可以将绘制出来的图像与保存的参考图像进行比较,也可以测试特定像素的颜色是否正确。我已经实现了这两种类型的测试。
问题在于,这些测试现在每晚都在一个虚拟机上运行,该虚拟机只支持16位颜色深度,导致颜色会稍微偏差。我尝试过使用不会因16位颜色深度而改变的颜色,但舍入方案似乎相当复杂,我需要让测试在32位和16位颜色深度下都有效。
另一个想法是创建一个始终具有32位颜色深度的离屏位图。这样做的好处是测试每次都使用相同的环境,但我无法使其正常工作。如何创建一个32位HBITMAP和HDC,无论屏幕颜色深度如何?或者您有其他解决一般问题的建议吗?
谢谢
5个回答

2
无论屏幕颜色深度如何,我该如何创建32位的HBITMAP和HDC呢?
很简单:
BITMAPINFO bmp_info = {};
bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmp_info.bmiHeader.biWidth = width;
bmp_info.bmiHeader.biHeight = height;
bmp_info.bmiHeader.biPlanes = 1;
bmp_info.bmiHeader.biBitCount = 32;
bmp_info.bmiHeader.biCompression = BI_RGB;

HDC mem_dc = CreateCompatibleDC(0);
void *dummy;
HBITMAP bitmap_handle = CreateDIBSection(mem_dc, &bmp_info, DIB_RGB_COLORS, &dummy, NULL, 0);
SelectObject(mem_dc, bitmap_handle));

现在在这个DC上绘制您的按钮。记得检查错误并释放资源。

或者,将您的按钮引用视图自动转换为实际桌面模式:

HWND desktop = GetDesktopWindow();
HDC desktop_dc = GetDC(desktop);
HDC mem_dc = CreateCompatibleDC(desktop_dc); 
RECT rect;
GetClientRect(desktop, &rect);
HBITMAP bitmap_handle = CreateCompatibleBitmap(desktop_dc, rect.right - rect.left, rect.bottom - rect.top);
SelectObject(mem_dc, bitmap_handle);

现在使用BitBlt将预加载的图像覆盖到mem_dc上。它会自动转换为当前桌面颜色模式。


我尝试了这段代码,但是似乎从0(屏幕)创建mem_dc会使它再次变为16b,因此它无法工作。 - Roman Plášil
@Roman:我已经成功在32bpp颜色的Windows上创建了mem_dc,使其成为4bpp、8bpp和16bpp。你的意思是说放大不起作用吗?请再检查一下。此外,问题可能与比较你的结果与参考图像的代码有关。 - Andriy Tylychko
这段代码确实可行,我在你的帮助下发现了我的一个错误。 - Roman Plášil

1
使用GDI+创建离屏位图,然后使用GDI绘制到它上面,类似于这样的方式:
int width=64; // or whatever you need
int height=100;
int stride = width*4;
BYTE buffer[stride*height];
Gdiplus::Bitmap bitmap(width, height, stride, PixelFormat32bppARGB, buffer);
Gdiplus::Graphics g (&bitmap);
HDC dc = g.GetHDC();

// drawing code, using WinAPI, to draw to dc

g.ReleaseHDC();

// Now compare the contents of your buffer

关于 GDI/GDI+ 互操作的更多信息,请参见此处:http://support.microsoft.com/kb/311221


最终我使用GDI+加载图像,因为OleLoadPicture在不同的颜色深度下无法工作,所以感谢您的提示。 - Roman Plášil

1

将您的测试更改为如果与32位图像或16位图像的比较是OK,则通过。捕获32位版本和16位版本(运行虚拟)。这非常快速且易于实现。

您应该已经有一种自动方式来捕获代码已知良好版本的参考图像。如果没有,请立即执行此操作,因为当您对控件的外观进行小更改时,它将为您节省时间。现在,您已经拥有回归测试的参考。


1

我通过在 WMF(现在是 EMF)文件中绘制来进行了 GDI 单元测试。它可以复制源设备(以及后续目标设备)的分辨率和 DPI,但我不记得颜色深度是否是一个“黏性”属性。即使是这样,由于文件格式允许您捕获/重放 GDI 序列,最终您可能会得到更准确的单元测试结果。我们会解释 WMF 文件以确保我们生成了我们认为应该生成的内容。

CreateEnhMetaFile 是一个起点。


0
要么像你说的那样创建一个32bpp离屏表面,要么使用你的比较参考图像执行完全相同的操作,这样你就可以同时测试两个bpp。换句话说,不要自己进行四舍五入;让GDI系统对两个表面进行相同的四舍五入。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接