C#复制BitmapData(GDI +)

时间:2017-04-13 10:15:55

标签: c# bitmap 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方法,因为这就是我首先创建该方法的原因。

2 个答案:

答案 0 :(得分:0)

Bitmap contanst“GetPixel”和“SetPixel”函数。我想你可以用它来复制FrombitMap数据到ToBitmap数据。

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

请试试。

答案 1 :(得分:0)

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

做出的假设:

  1. 正确放置图像中的矩形
  2. 图片PixelFormatFormat32bppPArgb,每像素4个字节
  3. srcRectdstRect具有相同的宽度和高度
  4. 所有代码都未经测试但看起来正确

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