System.Drawing.Image 保存的输出与输入 Image.FromStream 的输出不同

Output of System.Drawing.Image Save is not the same as what fed into Image.FromStream

我正在尝试验证以 Base64 字符串格式提交给后端的图像,方法是将其解析为 Image 对象,从同一 Image 对象中提取它,最后比较输入字节数组和输出字节数组,假设这两个应该是相同或输入图像有问题。这是代码:

    private void UpdatePhoto(string photoBase64) 
    {
        var imageDataInBytes = Convert.FromBase64String(photoBase64);
        ValidateImageContent(imageDataInBytes);
    }


    private void ValidateImageContent(byte[] imageDataInBytes)
    {
        using (var inputMem = new MemoryStream(imageDataInBytes))
        {
            var img = Image.FromStream(inputMem, false, true);

            using (MemoryStream outputMemStream = new MemoryStream())
            {
                img.Save(outputMemStream, img.RawFormat);
                var outputSerialized = outputMemStream.ToArray();

                if (!outputSerialized.SequenceEqual(imageDataInBytes))
                    throw new Exception("Invalid image. Identified extra data in the input. Please upload another photo.");
            }
        }
    }

它在一张我知道是有效的图像上失败了。

我认为 Image.Save 的输出必须与 Image.FromStream 的输入相同的假设是错误的吗?有没有办法纠正这个逻辑以正确实现这种验证方式?

如果将原始图像与创建的图像进行比较,您会注意到元数据中的一些差异:对于我的示例图像,我可以观察到一些元数据被剥离(XMP 数据被完全删除)。此外,在保留 EXIF 数据的同时,写入的 endianness 从小端倒转为大端。这本身就解释了为什么数据不匹配。

在我的示例中,实际图像数据是相同的,但您无法仅通过查看字节来轻易分辨。

如果您想生成与源相同的结果,则必须以与源完全相同的方式生成元数据。如果不仔细查看原始照片的元数据,您将无法做到这一点。 .NET 的 Image 根本无法包含文件可能包含的所有元数据。即使您能够提取所有元数据并再次以正确的格式存储它,元数据序列化程序之间也存在许多细微差别,因此很难产生完全相同的结果。

所以如果你想比较图像,你应该去掉元数据,只比较图像数据。但是,当您考虑如何保存图像 (Raw) 时,您将再次获得完全相同的数据块,所以我不希望那里有差异。