This post is to celebrate my 2nd app - Smart Dial has been approved in marketplace.
None of the build in imaging classes in Windows Phone or Silverlight is serializable, that's why I have to build my own class.
To serialize a custom object, the class need to implement IXmlSerializable interface. So my class inherits BitmapSource and then implement IXmlSerializable.
The idea of the whole thing is actually pretty simple. Just covert the image into byte array, and then transform to Base64 string, and backward for deserialization. With such approach, we are able to ship the image within XML(i.e. pure text). This is how my app (Smart Dial) to transfer contact photos between WP7 and server.
Since my Smart Dial solution consists 2 client programs in handset device and desktop computer, I made the class compatible with both silverlight (WP7) and Winform (base on .Net 3.5). However, somehow I can't load the image source to itself in winform version. The BitmapSource in winform doesn't contain the SetSource method, I have use a stupid property (Source).
Simply copy and paste and compile and enjoy
[code language=C#]
using System;
using System.Windows;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Media.Imaging;
using System.Xml.Schema;
using System.Xml;
#if !SILVERLIGHT
using System.Drawing;
#endif
namespace SmartDial.Data
{
public class SerializableImage : BitmapSource, IXmlSerializable
{
#if SILVERLIGHT
private string ImageToString(BitmapSource image)
#else
private string ImageToString(Bitmap image)
#endif
{
byte[] byteArray;
using (MemoryStream stream = new MemoryStream())
{
#if SILVERLIGHT
WriteableBitmap bmp = new WriteableBitmap((BitmapSource)image);
bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
byteArray = stream.ToArray();
#else
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Flush();
byteArray = stream.ToArray();
#endif
}
return Convert.ToBase64String(byteArray);
}
public SerializableImage() { }
#if SILVERLIGHT
public SerializableImage(Uri uri)
{
using (Stream stream = Application.GetResourceStream(uri).Stream)
{
this.SetSource(stream);
}
}
#else
public SerializableImage(Image image)
{
this.Source = (Bitmap)image;
}
protected override Freezable CreateInstanceCore() { return new SerializableImage(); }
public Bitmap Source { get; set; }
#endif
private void StringToImage(string imageString)
{
if (imageString == null)
throw new ArgumentNullException("imageString");
byte[] array = Convert.FromBase64String(imageString);
#if SILVERLIGHT
this.SetSource (new MemoryStream(array));
#else
Source = (Bitmap)Image.FromStream(new MemoryStream(array));
#endif
}
#region IXmlSerializable Members
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement || !reader.Read())
{
return;
}
XmlSerializer imgSerializer = new XmlSerializer(typeof(string));
while (reader.NodeType != XmlNodeType.EndElement)
{
reader.ReadStartElement("SerializedImage");
string img = (string)imgSerializer.Deserialize(reader);
reader.ReadEndElement();
reader.MoveToContent();
StringToImage(img);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
XmlSerializer imgSerializer = new XmlSerializer(typeof(string));
writer.WriteStartElement("SerializedImage");
#if SILVERLIGHT
string img = ImageToString( this);
#else
string img = ImageToString(this.Source);
#endif
imgSerializer.Serialize(writer, img);
writer.WriteEndElement();
}
#endregion
}
}
[/code]