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
代码来为您提供最大可能的性能。
做出的假设:
- 矩形正确地位于图像中
- 图像
PixelFormat
是 Format32bppPArgb
,因此每个像素 4 个字节
srcRect
和dstRect
的宽高相同
所有代码未经测试但看起来正确
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);
}
}
我目前正在使用 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
代码来为您提供最大可能的性能。
做出的假设:
- 矩形正确地位于图像中
- 图像
PixelFormat
是Format32bppPArgb
,因此每个像素 4 个字节 srcRect
和dstRect
的宽高相同
所有代码未经测试但看起来正确
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);
}
}