【问题标题】:Unit testing of control drawing in GDIGDI中控制绘图的单元测试
【发布时间】:2011-06-16 21:50:45
【问题描述】:

我有一个使用 WinAPI 用 C++ 编写的控件,我想自动测试它是否正确绘制。我可以将绘制的图像与保存的参考图像进行比较,也可以简单地测试特定像素是否具有特定颜色。我已经实现了这两种类型。

问题是测试现在也在每晚都在虚拟机上运行,​​由于某种原因,该虚拟机只有 16 位色深。这会导致颜色稍微偏离。我试图想出在 16 位色深中绘制时不会改变的颜色,但舍入方案似乎相当复杂,我需要测试在 32b 和 16b 色深中都能正常工作。

另一个想法是创建一个始终具有 32b 色深的离屏位图。这样做的好处是测试每次都使用相同的环境,但我无法让它工作。无论屏幕颜色深度如何,如何创建 32b HBITMAP 和 HDC?或者您有其他解决一般问题的技巧吗?

谢谢

【问题讨论】:

    标签: unit-testing winapi drawing gdi


    【解决方案1】:

    如何创建 32b 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:我在我的 32bpp 彩色窗口上成功创建了 mem_dc 为 4bpp、8bpp 和 16bpp。你的意思是升级不起作用?请重新检查。该问题也可能与将您的结果与参考图像进行比较的代码有关
    • 这段代码确实有效,感谢您的帮助,我发现了一个错误。
    【解决方案2】:

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

    CreateEnhMetaFile 是一个起点。

    【讨论】:

      【解决方案3】:

      如何使用 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 无法在与桌面不同的颜色深度下工作,所以感谢您的提示。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-07-06
          • 1970-01-01
          • 1970-01-01
          • 2011-08-29
          • 2014-09-13
          • 2018-08-03
          相关资源
          最近更新 更多