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

113

我正在制作远程桌面共享应用程序,其中我捕获桌面图像并进行压缩,并将其发送给接收者。为了压缩图像,我需要将其转换为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方法,请确保对它们进行处理,否则可能会导致内存泄漏。 - abc123
3
您无需处理 MemoryStream;它是完全托管的资源,除非您在远程使用它,在这两种情况下处理该资源是不适当的。 - Jon Skeet
1
@JonSkeet 很有趣,你对此进行过基准测试吗?以查看.NET释放对象的速度?我知道DataTable也有类似的论点,但是在使用dispose时分配内存的垃圾收集器收集内存的速度明显有所不同。 - abc123
@abc123: 我真的不认为会有这样的情况- 释放流对数组没有任何影响,而MemoryStream没有终结器(与DataTable不同,后者从MarshalByValueComponent继承一个终结器)。 - Jon Skeet
2
有没有完整源代码的最终解决方案? - Kiquenet
很好的事情。这个问题已经回答了我的问题。根据其他例子,这个问题非常简短和紧凑。我不明白你对此的问题。我正在尝试创建一个相同的应用程序。你的代码已经适合我了。 :) 已点赞。 - C4d
7个回答

56

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

10
我建议你要么处理掉这个MemoryStream,要么将这个方法的主体部分用using(){}语句包装起来。 - Neil.Allen
@Neil.Allen 我是新来的,你能告诉我为什么吗? - Khalil Khalaf
4
@FirstStep 因为要自己打扫干净 :) - Sinaesthetic
@Sinaesthetic 我明白了。那么惯例就是把我想要执行的任何函数放在 using(){} 中? - Khalil Khalaf
2
@FirstStep 不完全正确。更准确地说:如果您使用了实现了IDisposable接口的对象,则应确保在完成后调用Dispose()以清理其占用的任何资源。using(){}语句只是在该语句的作用域之外时自动调用它。因此,您可以执行myObject.Dispose()using(myObject){} - 两者都会做同样的事情,但是using语句基本上创建了一个将为您清理的作用域。 - Sinaesthetic
1
@Neil.Allen使用语句将调用Dispose方法。 - Mevius

40

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

没有。要将图像转换为字节数组,您必须指定图像格式 - 就像在将文本转换为字节数组时必须指定编码。

如果您担心压缩伪影,请选择无损格式。如果您担心CPU资源,请选择不需要压缩的格式 - 比如纯粹的ARGB像素。但是这当然会导致更大的字节数组。

请注意,如果您选择了一个包含压缩的格式,那么事后压缩字节数组就毫无意义 - 这几乎肯定不会产生任何好处。


12
您可以选择 imageIn.RawFormat 而不是选择“损失less格式”,它会尝试仅保存原始图像字节,而不进行进一步重新编码。 - Chris F Carroll

16
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用户...http://stackoverflow.com/help/how-to-answer - Mack
这是将文件转换为字节,但 OP 想要将绘图对象转换为字节。绘图对象可以作为字节数组存储在数据库中,而不一定是文件系统,并且因此必须来回转换... 但不是作为 FileStream 中的文件转换为字节 - 除非在初始上传期间。 - vapcguy
这对我很有帮助,因为我正在处理文件。它与此相关,值得保留。 - Justin

14

我不确定您是否能从中获得任何巨大的收益,因为 Jon Skeet 指出了原因。 但是,您可以尝试对TypeConvert.ConvertTo 方法进行基准测试,并查看它与使用当前方法的比较情况。

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

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

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

4
我能找到的最快方法是这个:

我能找到的最快方法是这个:

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

希望能够有所帮助。


要小心处理这个问题,尤其是在使用 WPF 的情况下,因为你可能会遇到 System.Windows.Controls.Image 对象。如果你想将它们之一转换为字节,并将其作为“InputImg”传递给此行,则此操作不起作用。它需要一个 System.Drawing.Image 对象。 - vapcguy

-1
尝试以下代码:
public Byte[] ConvertPictureToByte(System.Drawing.Image PictureFile)
{
   using (var MemStrm = new MemoryStream())
   {
      PictureFile.Save(MemStrm,PictureFile.RawFormat);
      return  MemStrm.ToArray();
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接