C# 复制位图数据 (GDI+)

C# Copying BitmapData (GDI+)

我目前正在使用 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 方法,因为这就是我首先创建该方法的原因。

位图包含 "GetPixel" 和 "SetPixel" 函数。我认为您可以使用它来将 FrombitMap 数据复制到 ToBitmap 数据。

GetPixel return一个Color和SetPixel是一样的。

请尝试一下。

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

做出的假设:

  1. 矩形正确地位于图像中
  2. 图像 PixelFormatFormat32bppPArgb,因此每个像素 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);
    }
}