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


106

我正在制作远程桌面共享应用程序,在该应用程序中,我捕获了桌面的图像并将其压缩并将其发送到接收器。要压缩图像,我需要将其转换为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中,这可能还会消耗资源(Slow Down)以及产生不同的压缩结果。了解他们。

那么还有其他方法可以实现这一目标吗?


MemoryStream和Image都具有dispose方法,请确保要对其进行处置,因为这可能导致MemoryLeaks。
abc123 2013年

3
@ abc123:您不需要处理MemoryStream; 它是一个完全托管的资源,除非您在远程处理中使用它。在这两种情况下,处置资源都是不合适的。
乔恩·斯基特

1
@JonSkeet有趣,您是否为此做了基准测试?看看.net释放对象的速度?我知道DataTable也有类似的论点,但是GarbageCollector收集使用处理时分配的内存的速度存在明显差异。
abc123 2013年

@ abc123:我真的不希望有-处理流对数组没有任何作用,MemoryStream没有终结器(不同于DataTable,后者从MarshalByValueComponent继承了其中一个)。
乔恩·斯基特

2
有完整源代码的最终解决方案吗?
Kiquenet

Answers:


39

那么还有其他方法可以实现这一目标吗?

不能。为了将图像转换为字节数组,您必须指定图像格式-就像将文本转换为字节数组时必须指定编码一样。

如果您担心压缩伪影,请选择一种无损格式。如果您担心CPU资源,请选择一种不会压缩的格式-例如,仅原始ARGB像素。但这当然会导致更大的字节数组。

请注意,如果选择了包含压缩的格式,随后压缩字节数组毫无意义-几乎可以肯定没有任何效果。


12
而不是“选择无损格式”,您可以选择imageIn.RawFormat尝试保存原始图像字节而无需进一步重新编码的方法。
克里斯·卡罗尔

52

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();
    }
}

9
我建议处置MemoryStream或将这种方法的主体包装在using(){}语句中
Neil.Allen 2014年

@ Neil.Allen我是新来的,你能告诉我为什么吗?
哈利勒·哈拉夫

3
@FirstStep因为在自己之后要清理:)
Sinaesthetic

@Sinaesthetic我明白了。例程是将我想执行的任何函数放在using(){}中?
哈利勒·哈拉夫

2
@FirstStep不太好。更准确地说:如果您使用已实现IDisposable的对象,则应确保在使用完该对象后调用Dispose(),以便它可以清理已占用的所有资源。当对象超出该语句的范围时,using(){}语句仅为您调用它。因此,您可以做myObject.Dispose()using(myObject){}-都做同样的事情,但是using语句基本上创建了一个将为您清理的作用域。
Sinaesthetic

14

由于乔恩·斯凯特(Jon Skeet)指出的原因,我不确定您是否会获得巨大收益。但是,您可以尝试对TypeConvert.ConvertTo方法进行基准测试,并查看它与使用当前方法的比较。

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));

无法将类型为“ System.Byte []”的对象转换为类型为“ System.Drawing.Image”的对象。
user123 2014年

14
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;
    }

5
欢迎来到stackoverflow.com,您能否添加一点细节来解释上面的代码示例为何有所帮助。它适用于可能不完全了解它的其他SO用户... stackoverflow.com/help/how-to-answer
Mack 2014年

这用于将文件转换为字节,但OP希望将图形对象转换为字节。绘图对象可以字节数组的形式存储在数据库中,而不必存储在文件系统中,因此必须进行来回转换...但是不能将其作为FileStream中的文件转换为字节-除非在初始上传。
vapcguy 2015年

这对我有所帮助,因为我一直希望使用文件来实现。很高兴与之相关。
贾斯汀

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;
    }
}

2

我能找到的最快方法是:

var myArray = (byte[]) new ImageConverter().ConvertTo(InputImg, typeof(byte[]));

希望有用


对此要特别小心,尤其是在使用WPF的地方,如果有System.Windows.Controls.Image对象的话。如果要将其中之一转换为字节,然后将其作为传递给此行InputImg,则将无法使用。它期望一个System.Drawing.Image对象。
vapcguy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.