使用JpegBitmapEncoder将WPF BitmapImage转换为Base64和从Base64转换失败,无法加载JPG文件

时间:2016-11-03 14:51:22

标签: c# xml wpf base64 bitmapimage

我想将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>
...

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

这仅适用于 JPG 文件我根本没有 PNG 文件的问题。

1 个答案:

答案 0 :(得分:2)

使用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中唯一受源流实际BitmapDecoder影响的Position