c# bitblt位图渲染控件
本文关键字:控件 位图 bitblt | 更新日期: 2023-09-27 18:07:17
我在一个小的实时项目中工作,其中快速位图渲染技术是非常必要的。我需要在一个图片框中每秒显示许多(数百)个小块,我从pinvoke.net网站找到了bitblt
的例子。
我使用一个while循环(现在它是无限的),检索一个特定的位图,然后调用Invalidate()
方法来触发Paint
事件。
这是我的代码:
protected override void OnPaint(PaintEventArgs e)
{
IntPtr pTarget = e.Graphics.GetHdc();
IntPtr pSource = CreateCompatibleDC(pTarget);
IntPtr pOrig = SelectObject(pSource, bmp.GetHbitmap());
BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
DeleteObject(pOrig);
DeleteDC(pSource);
e.Graphics.ReleaseHdc(pTarget);
}
private void Display()
{
while (true)
{
frame = desktopDuplicator.GetLatestFrame();
if (frame != null)
{
bmp = frame.DesktopImage;//retrieve image.
this.Invoke(new Action(() => this.Invalidate()));//trigger the repaint event
}
}
}
它工作很好几秒钟,然后我得到一个 System.ArgumentException
在这行:
BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
有人知道这里出了什么问题吗?我一直在释放已使用的资源(在paint事件中)…为什么我得到这个错误?
有人知道这里出了什么问题吗?我一直在释放已使用的资源(在paint事件中)…为什么我得到这个错误?
实际上你是而不是释放所有使用的资源,特别是bmp.GetHbitmap()
调用返回的位图句柄。正确的顺序是选择回原始的默认位图句柄到设备上下文中,然后删除您的位图句柄,如SelectObject
文档中所解释的:
此函数返回先前选定的指定类型的对象。应用程序应该在用新对象完成绘图后始终用原始的默认对象替换新对象。
IntPtr targetDC = e.Graphics.GetHdc();
IntPtr sourceDC = CreateCompatibleDC(targetDC);
IntPtr sourceBitmap = bmp.GetHbitmap();
IntPtr originalBitmap = SelectObject(sourceDC, sourceBitmap);
BitBlt(targetDC, 0, 0, bmp.Width, bmp.Height, sourceDC, 0, 0, TernaryRasterOperations.SRCCOPY);
SelectObject(sourceDC, originalBitmap);
DeleteObject(sourceBitmap);
DeleteDC(sourceDC);
e.Graphics.ReleaseHdc(targetDC);
Bitmap.GetHbitmap
方法的文档:
你负责调用GDI DeleteObject方法来释放GDI位图对象使用的内存。
当前似乎没有调用该函数,这将导致泄漏。你应该调用DeleteObject
一旦你完成了资源,所以可能像这样:
protected override void OnPaint(PaintEventArgs e)
{
IntPtr pTarget = e.Graphics.GetHdc();
IntPtr pSource = CreateCompatibleDC(pTarget);
IntPtr pOrig = SelectObject(pSource, bmp.GetHbitmap());
BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);
DeleteObject(pOrig);
DeleteDC(pSource);
e.Graphics.ReleaseHdc(pTarget);
}