如何在 C++/MFC/GDI 中创建一个非常大的位图

Posted

技术标签:

【中文标题】如何在 C++/MFC/GDI 中创建一个非常大的位图【英文标题】:How to create a very big bitmap in C++/MFC / GDI 【发布时间】:2010-09-13 09:07:10 【问题描述】:

我希望能够在 C++ MFC 应用程序中创建一个大的(比如 20,000 x 20,000)像素位图,使用 CDC 派生类写入位图。我已尝试使用 MSDN 文档中描述的内存 DC,但这些似乎仅限于与当前显示驱动程序兼容的大小。

我目前正在使用位图打印驱动程序来完成这项工作,但由于假脱机 GDI 信息,它非常慢并且使用大量中间存储。

我正在寻找的解决方案不应涉及元文件或假脱机,因为我正在绘制的模型需要数百万次 GDI 调用才能呈现。

我可以通过多个内存 DC 使用分而治之的方法,但这似乎是一种相当麻烦且不优雅的技术。

有什么想法吗?

【问题讨论】:

【参考方案1】:

CDC 和 CBitmap 似乎只支持与设备相关的位图,您可能会更幸运地使用 ::CreateDIBSection 创建位图,然后将 CBitmap 附加到该位图。不幸的是,原始的 GDI 接口有点陈旧。

至少在 32 位应用程序中,32 BPP 的 20,000 x 20,000 可能不会有太大的运气,因为它大约有 1.5 GB 的内存,但我得到了一个有效的 HBITMAP 16 bpp:

BITMAPINFOHEADER bmi =  sizeof(bmi) ;
bmi.biWidth = 20000;
bmi.biHeight = 20000;
bmi.biPlanes = 1;
bmi.biBitCount = 16;
HDC hdc = CreateCompatibleDC(NULL);
BYTE* pbData = 0;
HBITMAP hbm = CreateDIBSection(hdc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&pbData, NULL, 0);
DeleteObject(SelectObject(hdc, hbm));

【讨论】:

谢谢西蒙,正是我所追求的。我是每像素 8 位,所以应该没问题。【参考方案2】:

这很不寻常,因为我经常根据屏幕创建一个 DC,该 DC 将用于比屏幕大得多的位图图像 - 在某些情况下超过 3000 像素 - 完全没有问题。你有一些示例代码来显示这个问题吗?

【讨论】:

【参考方案3】:

考虑到如此大的图像分辨率,您无法使用兼容的位图创建图像。

例子:

像素深度 = 32 位 = 每像素 4 字节

像素数 = 20.000 * 20.000 = 400.000.000

总字节数 = 像素数 * 4 = 1.600.000.000 字节 = 1.562.500 kb ~= 1525 MB ~= 1.5GB

我在推测最终意图,但假设您想要创建并允许用户探索具有非常详细缩放的巨大地图。 您应该创建自定义图像文件格式;例如,您可以在该文件中放入包含位图网格的各种图层,以加快渲染速度。渲染过程可以使用 GDI DIB 或 GDI+ 来创建部分图像,然后将它们一起渲染。当然,这需要一些试验/优化才能达到完美的用户体验。

祝你好运

【讨论】:

xoreax,大小非常合适,并且与地图应用程序一致。颜色深度是一个托盘化的 8 位,对于原始位图来说,它的大小略低于 400mb,比 JPEG 小得多。西蒙,你的 CreateDIB 答案现在就成功了。稍后我会检查 SVG。【参考方案4】:

为了将内存使用量保持在可接受的范围内,您必须使用“分而治之”的策略。这不是 hack,如果实施得当,它实际上是一种非常优雅的方式来处理无限大小的位图。如果设计得当,您可以结合“仅渲染/显示图像的一部分”、“以低分辨率渲染整个图像以在屏幕上显示”和“将整个图像渲染到磁盘上的位图”方法一个引擎并保护您的代码的用户(很可能是您自己在两周内;))免受内部影响。我开发的产品存在同样的问题:将(可能很大)映射到屏幕或 .bmp 文件。

【讨论】:

谢谢,罗尔。我认为分而治之与西蒙的大型位图代码相结合是一个很好的长期解决方案。可能使用滚动垂直扫描、较大的缓冲区,并在缓冲区耗尽时刷新并重复。【参考方案5】:

如果图像必须是这个分辨率 - 比如说 X 射线的高分辨率扫描 - 那么您可能需要考虑为它编写自定义假脱机例程 - 1.5 GB 非常昂贵 - 即使对于现代台式机也是如此。

如果它是基于矢量的,那么您可以查看 SVG,因为它支持视口,并且大多数允许您渲染为其他格式。我通过 Batik (java) 使用 SVG 到 JPG,所以可以这样做。

【讨论】:

以上是关于如何在 C++/MFC/GDI 中创建一个非常大的位图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中创建一个位数组?

c ++:在数学错误中创建实际错误而不是nan

如何在 Angular2 中创建拦截器?

如何在 C++ 中创建一个位于堆而不是堆栈的数组?

如何在 grafana 图表中创建趋势线

什么是哈希表以及如何在 C 中创建它? [关闭]