Serialize a Bitmap in C#/.NET to XML
I would do something like:
[XmlIgnore]
public Bitmap LargeIcon { get; set; }
[Browsable(false),EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("LargeIcon")]
public byte[] LargeIconSerialized
{
get { // serialize
if (LargeIcon == null) return null;
using (MemoryStream ms = new MemoryStream()) {
LargeIcon.Save(ms, ImageFormat.Bmp);
return ms.ToArray();
}
}
set { // deserialize
if (value == null) {
LargeIcon = null;
} else {
using (MemoryStream ms = new MemoryStream(value)) {
LargeIcon = new Bitmap(ms);
}
}
}
}
Bitmap XML Serialization
You could make a property that get/sets your bitmap as a byte array. This should be base-64 encoded by the serializer.
public byte[] MyImageBytes {
get {
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(MyImage, typeof(byte[]));
}
}
You would probably also want to hide your Bitmap property with an [XmlIgnore] attribute. You may also want to prefer LinqToXml to the serializer as it gives you far more control.
Note that XmlSerializer performs quite badly when base-64 encoding. This is also the case for LinqToXml, the BitConverter class does a fine job converting to base-64 though.
Serialize and Store an Image in an XML File
XmlSerializer can't serialize or deserialize the WPF image types like BitmapImage etc. It is however able to (de)serialize byte arrays. So you may add a byte[] ImageBuffer
property to your Person class, which contains the binary image data. You would then also set the XmlIgnore
attribute on the Image
property to suppress its (de)serialization, and set XmlElement("Image")
on the ImageBuffer
properties to (de)serialize it as <Image>...</Image>
.
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
[XmlIgnore]
public BitmapSource Image { get; set; }
[XmlElement("Image")]
public byte[] ImageBuffer
{
get
{
byte[] imageBuffer = null;
if (Image != null)
{
using (var stream = new MemoryStream())
{
var encoder = new PngBitmapEncoder(); // or some other encoder
encoder.Frames.Add(BitmapFrame.Create(Image));
encoder.Save(stream);
imageBuffer = stream.ToArray();
}
}
return imageBuffer;
}
set
{
if (value == null)
{
Image = null;
}
else
{
using (var stream = new MemoryStream(value))
{
var decoder = BitmapDecoder.Create(stream,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
Image = decoder.Frames[0];
}
}
}
}
}
This approach has also been suggested for properties of type Bitmap in this answer.
Serialize a System.Windows.Media.ImageSource object
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.
C#: Why would an object that implements Serializable wouldn't be possible to serialize?
There's a hint in the stacktrace:
InnerException: System.InvalidOperationException
Message="The type System.Drawing.Bitmap was not expected.
Use the XmlInclude or SoapInclude attribute to specify types
that are not known statically."
System.Drawing.Bitmap
is not Xml Serializable, hence the exception. Perhaps another way would be to use XmlIgnoreAttribute
to ignore this property, or implement IXmlSerializable
and serialize the image as an ascii blob if you really need it saved?
See the related question & answer Serializing a Bitmap in C# to XML
contributed by Conrad Frix in comments
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);
}
}
Related Topics
What's the Difference Between Anonymous Methods (C# 2.0) and Lambda Expressions (C# 3.0)
Catch All Unhandled Exceptions in ASP.NET Web API
Should I Always Return Ienumerable<T> Instead of Ilist<T>
C# Entity-Framework: How to Combine a .Find and .Include on a Model Object
Displayname Attribute VS Display Attribute
How to Make Method Call Another One in Classes
How to Know User Has Clicked "X" or the "Close" Button
C# Filestream:Optimal Buffer Size for Writing Large Files
How to Use Interface as a C# Generic Type Constraint
Cannot Convert Lambda Expression to Type 'System.Delegate'
The Type '...' Has No Constructors Defined
ASP.NET Core API Only Returning First Result of List