这是绝对最快我可以可能将Bitmap
复制到Byte[]
中的C#
吗?
如果有更快的方式我很想知道!
const int WIDTH = /* width */;
const int HEIGHT = /* height */;
Bitmap bitmap = new Bitmap(WIDTH, HEIGHT, PixelFormat.Format32bppRgb);
Byte[] bytes = new byte[WIDTH * HEIGHT * 4];
BitmapToByteArray(bitmap, bytes);
private unsafe void BitmapToByteArray(Bitmap bitmap, Byte[] bytes)
{
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, WIDTH, HEIGHT), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
fixed(byte* pBytes = &bytes[0])
{
MoveMemory(pBytes, bitmapData.Scan0.ToPointer(), WIDTH * HEIGHT * 4);
}
bitmap.UnlockBits(bitmapData);
}
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
private static unsafe extern void MoveMemory(void* dest, void* src, int size);
答案 0 :(得分:6)
好吧,使用Marshal.Copy()
会更明智,至少可以减少查找DLL导出的(一次)成本。但就是这样,它们都使用C运行时memcpy()
函数。速度完全受到RAM总线带宽的限制,只需购买更昂贵的机器就可以加快速度。
请注意,分析很棘手,第一次访问位图数据会导致页面错误,从而将像素数据导入内存。这需要多长时间,这取决于您的硬盘正在做什么以及文件系统缓存的状态。
答案 1 :(得分:4)
我正在读到这一点,你正在寻找对位图进行像素处理。 所以从逻辑上讲,你想要像素一样访问像素,以便做到这一点。
你面临的问题从根本上是有缺陷的,其他人没有接受这个 - 也许这也是他们可以带走的东西?
基本上,你到目前为止要搞乱位图的指针,我会给你一个我辛苦赚来的“秘密”。
您不需要将BITMAP复制到阵列中。只要按原样使用它。
在这种情况下,不安全的指针是你的朋友。当你点击“bitmapData.Scan0.ToPointer()”时你就错过了这个技巧。
只要你有一个指向第一个像素和Stride的指针,并且你知道每个像素的字节数,那么你就是胜利者。
我定义了一个特定于每像素32位的位图(对UInt32访问有效的内存),我得到一个指向第一个像素的指针。然后我将指针视为一个数组,并且可以将像素数据读取和写入为UInt32值。
代码胜于雄辩。看看。
我向你致敬,为此做到这一点!
这是未经测试的代码,但很多都是从我的源代码中复制的。
public delegate void BitmapWork(UInt32* ptr, int stride);
/// <summary>
/// you don't want to forget to unlock a bitmap do you? I've made that mistake too many times...
/// </summary>
unsafe private void UnlockBitmapAndDoWork(Bitmap bmp, BitmapWork work)
{
var s = new Rectangle (0, 0, bmp.Width, bmp.Height);
var locker = bmp.LockBits(new Rectangle(0, 0, 320, 200), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
var ptr = (UInt32*)locker.Scan0.ToPointer();
// so many times I've forgotten the stride is expressed in bytes, but I'm accessing with UInt32's. So, divide by 4.
var stride = locker.Stride / 4;
work(ptr, stride);
bmp.UnlockBits(locker);
}
//using System.Drawing.Imaging;
unsafe private void randomPixels()
{
Random r = new Random(DateTime.Now.Millisecond);
// 32 bits per pixel. You might need to concern youself with the Alpha part depending on your use of the bitmap
Bitmap bmp = new Bitmap(300, 200, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
UnlockBitmapAndDoWork(bmp, (ptr, stride) =>
{
var calcLength = 300 * 200; // so we only have one loop, not two. It's quicker!
for (int i = 0; i < calcLength; i++)
{
// You can use the pointer like an array. But there's no bounds checking.
ptr[i] = (UInt32)r.Next();
}
});
}
答案 2 :(得分:1)
我也会看System.Buffer.BlockCopy
。
此功能也非常快,在您可以在此设置中具有竞争力,因为您正在从托管复制到托管。不幸的是,我无法提供一些性能测试。
答案 3 :(得分:-2)
我认为这更快(我实际上使用它):
// Bitmap bytes have to be created via a direct memory copy of the bitmap
private byte[] BmpToBytes_MemStream (Bitmap bmp)
{
MemoryStream ms = new MemoryStream();
// Save to memory using the Jpeg format
bmp.Save(ms, ImageFormat.Jpeg);
// read to end
byte[] bmpBytes = ms.GetBuffer();
bmp.Dispose();
ms.Close();
return bmpBytes;
}