使用 JpegBitmapEncoder 将 WPF BitmapImage 转换为 Base64 或从 Base64 转换为加载 JPG 文件失败

Converting WPF BitmapImage to and from Base64 using JpegBitmapEncoder fails for loading JPG files

我想将 WPF BitmapImage 存储到 XML。 (我知道这通常不被推荐,但对于我来说,这是有道理的,因为我想将我所有的资源嵌入到一个 XML 文件中,除了我拥有的其他数据)。

下面是我的扩展方法:

    public static string ToBase64(this BitmapImage image, string format)
    {
        return Convert.ToBase64String(Encode(image, format));
    }

    public static Stream FromBase64(this string content)
    {
        var bytes = Convert.FromBase64String(content);
        var stream = new MemoryStream();
        stream.Write(bytes, 0, bytes.Length);
        return stream;
    }

    private static byte[] Encode(BitmapImage bitmapImage, string format)
    {
        byte[] data = null;
        BitmapEncoder encoder = null;
        switch (format.ToUpper())
        {
            case "PNG": encoder = new PngBitmapEncoder();
                break;
            case "GIF": encoder = new GifBitmapEncoder();
                break;
            case "BMP": encoder = new BmpBitmapEncoder();
                break;
            case "JPG": encoder = new JpegBitmapEncoder();
                break;
        }
        if (encoder != null)
        {
            encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
            using (var ms = new MemoryStream())
            {
                encoder.Save(ms);
                ms.Seek(0, SeekOrigin.Begin);
                data = ms.ToArray();
            }
        }

        return data;
    }

    public static BitmapImage ToBitmapImage(this Stream stream)
    {
        try
        {
            var bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.StreamSource = stream;
            bitmap.EndInit();
            return bitmap;
        }
        catch (Exception ex)
        {


        }

        return null;
    }

这是我的 XML 逻辑:

    public async void LoadImage(Guid imageSourceGuid)
    {
        var sourceElement = await GetImageSource(imageSourceGuid);
        if (sourceElement != null)
        {
            var data = sourceElement.Element("Value").Value;
            Format = sourceElement.Attribute("Format").Value.ToUpper();
            if (string.IsNullOrEmpty(data) == false)
            {
                using (var stream = data.FromBase64())
                {
                    SetImage(stream.ToBitmapImage());
                }
            }
        }
    }

    private void SetImage(BitmapImage bitmap)
    {
        this.ImageShape.Source = bitmap;
    }

    public async Task<XElement> GetImageSource(Guid id)
    {
        XElement result = null;

        await Task.Run(() =>
        {
            var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, IgnoreWhitespace = true, IgnoreComments = true, Async = true };
            using (var reader = XmlReader.Create(FilePath, settings))
            {
                while (reader.Read())
                {
                    if (reader.IsStartElement() && reader.Name == "ImageSource")
                    {
                        var att = reader.GetAttribute("Id");
                        if (att != null && Guid.Parse(att) == id)
                        {
                            result = XNode.ReadFrom(reader) as XElement;
                            break;
                        }
                    }
                }
            }

        });

        return result;
    }

我的 XML 文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<ImageSources>
   <ImageSource Id="1b1e4ebc-484c-4f63-bbed-bf33430f85f2" Format="JPG" OriginalWidth="534" OriginalHeight="338">
     <Value><![CDATA[....]]<Value>
  </ImageSource>
</ImageSources>
...

但是当我尝试使用 ToBitmapImage 方法从我之前保存的 XML 数据创建 BitmapImage 时,我得到“ 图像无法解码。图像header可能已损坏。"例外。

这只发生在 JPG 文件上 我对 PNG 文件完全没有问题。

你应该在你的 FromBase64 方法中写入后倒回 MemoryStream:

public static Stream FromBase64(this string content)
{
    var bytes = Convert.FromBase64String(content);
    var stream = new MemoryStream();
    stream.Write(bytes, 0, bytes.Length);
    stream.Seek(0, SeekOrigin.Begin); // here
    return stream;
}

或者直接从字节数组构造:

public static Stream FromBase64(this string content)
{
    return new MemoryStream(Convert.FromBase64String(content));
}

Afaik,JpegBitmapDecoder 是 WPF 中唯一受源流的实际 Position.

影响的 BitmapDecoder