【问题标题】:Converting WPF BitmapImage to and from Base64 using JpegBitmapEncoder fails for loading JPG files使用 JpegBitmapEncoder 将 WPF BitmapImage 与 Base64 相互转换,无法加载 JPG 文件
【发布时间】:2016-11-03 23:02:53
【问题描述】:

我想将 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 时,我得到“无法解码图像。图像标题可能已损坏。”例外。

这仅适用于 JPG 文件我对 PNG 文件没有任何问题。

【问题讨论】:

    标签: c# xml wpf base64 bitmapimage


    【解决方案1】:

    您应该在写入 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

    【讨论】:

    • 谢谢@Clemens。这就是问题所在。你拯救了我的一天:)
    猜你喜欢
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 2015-12-09
    • 1970-01-01
    • 2023-02-24
    • 2016-12-26
    相关资源
    最近更新 更多