将图像转换为字节数组的最快方法
Posted
技术标签:
【中文标题】将图像转换为字节数组的最快方法【英文标题】:Fastest way to convert Image to Byte array 【发布时间】:2013-06-25 11:31:59 【问题描述】:我正在制作远程桌面共享应用程序,在该应用程序中我捕获桌面图像并将其压缩并将其发送到接收器。要压缩图像,我需要将其转换为 byte[]。
目前我正在使用这个:
public byte[] imageToByteArray(System.Drawing.Image imageIn)
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
public Image byteArrayToImage(byte[] byteArrayIn)
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
但我不喜欢它,因为我必须将它保存在 ImageFormat 中,这也可能会占用资源(减慢速度)以及产生不同的压缩结果。我已经阅读过使用 Marshal.Copy 和 memcpy 但我我无法理解它们。
那么还有其他方法可以实现这个目标吗?
【问题讨论】:
MemoryStream 和 Image 都有一个 dispose 方法,请确保您正在 Disposing 它们,因为这会导致 MemoryLeaks。 @abc123:你不需要处理MemoryStream
;它是一个完全托管的资源,除非您在远程处理中使用它。在这两种情况下,处置资源都是不合适的。
@JonSkeet 很有趣,你做过基准测试吗?查看 .net 释放对象的速度?我知道 DataTable 也有类似的论点,但 GarbageCollector 收集使用 dispose 时分配的内存的速度存在明显差异。
@abc123:我真的不希望有 - 处理流不会对数组做任何事情,而且 MemoryStream 没有终结器(与 DataTable 不同,它继承自MarshalByValueComponent)。
有完整源代码的最终解决方案吗?
【参考方案1】:
Image 参数有一个 RawFormat 属性,它返回图像的文件格式。 您可以尝试以下方法:
// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
using(var ms = new MemoryStream())
image.Save(ms, image.RawFormat);
return ms.ToArray();
【讨论】:
我建议处置 MemoryStream 或将此方法的主体包装在 using() 语句中 @Neil.Allen 我是新来的,你能告诉我为什么吗? @FirstStep 因为要自己清理 :) @Sinaesthetic 我明白了。例程是将我想要执行的任何功能放在 using()? @FirstStep 不完全是。更准确地说:如果您使用已实现 IDisposable 的对象,那么您应该确保在完成后调用 Dispose() 以便它清理它占用的所有资源。 using() 语句只是在对象超出该语句的范围时为您调用它。所以你可以使用myObject.Dispose()
或using(myObject)
——两者都做同样的事情,但是 using 语句基本上创建了一个可以为你清理的作用域。【参考方案2】:
那么还有其他方法可以实现这个目标吗?
没有。为了将图像转换为字节数组,您必须指定图像格式 - 就像在将文本转换为字节数组时必须指定编码一样。
如果您担心压缩伪影,请选择无损格式。如果您担心 CPU 资源,请选择一种无需压缩的格式 - 例如,只需原始 ARGB 像素。但是当然会导致更大的字节数组。
请注意,如果您选择一种确实包含压缩的格式,那么之后再压缩字节数组是没有意义的 - 几乎可以肯定没有任何有益效果。
【讨论】:
您可以选择imageIn.RawFormat
,而不是“选择无损格式”,它会尝试保存原始图像字节而无需进一步重新编码。【参考方案3】:
public static byte[] ReadImageFile(string imageLocation)
byte[] imageData = null;
FileInfo fileInfo = new FileInfo(imageLocation);
long imageFileLength = fileInfo.Length;
FileStream fs = new FileStream(imageLocation, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
imageData = br.ReadBytes((int)imageFileLength);
return imageData;
【讨论】:
欢迎来到 ***.com,您能否添加一些细节来解释为什么上面的代码示例会有所帮助。供其他可能不完全理解的 SO 用户使用...***.com/help/how-to-answer 这是用于将文件转换为字节的,但 OP 希望将绘图对象转换为字节。绘图对象可以存储在数据库中,不一定是文件系统,作为字节数组,因此必须来回转换......但不能作为 FileStream 中的文件转换为字节 - 除非可能,在初始上传。 这对我很有帮助,因为我希望对文件进行此操作。很高兴有相关的。【参考方案4】:由于 Jon Skeet 指出的原因,我不确定您是否会获得任何巨大收益。但是,您可以尝试对 TypeConvert.ConvertTo 方法进行基准测试,看看它与使用当前方法的比较。
ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));
【讨论】:
无法将“System.Byte[]”类型的对象转换为“System.Drawing.Image”类型。【参考方案5】:public static class HelperExtensions
//Convert Image to byte[] array:
public static byte[] ToByteArray(this Image imageIn)
var ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return ms.ToArray();
//Convert byte[] array to Image:
public static Image ToImage(this byte[] byteArrayIn)
var ms = new MemoryStream(byteArrayIn);
var returnImage = Image.FromStream(ms);
return returnImage;
【讨论】:
【参考方案6】:我能找到的最快方法是:
var myArray = (byte[]) new ImageConverter().ConvertTo(InputImg, typeof(byte[]));
希望有用
【讨论】:
对此要小心,尤其是在使用 WPF 的情况下,您将拥有System.Windows.Controls.Image
对象。如果您想将其中一个转换为字节,并将其作为InputImg
传递到这一行,这将不起作用。它需要一个 System.Drawing.Image
对象。以上是关于将图像转换为字节数组的最快方法的主要内容,如果未能解决你的问题,请参考以下文章