为了账号安全,请及时绑定邮箱和手机立即绑定

从像素数据的字节数组创建位图

从像素数据的字节数组创建位图

C#
繁星点点滴滴 2019-12-27 15:30:46
这个问题是关于如何读取/写入,分配和管理位图的像素数据。这是一个如何为像素数据分配字节数组(托管内存)并使用它创建位图的示例:Size size = new Size(800, 600);PixelFormat pxFormat = PixelFormat.Format8bppIndexed;//Get the stride, in this case it will have the same length of the width.//Because the image Pixel format is 1 Byte/pixel.//Usually stride = "ByterPerPixel"*Width//但这并不总是正确的。在bobpowell的更多信息。int stride = GetStride(size.Width, pxFormat);byte[] data = new byte[stride * size.Height];GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);Bitmap bmp = new Bitmap(size.Width, size.Height, stride,             pxFormat, handle.AddrOfPinnedObject());//After doing your stuff, free the Bitmap and unpin the array.bmp.Dispose();handle.Free();public static int GetStride(int width, PixelFormat pxFormat){    //float bitsPerPixel = System.Drawing.Image.GetPixelFormatSize(format);    int bitsPerPixel = ((int)pxFormat >> 8) & 0xFF;    //Number of bits used to store the image data per line (only the valid data)    int validBitsPerLine = width * bitsPerPixel;    //4 bytes for every int32 (32 bits)    int stride = ((validBitsPerLine + 31) / 32) * 4;    return stride;}我以为该位图可以复制数组数据,但实际上它指向相同的数据。您可以看到:Color c;c = bmp.GetPixel(0, 0);Console.WriteLine("Color before: " + c.ToString());//Prints: Color before: Color [A=255, R=0, G=0, B=0]data[0] = 255;c = bmp.GetPixel(0, 0);Console.WriteLine("Color after: " + c.ToString());//Prints: Color after: Color [A=255, R=255, G=255, B=255]问题:从byte []数组(托管内存)和free()GCHandle创建位图是否安全?如果不安全,则需要保留固定的阵列,这对GC / Performance有多严重?更改数据是否安全(例如:data [0] = 255;)?GC可以更改Scan0的地址吗?我的意思是,我从锁定的位图获取Scan0,然后将其解锁,再过一段时间锁定后,Scan0会有所不同吗?LockBits方法中ImageLockMode.UserInputBuffer的用途是什么?很难找到有关该信息!MSDN没有清楚地解释它!
查看完整描述

3 回答

?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

关于你的问题4:在ImageLockMode.UserInputBuffer能给你可能被引用到的那些记忆大量的分配过程的控制BitmapData对象。


如果选择创建自己的BitmapData对象,则可以避免使用Marshall.Copy。然后,您将不得不将此标志与另一个标志结合使用ImageLockMode。


注意这是一项复杂的业务,特别是与Stride和PixelFormat有关。


这是一个示例,将一张照片中的24bbp缓冲区的内容放入一个BitMap中,然后另一张照片将其读回到另一个缓冲区中,并将其读入48bbp。


Size size = Image.Size;

Bitmap bitmap = Image;

// myPrewrittenBuff is allocated just like myReadingBuffer below (skipped for space sake)

// But with two differences: the buff would be byte [] (not ushort[]) and the Stride == 3 * size.Width (not 6 * ...) because we build a 24bpp not 48bpp

BitmapData writerBuff= bm.LockBits(new Rectangle(0, 0, size.Width, size.Height), ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb, myPrewrittenBuff);

// note here writerBuff and myPrewrittenBuff are the same reference

bitmap.UnlockBits(writerBuff);

// done. bitmap updated , no marshal needed to copy myPrewrittenBuff 


// Now lets read back the bitmap into another format...

BitmapData myReadingBuffer = new BitmapData();

ushort[] buff = new ushort[(3 * size.Width) * size.Height]; // ;Marshal.AllocHGlobal() if you want

GCHandle handle= GCHandle.Alloc(buff, GCHandleType.Pinned);

myReadingBuffer.Scan0 = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);

myReadingBuffer.Height = size.Height;

myReadingBuffer.Width = size.Width;

myReadingBuffer.PixelFormat = PixelFormat.Format48bppRgb;

myReadingBuffer.Stride = 6 * size.Width;

// now read into that buff

BitmapData result = bitmap.LockBits(new Rectangle(0, 0, size.Width, size.Height), ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly, PixelFormat.Format48bppRgb, myReadingBuffer);

if (object.ReferenceEquals(result, myReadingBuffer)) {

    // Note: we pass here

    // and buff is filled

}

bitmap.UnlockBits(result);

handle.Free();

// use buff at will...

如果您使用ILSpy,则会看到此方法链接到GDI +,这些方法的帮助更加完整。


您可以通过使用自己的内存方案来提高性能,但是请注意,Stride可能需要进行一些调整才能获得最佳性能。


然后,您将可以例如分配巨大的虚拟内存映射的scan0并非常有效地blit它们。请注意,固定巨大的数组(尤其是少数数组)不会给GC造成负担,并且可以让您以完全安全的方式(或者如果您追求速度则不安全)来操纵字节/短路。


查看完整回答
反对 回复 2019-12-27
?
慕沐林林

TA贡献2016条经验 获得超9个赞

我不确定您是否会按照自己的方式进行操作。也许有。似乎您走得太远了,所以您可能要尝试做一些比问题标题所暗示的要高级的事情...


但是,从字节数组创建位图的传统方法是:


using (MemoryStream stream = new MemoryStream(byteArray))

{

     Bitmap bmp = new Bitmap(stream);

     // use bmp here....

}


查看完整回答
反对 回复 2019-12-27
  • 3 回答
  • 0 关注
  • 546 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信