将图像转换为字节数组的最快方法

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 对象。

以上是关于将图像转换为字节数组的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

将 PIL 图像转换为字节数组?

在opencv中使用imshow显示字节数组的最快方法是啥?

将位图转换为字节数组

图像到字节数组 - ExternalException

将字节数组转换/显示为 bmp/jpeg 图像

将图像控件转换为字节数组 Asp.Net