Most Elegant Xml Serialization of Color Structure

Most elegant XML serialization of Color structure

Here's something I'm using for serializing the Color struct in XML. It's better than shadowing the primary Color property in my opinion. Any suggestions welcome.

The XmlColor class relies primarily on the implicit operator language feature to provide the key data tranformations. Without this, the class is basically useless. Other bits of functionality were added to round out the class.

The XmlColor helper also provides a convenient way to separate color components. I added the Alpha property to show this. Notice the Alpha component won't be serialized if it's cranked all the way up to 255.

Deserializing the Web color value combines the Alpha value currently stored in the instance. The order in which the attributes are parsed shouldn't matter. If the Alpha attribute is missing in the XML source, the instance component value will be used to set the Alpha level. This is arguably faulty; however, in the case of XML serialization, the XmlColor class will initialized with Color.Black setting the Alpha to 255.

I'm working out of the VS2010 environment and building against .Net 4. I have no idea how compatible the code is with previous versions.

Here's an example property that should be serialized to XML:

    [XmlElement(Type=typeof(XmlColor))]
public Color MyColor { get; set; }

Here's the XmlColor helper class:

public class XmlColor
{
private Color color_ = Color.Black;

public XmlColor() {}
public XmlColor(Color c) { color_ = c; }

public Color ToColor()
{
return color_;
}

public void FromColor(Color c)
{
color_ = c;
}

public static implicit operator Color(XmlColor x)
{
return x.ToColor();
}

public static implicit operator XmlColor(Color c)
{
return new XmlColor(c);
}

[XmlAttribute]
public string Web
{
get { return ColorTranslator.ToHtml(color_); }
set {
try
{
if (Alpha == 0xFF) // preserve named color value if possible
color_ = ColorTranslator.FromHtml(value);
else
color_ = Color.FromArgb(Alpha, ColorTranslator.FromHtml(value));
}
catch(Exception)
{
color_ = Color.Black;
}
}
}

[XmlAttribute]
public byte Alpha
{
get { return color_.A; }
set {
if (value != color_.A) // avoid hammering named color if no alpha change
color_ = Color.FromArgb(value, color_);
}
}

public bool ShouldSerializeAlpha() { return Alpha < 0xFF; }
}

Best solution for XmlSerializer and System.Drawing.Color

The simplest method uses this at it's heart:

String HtmlColor = System.Drawing.ColorTranslator.ToHtml(MyColorInstance);

It will just convert whatever the color is to the standard hex string used by HTML which is just as easily deserialized using:

Color MyColor = System.Drawing.ColorTranslator.FromHtml(MyColorString);

That way you're just working with bog standard strings...

Serialize/Deserialize System.Drawing.Color with System.Text.Json

After some searching i found a solution and get a converter for System.Drawing.Color:

public class ColorJsonConverter : JsonConverter<Color>
{
public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => ColorTranslator.FromHtml(reader.GetString());

public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options) => writer.WriteStringValue("#" + value.R.ToString("X2") + value.G.ToString("X2") + value.B.ToString("X2").ToLower());
}

With the converter, serialization/deserilization is working proper.

Test test = new()
{
Farbe = Color.Red,
Farben = new List<Color>()
{
Color.Red,
Color.Green,
Color.Blue
}
};

var options = new JsonSerializerOptions()
{
Converters = {
new ColorJsonConverter()
}
};

File.WriteAllText("data.json", JsonSerializer.Serialize(test, options));

Test test2 = JsonSerializer.Deserialize<Test>(File.ReadAllText("data.json"), options);

Console.WriteLine($"{test2.Farbe.R}:{test2.Farbe.G}:{test2.Farbe.B}");
Console.WriteLine(string.Join(',', test2.Farben));

Result

255:0:0
Color [A=255, R=255, G=0, B=0],Color [A=255, R=0, G=128, B=0],Color [A=255, R=0, G=0, B=255]


Related Topics



Leave a reply



Submit