【问题标题】:C# bitblt bitmap render to controlC# bitblt 位图渲染控制
【发布时间】:2016-09-16 09:20:39
【问题描述】:

我从事一个小型实时项目,其中非常需要快速位图渲染技术。我需要每秒在图片框中显示许多(数百)个小块,我从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);

有人知道这里出了什么问题吗?我不断释放使用的资源(在绘画事件中)...为什么会出现此错误?

提前致谢。

【问题讨论】:

  • 异常中ParamName的值是多少?这应该会提示您遇到问题的对象:pTargetbmppSource 等。

标签: c# bitmap rendering gdi+


【解决方案1】:

有人知道这里出了什么问题吗?我不断释放使用的资源(在绘画事件中)...为什么会出现此错误?

实际上,您没有释放所有使用的资源,特别是bmp.GetHbitmap() 调用返回的位图句柄。正确的顺序是将原始默认位图句柄选回到设备上下文中,然后删除您的位图句柄,如SelectObject documentation 中所述:

此函数返回先前选择的指定类型的对象。应用程序在使用新对象完成绘制后,应始终将新对象替换为原始默认对象

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);

【讨论】:

  • 在运行几秒钟后我仍然遇到同样的错误。哈哈@Ivan Stoev
  • 那么您还有其他问题。例如,desktopDuplicator.GetLatestFrame(); 是什么(您将其分配给变量 frame 而不处理先前的值。frame.DesktopImage 是什么,并且您再次将其分配给 bmp 变量而不处理先前的值。 bmp 变量在线程之间不受保护。所以,我在答案中写的内容仍然适用,但您需要为其他部分提供更多信息(代码)。提供一些简单的 mcve 就像我为您所做的那样复制问题的上一个问题将有助于解决它。
  • 好吧...但我必须说像DrawImage()这样的gdi+方法工作得更快...
  • 好吧,我理解这种失望,但你是在比较苹果和橘子。 Gdi+ 版本在绘制整个屏幕时绘制小矩形。我认为问题是由于许多转换 - Lock/InlockBits、GetHBitmap / DeleteObject。使用 Gdi 也很困难,尤其是应用缩放。如果你一直拥有这个 Gdi 位图句柄而不是位图对象,并以某种方式更新它的一部分,并且只绘制无效的部分,那么我认为 Gdi 会更快。但简单地用这样的东西替换 DrawImage 是没有意义的。
【解决方案2】:

来自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);
}

【讨论】:

  • 抱歉回复晚了..我猜你是对的,但现在我在运行了几秒钟后抛出了“System.ArgumentException”bitblt 调用。 BitBlt(pTarget, 0, 0, bmp.Width, bmp.Height, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);@罗兰肖
猜你喜欢
  • 1970-01-01
  • 2013-04-29
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多