【问题标题】:Copy Graphics content to bitmap将图形内容复制到位图
【发布时间】:2011-07-30 22:18:44
【问题描述】:

我尝试将图形对象的内容复制到位图。我正在使用此代码

public static class GraphicsBitmapConverter
{
    [DllImport("gdi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

    public static Bitmap GraphicsToBitmap(Graphics g, Rectangle bounds)
    {
        Bitmap bmp = new Bitmap(bounds.Width, bounds.Height);

        using (Graphics bmpGrf = Graphics.FromImage(bmp))
        {
            IntPtr hdc1 = g.GetHdc();
            IntPtr hdc2 = bmpGrf.GetHdc();

            BitBlt(hdc2, 0, 0, bmp.Width, bmp.Height, hdc1, 0, 0, TernaryRasterOperations.SRCCOPY);

            g.ReleaseHdc(hdc1);
            bmpGrf.ReleaseHdc(hdc2);
        }

        return bmp;
    }
}

如果我使用这样的方法

Graphics g = button1.CreateGraphics();
var bmp = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));

位图包含内容。但是,如果我在调用方法之前在图形对象上绘制,则位图是空白的:

using (Bitmap bmp = new Bitmap(100, 100))
{
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
        g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);
        g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);

        var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));
    }
}

为什么它在第一种情况下有效,而在后一种情况下无效?

【问题讨论】:

  • 你在检查BitBlt()的返回值吗?也许它失败了,可能会导致线索。
  • 代码不完整

标签: c# graphics bitmap gdi+ bitblt


【解决方案1】:

据我了解

    Graphics g = Graphics.FromImage(bmp)

创建一个 Graphics 上下文用于将图像绘制到 中,而

    Graphics g = button1.CreateGraphics();

为已经绘制到屏幕上的控件创建一个。您可以将动态创建的位图绘制到 PictureBox,然后执行与按钮相同的操作,例如

        using (Bitmap bmp = new Bitmap(100, 100)) 
            {
            using (Graphics g = Graphics.FromImage(bmp)) 
                {
                g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);
                g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
                g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);

                pictureBox1.Image = bmp;
                pictureBox1.Update(); // force an update before doing anything with it
                Graphics g2 = pictureBox1.CreateGraphics();
                var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g2, Rectangle.Truncate(g.VisibleClipBounds)); 
                // bmp2 now has the same contents as bmp1
                pictureBox1.Image = null; // bmp is about to be Disposed so remove the reference to it
                }
            }

当然,这只是重新创建您已经拥有的位图,所以我假设您还有其他用途。

【讨论】:

    【解决方案2】:

    您是否尝试刷新图形?

    using (Bitmap bmp = new Bitmap(100, 100))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.FillRectangle(Brushes.Red, 10, 10, 50, 50);
            g.FillRectangle(Brushes.Blue, 20, 20, 50, 50);
            g.FillRectangle(Brushes.Green, 0, 0, bmp.Width, bmp.Height);
    
            g.Flush(); // !!
    
            var bmp2 = GraphicsBitmapConverter.GraphicsToBitmap(g, Rectangle.Truncate(g.VisibleClipBounds));
        }
    }
    

    【讨论】:

      【解决方案3】:

      你很难做到。显然,由于相同的代码在不同的调用中成功和失败,图形使用不同的临时空间来存储信息,直到要求通过创建图形完成 - 否则在两种情况下都应该读取它。

      尝试使用

      gr.Save(); 
      

      对于图形,也许这将在创建之前起作用。

      但是,当我想进行绘图时,我只需使用以下方法克隆图形图像:

      public void CopyBackgroundLayer(ref Bitmap bitmap)
      {
          Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
          bitmap = new Bitmap(buffer.Clone(rect, Primary.BackGround.PixelFormat));
      }
      

      所以同时我向一个图形对象添加东西,我称之为克隆图形对象绘制的图像(示例中的缓冲区),以便在添加更多东西之前将位图上升到任意点。

      【讨论】:

        猜你喜欢
        • 2010-09-25
        • 1970-01-01
        • 1970-01-01
        • 2013-01-20
        • 1970-01-01
        • 2016-03-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多