gdi+ Graphics::DrawImage真的很慢~~
我正在使用 GDI+ Graphic 将 4000*3000 图像绘制到屏幕上,但速度非常慢。 大约需要300ms。 我希望它占用的时间少于 10 毫秒。
Bitmap *bitmap = Bitmap::FromFile("XXXX",...);
//-------------------------------------------------------- // 这部分大约需要 300ms,太糟糕了!
int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
DrawImage(bitmap,0,0,width,height);
//-----------------------------------------
我无法使用 CachedBitmap,因为我想稍后编辑位图。
我该如何改进它? 或者有什么问题吗?
这个原生 GDI 函数还将图像绘制到屏幕上,并且只需要 1 毫秒:
SetStretchBltMode(hDC, COLORONCOLOR);
StretchDIBits(hDC, rcDest.left, rcDest.top,
rcDest.right-rcDest.left, rcDest.bottom-rcDest.top,
0, 0, width, height,
BYTE* dib, dibinfo, DIB_RGB_COLORS, SRCCOPY);
//-------------------------------------------- ---------------------------------
如果我想使用StretchDIBits,我需要传递BITMAPINFO,但是我该怎么办从 Gdi+ 位图对象获取 BITMAPINFO? 我通过FreeImage lib做了实验,我使用FreeImageplus对象调用StretchDIBits,它绘制得非常快。 但是现在我需要绘制Bitmap,并在Bitmap的位数组上编写一些算法,如果我有一个Bitmap对象,如何获取BITMAPINFO? 真是烦人-___________-|
I am using a GDI+ Graphic to draw a 4000*3000 image to screen, but it is really slow. It takes about 300ms. I wish it just occupy less than 10ms.
Bitmap *bitmap = Bitmap::FromFile("XXXX",...);
//--------------------------------------------
// this part takes about 300ms, terrible!
int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
DrawImage(bitmap,0,0,width,height);
//------------------------------------------
I cannot use CachedBitmap, because I want to edit the bitmap later.
How can I improve it? Or is any thing wrong?
This native GDI function also draws the image into the screen, and it just take 1 ms:
SetStretchBltMode(hDC, COLORONCOLOR);
StretchDIBits(hDC, rcDest.left, rcDest.top,
rcDest.right-rcDest.left, rcDest.bottom-rcDest.top,
0, 0, width, height,
BYTE* dib, dibinfo, DIB_RGB_COLORS, SRCCOPY);
//--------------------------------------------------------------
If I want to use StretchDIBits, I need to pass BITMAPINFO, But how can I get BITMAPINFO from a Gdi+ Bitmap Object? I did the experiment by FreeImage lib, I call StretchDIBits using FreeImageplus object, it draw really fast. But now I need to draw Bitmap, and write some algorithm on Bitmap's bits array, how can I get BITMAPINFO if I have an Bitmap object? It's really annoying -___________-|
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
如果您使用 GDI+,TextureBrush 类就是您快速渲染图像所需要的。 我用它编写了几个 2D 游戏,帧速率约为 30 FPS 左右。
我从未用 C++ 编写过 .NET 代码,因此这里有一个 C# 风格的示例:
If you're using GDI+, the TextureBrush class is what you need for rendering images fast. I've written a couple of 2d games with it, getting around 30 FPS or so.
I've never written .NET code in C++, so here's a C#-ish example:
您的屏幕分辨率为 4000 x 3000? 哇!
如果没有,你应该只绘制图像的可见部分,它会快得多...
[第一个评论后编辑]我的评论确实有点愚蠢,我想 DrawImage 会屏蔽/跳过不需要的像素。
编辑后(显示 StretchDIBits),我猜速度差异的可能来源可能来自以下事实: StretchDIBits 是硬件加速的(“如果驱动程序无法支持 JPEG 或 PNG 文件图像”是一个提示...),而 DrawImage 可能是(我没有证据证明这一点!)用 C 编码,依赖于 CPU 能力而不是 GPU 的能力...
如果我没记错的话,DIB 图像速度很快(尽管是“设备独立”)。 请参阅高速 Win32 动画:“使用CreateDIBSection来做高速动画”。 好吧,它适用于旧 Windows 版本(1996!)中的 DIB 与 GDI,但我认为这仍然是正确的。
[编辑] 也许 Bitmap::GetHBITMAP 函数可能帮助您使用 StretchDIBits(未测试...)。
You have a screen of 4000 x 3000 resolution? Wow!
If not, you should draw only the visible part of the image, it would be much faster...
[EDIT after first comment] My remark is indeed a bit stupid, I suppose DrawImage will mask/skip unneeded pixels.
After your edit (showing StretchDIBits), I guess a possible source of speed difference might come from the fact that StretchDIBits is hardware accelerated ("If the driver cannot support the JPEG or PNG file image" is a hint...) while DrawImage might be (I have no proof for that!) coded in C, relying on CPU power instead of GPU's one...
If I recall correctly, DIB images are fast (despite being "device independent"). See High Speed Win32 Animation: "use CreateDIBSection to do high speed animation". OK, it applies to DIB vs. GDI, in old Windows version (1996!) but I think it is still true.
[EDIT] Maybe Bitmap::GetHBITMAP function might help you to use StretchDIBits (not tested...).
/*
首先对我的英语感到抱歉,代码部分是波兰语的,但很容易理解。
我遇到了同样的问题,并且找到了最好的解决方案。 这里是。
不要使用:图形graphics(hdc); 图形.DrawImage(gpBitmap, 0, 0); 它很慢。
使用:GetHBITMAP(Gdiplus::Color(), &g_hBitmap) 获取 HBITMAP 并使用我的函数 ShowBitmapStretch() 进行绘制。
您可以调整它的大小,而且速度要快得多! 阿图尔·切卡尔斯基 / 波兰
*/
/*
First sorry for ma English, and the code is partly in polish, but it's simple to understand.
I had the same problem and I found the best solution. Here it is.
Dont use: Graphics graphics(hdc); graphics.DrawImage(gpBitmap, 0, 0); It is slow.
Use: GetHBITMAP(Gdiplus::Color(), &g_hBitmap) for HBITMAP and draw using my function ShowBitmapStretch().
You can resize it and it is much faster! Artur Czekalski / Poland
*/
只是一个想法; 为什么不在加载图像时缓存这些值,而不是在绘制之前检索图像的宽度和高度?
Just a thought; instead of retrieving the width and height of the image before drawing, why not cache these values when you load the image?
探索将插值模式显式设置为 NearestNeighbor 的影响(在您的示例中,看起来实际上不需要插值!但是 300 毫秒是不需要插值时进行高质量插值的成本,因此值得一试)尝试)
另一件事要探索的是改变位图的颜色深度。
Explore the impact of explicitly setting the interpolation mode to NearestNeighbor (where, in your example, it looks like interpolation is not actually needed! But 300ms is the kind of cost of doing high-quality interpolation when no interpolation is needed, so its worth a try)
Another thing to explore is changing the colour depth of the bitmap.
不幸的是,当我遇到类似的问题时,我发现 GDI+ 已知比 GDI 慢得多,并且通常不进行硬件加速,但现在 Microsoft 已经转向 WPF,他们不会回来改进 GDI+!
所有显卡制造商都已转向 3D 性能,并且似乎对 2D 加速不感兴趣,并且没有关于哪些功能可以或可以硬件加速或不硬件加速的明确信息来源。 非常令人沮丧,因为我使用 GDI+ 在 .NET 中编写了一个应用程序,但我不乐意更改为完全不同的技术以将其速度提高到合理的水平。
Unfortunately when I had a similar problem, I found that GDI+ is known to be much slower than GDI and not generally hardware accelerated, but now Microsoft have moved on to WPF they will not come back to improve GDI+!
All the graphics card manufacturers have moved onto 3D performance and don't seem interested in 2D acceleration, and there's no clear source of information on which functions are or can be hardware accelerated or not. Very frustrating because having written an app in .NET using GDI+, I am not happy to change to a completely different technology to speed it up to reasonable levels.
我认为它们不会有太大不同,但由于您实际上不需要调整图像大小,请尝试使用 DrawImage 不会(尝试)调整大小:
就像我说的,我怀疑这会产生任何影响,因为我确定< /em> DrawImage 检查位图的宽度和高度,如果不需要调整大小,则只需调用此重载。 (我希望它不会费心去遍历所有 1200 万像素而不执行任何实际工作)。
更新:我的想法是错误的。 我后来发现了,但大家的评论让我想起了我的旧答案:你想要指定目标大小; 即使它与源尺寸匹配:
原因是位图的 dpi 和目标的 dpi 之间存在 dpi 差异。 GDI+ 将执行缩放以使图像达到正确的“尺寸”(即以英寸为单位)
自去年 10 月以来我自己了解到的是,您确实想要绘制一个“缓存”位图的版本。 GDI+ 中有一个 CachedBitmap 类。 使用它有一些技巧。 但最终我有一个(Delphi)代码的功能位可以做到这一点。
需要注意的是,
CachedBitmap
可能会变得无效 - 这意味着它不能用于绘制。 如果用户更改分辨率或颜色深度(例如远程桌面),就会发生这种情况。 在这种情况下,DrawImage
将失败,您必须重新创建CachedBitmap
:cachedBitmap
是通过引用传入的。 第一次调用DrawCachedBitmap
将创建它的缓存版本。 然后,您可以在后续调用中传递它,例如:我使用例程在按钮上绘制字形,同时考虑当前的 DPI。 当用户运行高 dpi 时(即绘制缩放图像非常慢,因为他们使用 GDI+),Internet Explorer 团队也可以使用相同的方法来绘制图像。
i don't think they'll make much of a different, but since you're not actually needing to resize the image, try using the overload of DrawImage that doesn't (attempt) to resize:
Like i said, i doubt it will make any difference, because i'm sure that DrawImage checks the Width and Height of the bitmap, and if there's no resizing needed, just calls this overload. (i would hope it doesn't bother going through all 12 million pixels performing no actual work).
Update: My ponderings are wrong. i had since found out, but guys comment reminded me of my old answer: you want to specify the destination size; even though it matches the source size:
The reason is because of dpi differences between the dpi of
bitmap
and the dpi of the destination. GDI+ will perform scaling to get the image to come out the right "size" (i.e. in inches)What i've learned on my own since last October is that you really want to draw a "cached" version of your bitmap. There is a
CachedBitmap
class in GDI+. There are some tricks to using it. But in there end i have a function bit of (Delphi) code that does it.The caveat is that the
CachedBitmap
can become invalid - meaning it can't be used to draw. This happens if the user changes resolutions or color depths (e.g. Remote Desktop). In that case theDrawImage
will fail, and you have to re-created theCachedBitmap
:The
cachedBitmap
is passed in by reference. The first call toDrawCachedBitmap
it cached version will be created. You then pass it in subsequent calls, e.g.:i use the routine to draw glyphs on buttons, taking into account the current DPI. The same could have been used by the Internet Explorer team to draw images when the user is running high dpi (ie is very slow drawing zoomed images, because they use GDI+).
尝试使用文件中的位图副本。 某些文件上的 FromFile 函数返回“慢速”图像,但其副本绘制速度会更快。
Try using copy of Bitmap from file. FromFile function on some files returns "slow" image, but its copy will draw faster.
我做了一些研究,但无法找到一种使用 GDI/GDI+ 渲染图像的方法,比
它更快,同时又更简单。
直到我发现
,是的,它真的是如此快速和简单。
I have made some researching and wasn't able to find a way to render images with GDI/GDI+ more faster than
and at the same time simple like it.
Till I discovered
and yeah it's really so fast and simple.