【问题标题】:C# Copying BitmapData (GDI+)C# 复制位图数据 (GDI+)
【发布时间】:2017-09-09 09:57:01
【问题描述】:

我目前正在使用 GDI+ 用 C# 开发游戏引擎。目前,我正在尝试通过实现一种更快的方式将一个位图复制到另一个位图来使图形引擎更快地渲染位图。

我有一个名为CopyBitmap 的方法,它接收您希望从中复制的位图、您希望复制到的位图、目标矩形(您希望放置到复制图像的位置和大小) 和一个源矩形(这是您要复制的图像部分)。

但是,我不知道如何设置复制图像的位置和大小。

我该怎么做呢?

这是我目前的代码:

    /// <summary>
    /// Copies the <see cref="BitmapData"/> from one <see cref="Bitmap"/> to another.
    /// </summary>
    /// <param name="from">The <see cref="Bitmap"/> you wish to copy from.</param>
    /// <param name="to">The <see cref="Bitmap"/> you wish to copy to.</param>
    /// <param name="destRect">The location and size of the copied image.</param>
    /// <param name="srcRect">The portion of the image you wish to copy.</param>
    public static void CopyBitmap(Bitmap from, Bitmap to, Rectangle destRect, Rectangle srcRect)
    {
        // The bitmap we're copying from needs to know the portion of the bitmap we wish to copy
        // so lets pass it the src rect, it is also read only.
        BitmapData fromData = from.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);

        // The bitmap we're copying to needs to know where the copied bitmap should be placed, and also how big it is
        // so lets pass it the dest rect, it is also write only
        BitmapData toData = to.LockBits(destRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);

        // Declare an array to hold the bytes of data we're copying from
        int bytes = Math.Abs(fromData.Stride) * from.Height;

        // convert it to bytes
        byte[] rgbValues = new byte[bytes];

       // I imaginge here is where I should set the position and size of the image I wish to copy to it's destRect

        // Copy the values to the bitmap we're copying to
        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, toData.Scan0, bytes);

        // unlock them both
        from.UnlockBits(fromData);
        to.UnlockBits(toData);
    }

我认为值得一提的是,我不希望使用 graphics.DrawImage 方法,因为这就是我首先创建该方法的原因。

【问题讨论】:

  • 旁注,您需要检查destRectsrcRect 是否正确位于各自图像的范围内
  • 谢谢,我现在就做。很明显,id 用一个简单的 Rectangle.IntersectsWith 校验来做到这一点?
  • 您可以按照自己的意愿进行操作,但是应该可以。

标签: c# bitmap gdi+


【解决方案1】:

我做了几个假设来向您展示如何执行此操作的示例,并且我还使用了unsafe 代码来为您提供最大可能的性能。

假设:

  1. 矩形正确地位于图像中
  2. PixelFormats 的图像是 Format32bppPArgb,因此每个像素 4 个字节
  3. srcRectdstRect 具有相同的宽度和高度

所有代码未经测试,但看起来正确

public static unsafe void CopyBitmap(Bitmap from, Bitmap to, Rectangle destRect, Rectangle srcRect)
{
    //Check rects line up appropriatley

    //You should get this and the PixelFormat's of the images properly
    //unless you can alsways assume the same format
    const int BYTES_PER_PIXEL = 4;

    BitmapData fromData = from.LockBits(new Rectangle(Point.Empty, from.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
    try
    {
        BitmapData toData = to.LockBits(new Rectangle(Point.Empty, to.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
        try
        {
            //For the purpose of this example I will assume that srcRect and destRect have the same width and height

            int xOffset = (destRect.X - srcRect.X) * BYTES_PER_PIXEL;
            int yOffset = destRect.Y - srcRect.Y;

            for (int hi = srcRect.Y, hc = srcRect.Bottom; hi < hc; ++hi)
            {
                byte* fromRow = (byte*)fromData.Scan0 + (hi * fromData.Stride);
                byte* toRow = (byte*)toData.Scan0 + ((hi + yOffset) * toData.Stride);

                for (int wi = (srcRect.X * BYTES_PER_PIXEL), wc = (srcRect.Right * BYTES_PER_PIXEL);
                        wi < wc; wi += BYTES_PER_PIXEL)
                {
                    //Adjust this if you have a different format

                    toRow[xOffset + wi] = fromRow[wi];
                    toRow[xOffset + wi + 1] = fromRow[wi + 1];
                    toRow[xOffset + wi + 2] = fromRow[wi + 2];
                    toRow[xOffset + wi + 3] = fromRow[wi + 3];
                }
            }
        }
        finally
        {
            to.UnlockBits(fromData);
        }
    }
    finally
    {
        from.UnlockBits(fromData);
    }
}

【讨论】:

  • @MathewO'Dwyer 刚刚用带有 alpha 组件的图像尝试了我的代码,它工作正常,所以我无法重现您丢失 alpha 通道的结果
【解决方案2】:

位图常量“GetPixel”和“SetPixel”函数。我认为您可以使用它将 FrombitMap 数据复制到 ToBitmap 数据。

GetPixel 返回一个 Color 和 SetPixel 是一样的。

请试一试。

【讨论】:

  • BitmapData 类不包含 SetPixel 或 GetPixel 方法,只有 Bitmap 类包含。
  • 这些方法也非常慢,因此 OP 想要使用 LockBits
猜你喜欢
  • 2013-05-05
  • 2012-05-10
  • 2012-08-21
  • 2014-08-01
  • 2014-07-11
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 1970-01-01
相关资源
最近更新 更多