Serialize a System.Windows.Media.ImageSource object




system windows controls image source (5)

I am creating a chat application very basic. I establish the chat with a tcp connection. I often send serialized object through the network stream because it is simplier to program that way. anyways if I have a class person{ public string name{get;set;} } then it will be eassy to serialize that class. when I include a public ImageSource Img {get;set;} I am not able to serialize that class person any more.

the way I serialize is as:

Person p = new Person();
p.name = \\some name
p.Img = \\ some image

System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());

x.Serialize(connection.stream, p);//here is when the problem comes. I am not able to serialize it if I include an Img

Answer #1

Saving ImageSource (BitmapSource) in XML

There's a problem with Base64ToImage method from this answer. The documentation states that with the default OnDemand cache option the stream must not be closed before the image is actually used. In your case this means that the Image element is trying to access the already disposed stream.

The fix is pretty simple, you just need to change the cache option to OnLoad and the problem is gone:

BitmapSource Base64ToImage(string base64)
{
    byte[] bytes = Convert.FromBase64String(base64);
    using (var stream = new MemoryStream(bytes))
    {
        return BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    }
}

Answer #2

C# Convert BitmapImage to Byte[] and vice-versa in Windows Store App

You could try using InMemoryRandomAccessStream:

var stream = new InMemoryRandomAccessStream();
await stream.WriteAsync(iconBytes.AsBuffer());
stream.Seek(0);

var image = new BitmapImage();
await image.SetSourceAsync(stream);

Here's another example.


Answer #3

WPF BitmapImage Serialization/Deserialization

1) You should not dispose MemoryStream, used from image initializing. Remove using in this line

using (MemoryStream ms = new MemoryStream(entry.Value as byte[]))

2) After

encoder.Save(ms);

Try adding

ms.Seek(SeekOrigin.Begin, 0);
ms.ToArray();

Answer #4

You can't serialize an image to XML, but you can save it to a MemoryStream and encode the binary data to base64.

string ImageToBase64(BitmapSource bitmap)
{
    var encoder = new PngBitmapEncoder();
    var frame = BitmapFrame.Create(bitmap);
    encoder.Frames.Add(frame);
    using(var stream = new MemoryStream())
    {
        encoder.Save(stream);
        return Convert.ToBase64String(stream.ToArray());
    }
}

BitmapSource Base64ToImage(string base64)
{
    byte[] bytes = Convert.FromBase64String(base64);
    using(var stream = new MemoryStream(bytes))
    {
        return BitmapFrame.Create(stream);
    }
}

Note that base64 is not very efficient in terms of space... If possible, it would be better to transmit the image in binary form, rather than in XML.