将位图转换为字节数组
Posted
技术标签:
【中文标题】将位图转换为字节数组【英文标题】:Convert a bitmap into a byte array 【发布时间】:2011-11-13 02:54:31 【问题描述】:使用 C#,有没有比保存到临时文件并使用 FileStream
读取结果更好的方法将 Windows Bitmap
转换为 byte[]
?
【问题讨论】:
【参考方案1】:有几种方法。
图像转换器
public static byte[] ImageToByte(Image img)
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
这个很方便,因为它不需要很多代码。
内存流
public static byte[] ImageToByte2(Image img)
using (var stream = new MemoryStream())
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
这个和你正在做的一样,只是文件被保存到内存而不是磁盘。虽然有更多代码,但您可以选择 ImageFormat,并且可以在保存到内存或磁盘之间轻松修改它。
来源:http://www.vcskicks.com/image-to-byte.php
【讨论】:
您还可以使用 bitmap.Lockbits 和 Marshal.Copy 进行简单的快速复制,无需任何中间内存流等。 请注意ImageConverter
方法会将图像保存为Png,从而产生巨大的文件。
使用'using'时不需要关闭流
谁能给我更多关于这个数组结构的信息?它是否以 x = 0 开始并循环遍历每个 y 然后递增 x?然后像这样存储它:[0,0,1,1,1,1,0,0,1,1]?
ImageConverter
不是您可能使用的 .net 标准 MemoryStream
【参考方案2】:
MemoryStream 可以对此有所帮助。你可以把它放在一个扩展方法中:
public static class ImageExtensions
public static byte[] ToByteArray(this Image image, ImageFormat format)
using(MemoryStream ms = new MemoryStream())
image.Save(ms, format);
return ms.ToArray();
你可以像这样使用它:
var image = new Bitmap(10, 10);
// Draw your image
byte[] arr = image.ToByteArray(ImageFormat.Bmp);
我部分不同意 prestomanifto 关于 ImageConverter 的回答。 不要使用 ImageConverter。 它在技术上没有任何问题,但它使用来自对象的装箱/拆箱这一事实告诉我它是来自 .NET 框架的旧黑暗地方的代码,它并不适合与图像处理一起使用(至少转换为 byte[] 有点过分),尤其是在考虑以下情况时。
我查看了 .Net 框架使用的 ImageConverter
代码,它在内部使用的代码几乎与我上面提供的代码相同。它创建一个新的MemoryStream
,以您提供它时的任何格式保存Bitmap
,然后返回数组。使用MemoryStream
跳过创建ImageConverter
类的额外开销
【讨论】:
可爱。这样就行了!我认为你会想要处理 MemoryStream,不过 - 关心更新吗? 我已经更新了我的答案,讨论了为什么不使用 ImageConverter,正如您选择的答案所暗示的那样,以及添加了处置。 很好用的扩展方法,我喜欢! +1 用于查看 ImageConverter 并报告您的研究结果。但我不认为你的发现保证了“不要使用 ImageConverter”的说法。它肯定会提供有用的服务,从字节数组到图像,例如设置图像分辨率(dpi)。而且“创建 ImageConverter 类的额外开销”大概可以忽略不计,无论您使用多少次,都只需要完成一次。 我发现 ImageConverter 也很有帮助,因为它可以自动确定图像的类型 - 例如,如果您有图像的字节数组,但不知道格式 - 您可以尝试读取标题并从那里获得提示,但是,嗯,......使用 (Image img = (Image)myImgConverter.ConvertFrom(byteImage)) 然后检查 img.PixelFormat 等更容易...... - 当然取决于你想要什么做【参考方案3】:您也可以只 Marshal.Copy 位图数据。没有中间内存流等和快速内存副本。这应该适用于 24 位和 32 位位图。
public static byte[] BitmapToByteArray(Bitmap bitmap)
BitmapData bmpdata = null;
try
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
int numbytes = bmpdata.Stride * bitmap.Height;
byte[] bytedata = new byte[numbytes];
IntPtr ptr = bmpdata.Scan0;
Marshal.Copy(ptr, bytedata, 0, numbytes);
return bytedata;
finally
if (bmpdata != null)
bitmap.UnlockBits(bmpdata);
.
【讨论】:
您好,我使用了这种方法,但是我无法再次将此字节数组转换回图像。位图 bitmap1 = new Bitmap(new MemoryStream(array));它抛出无效参数的异常。有什么错误吗? 嗨,cmets 部分太小,我无法发布完整的干净代码。最简单的方法是固定数组: GCHandle handle = GCHandle.Alloc(bufferarray, GCHandleType.Pinned);获取指向数组的指针 IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement(bufferarray, 0);然后使用 IntPtr 创建一个新位图: bitmap = new Bitmap(width, height, (width * 4), PixelFormat.Format32bppArgb, iptr);但是您必须为您的位图格式使用适当的位图创建参数。一定要清理:iptr = IntPtr.Zero; handle.Free(); 什么是错误?包括我在内的许多程序员都在使用这种代码风格,而且效果很好。 @mini-me - 我建议查看位图步幅与位图宽度的关系。这不是我的代码中的错误,这是 Windows 处理位图的方式。步幅可能会在每行的末尾(宽度)包含额外的数据,以便让每行结束并从 32 位边界开始,以实现内存对齐和性能。 这不是错误。 msdn.microsoft.com/en-us/library/…【参考方案4】:将图像保存到 MemoryStream,然后获取字节数组。
http://msdn.microsoft.com/en-us/library/ms142148.aspx
Byte[] data;
using (var memoryStream = new MemoryStream())
image.Save(memoryStream, ImageFormat.Bmp);
data = memoryStream.ToArray();
【讨论】:
图片没有保存方法 @PrescottChartier 上面的示例假设您使用从System.Drawing.Image
派生的类型(请参阅:docs.microsoft.com/en-us/dotnet/api/…)
是的,我得到了System.Drawing.Image does not exist
。所以..不,不起作用:(
你可以在这里看到我想要做什么:***.com/questions/55084620/…
此解决方案还包含字节数组中的元数据。所以它可以用来填充一个 MemoryStream 并再次创建相同的 Bitmap:using (var ms = new MemoryStream(previewBinary))
bitmap = (Bitmap)Image.FromStream(ms);
【参考方案5】:
使用MemoryStream
而不是FileStream
,如下所示:
MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();
【讨论】:
你可能想要ToArray
,而不是GetBuffer
。
GetBuffer 返回一个无符号字节数组(字节数组)
它可能包含不属于图像的填充数据。来自文档:Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method.
所以现在来自GetBuffer
的字节数组将返回图像加上未使用的字节,这可能会导致图像损坏。
很高兴知道。感谢 vcs 的评论!
此方法将图像保存为具有默认压缩设置的 jpeg,这将引入可能会明显降低图像质量的压缩伪影。【参考方案6】:
尝试以下方法:
MemoryStream stream = new MemoryStream();
Bitmap bitmap = new Bitmap();
bitmap.Save(stream, ImageFormat.Jpeg);
byte[] byteArray = stream.GetBuffer();
确保您正在使用:
System.Drawing & using System.Drawing.Imaging;
【讨论】:
此方法将图像保存为具有默认压缩设置的 jpeg,这将引入可能会明显降低图像质量的压缩伪影。 同样,位图上没有保存方法。【参考方案7】:更简单:
return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))
【讨论】:
谢谢 - 就像一个魅力,但如果你添加解释它是如何工作的答案会更好。【参考方案8】:我相信你可以这样做:
ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));
【讨论】:
【参考方案9】:MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();
【讨论】:
【参考方案10】:非常简单,只需一行即可:
byte[] imgdata = File.ReadAllBytes(@"C:\download.png");
【讨论】:
op 说他对这个选项不感兴趣以上是关于将位图转换为字节数组的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin 安卓。将字节数组转换为位图。 Skia 解码器返回 false