当字节数组的源是 jpg 时,从存储的字节数组创建位图并保存到磁盘会引发 GDI+ 异常

Posted

技术标签:

【中文标题】当字节数组的源是 jpg 时,从存储的字节数组创建位图并保存到磁盘会引发 GDI+ 异常【英文标题】:Create a bitmap from a stored byte array and save to disk throws GDI+ exception when source of byte array was a jpg 【发布时间】:2019-10-08 01:46:04 【问题描述】:

我希望有人可以帮助解决我将已提供给我的图像保存为字节数组的问题。

版本:

.Net Framework 4.6.2 C# 7.2

故事是

    用户上传图片 我们序列化成一个字节数组并存储它 稍后我们会获取该字节数组并创建一个内存流,并使用该流创建一个位图对象。 使用该位图对象保存到磁盘

当原始文件为 PNG 格式时,这一切都有效。但是,当它是 Jpg 格式时,它会失败。

以下是一些示例代码,您可以将其粘贴在基本控制台应用程序中,只要您引用 System.Drawing,它就会运行。

static void Main(string[] args)

    Console.WriteLine("Enter image file location");
    var filePath = Console.ReadLine();
    while (!File.Exists(filePath))
    
        Console.WriteLine("Cannot find file. Try Again");
        filePath = Console.ReadLine();
    

    byte[] bytes = File.ReadAllBytes(filePath);

    Bitmap image;
    using (var stream = new MemoryStream(bytes))
    
        image = new Bitmap(stream);
    

    WriteToFile(image);
    image.Dispose();
    Console.ReadKey();


private static void WriteToFile(Bitmap image)

    Console.WriteLine("Enter write location filename");
    var fileName = Console.ReadLine();
    image.Save(fileName);
    Console.WriteLine($"File saved to fileName");

如果原始图像是 PNG,则可以正常工作,如果是 JPG,则失败。这是为什么? 我看到位图类的 Save 方法有一个采用 ImageFormat 实例的重载。但是只有我有原始字节数组,所以我不知道我的图像格式是什么。

任何帮助将不胜感激,谢谢!

编辑: 在从原始文件创建字节数组以及将其保存回磁盘(参见下面的代码)时,我都尝试将图像格式指定为 JPG,而使用 jpgs 时它仍然会继续失败。但是,Pngs 仍然可以正常工作

static void Main(string[] args)

    Console.WriteLine("Enter jpg file location");
    var filePath = Console.ReadLine();
    while (!File.Exists(filePath))
    
        Console.WriteLine("Cannot find file. Try Again");
        filePath = Console.ReadLine();
    

    byte[] bytes = CreateSerializedImage(filePath);

    Image image;
    using (var steram = new MemoryStream(bytes))
    
        image = Image.FromStream(steram);
    

    WriteToFile(image);
    image.Dispose();
    Console.ReadKey();


private static byte[] CreateSerializedImage(string filePath)

    var image = Image.FromFile(filePath);
    using (var stream = new MemoryStream())
    
        image.Save(stream,ImageFormat.Jpeg);
        return stream.ToArray();
    


private static void WriteToFile(Image image)

    Console.WriteLine("Enter write location filename");
    var fileName = Console.ReadLine();
    image.Save(fileName, ImageFormat.Jpeg);
    Console.WriteLine($"File saved to fileName");

【问题讨论】:

【参考方案1】:

您要在写入图像之前释放MemoryStream,请在保存文件后尝试释放流。这对我有用:)

如果要获取图片格式,尝试从流的前几个字节检测:

Wikipedia: file-signature-list

【讨论】:

据我了解,一旦流被读入其 ctor 中的新位图,我就不再需要保留它。这得到了它与 PNG 一起使用的事实的支持——它是我得到错误的唯一 JPG 但是文档确实说你是对的 docs.microsoft.com/en-us/dotnet/api/… 奇怪的是它可以与 png 一起使用 您是否尝试过其他 JPG 文件?它可能已损坏或包含 .NET 不支持的(元)数据... 我也是这么想的,我查了一下,同样的事情发生了

以上是关于当字节数组的源是 jpg 时,从存储的字节数组创建位图并保存到磁盘会引发 GDI+ 异常的主要内容,如果未能解决你的问题,请参考以下文章

将固定字节从输入流存储到字节数组中

如何从字节数组创建位图?

解释图像的字节数组

已知线性表最多可能有20个元素,存储每个元素需要8字节,存储每个指针需要4字节。当元素个数为( )时使用单链表比使用数组存储此线性表更加节约空间。

Java - 将字节数组作为字符串存储在数据库中,并使用字符串值创建字节数组

如何将字节数组转换为图像文件?