C
C#9mo ago
Conner

❔ Cannot deserialize System.Drawing.Color from JSON

It seems like the System.Text.Json library is not able to deserialize a Color from a JSON string it serialized before. Code I used for testing:
public static void TestSerialisation()
{
Color toJson = Color.FromArgb(0xFF, 0xF, 0x36);
string inJson = JsonSerializer.Serialize(toJson);
Color fromJson = JsonSerializer.Deserialize<Color>(inJson);
}
public static void TestSerialisation()
{
Color toJson = Color.FromArgb(0xFF, 0xF, 0x36);
string inJson = JsonSerializer.Serialize(toJson);
Color fromJson = JsonSerializer.Deserialize<Color>(inJson);
}
75 Replies
Pobiega
Pobiega9mo ago
Write your own converter then
ero
ero9mo ago
tuple issue i guess whoopie
Pobiega
Pobiega9mo ago
Yup, seems likely
Conner
Conner9mo ago
I dont think I understand?
Pobiega
Pobiega9mo ago
Tuples can be serialized but not easily deserialized. You will need a custom converter afaik
Conner
Conner9mo ago
but the Color struct doesnt use Tuples
Thinker
Thinker9mo ago
What Color struct is this? From System.Drawing?
Conner
Conner9mo ago
yes
Thinker
Thinker9mo ago
ah, seems like it's read-only yeah you'd probably need to write your own STJ converter for it
Thinker
Thinker9mo ago
How to write custom converters for JSON serialization - .NET
Learn how to create custom converters for the JSON serialization classes that are provided in the System.Text.Json namespace.
Conner
Conner9mo ago
ah ok I get it then. I was just confused because the Newtonsoft.Json library was able to do it when I still used that
TheRanger
TheRanger9mo ago
tbh serializing the other properties are unnecessarily
Thinker
Thinker9mo ago
idk how Newtonsoft would be able to do that since the properties are get-only
Conner
Conner9mo ago
What if I create my own color struct and add an implicit cast to System.Drawing.Color
TheRanger
TheRanger9mo ago
maybe newtonsoft had a custom converter for Color
MODiX
MODiX9mo ago
ero
REPL Result: Success
System.Text.Json.JsonSerializer.Serialize((1, 2, 3, 4))
System.Text.Json.JsonSerializer.Serialize((1, 2, 3, 4))
Result: string
{}
{}
Quoted by
<@542772576905199626> from #bot-spam (click here)
Compile: 549.845ms | Execution: 48.130ms | React with ❌ to remove this embed.
ero
ero9mo ago
:/
Thinker
Thinker9mo ago
what's the deal with tuples? System.Drawing.Color isn't a tuple
ero
ero9mo ago
ARGB is
ero
ero9mo ago
Thinker
Thinker9mo ago
no it's not that's just how it displays it looks like a debugger display attribute if you look at the code, they're clearly serializing toJson, which is a Color
Pobiega
Pobiega9mo ago
Iirc it uses reflection to get the private setter
Thinker
Thinker9mo ago
ah
ero
ero9mo ago
there is no setter actually it's a readonly struct it also has no public constructor except for the default parameterless one i guess
Conner
Conner9mo ago
Ill just go ahead an write a custom converter prevents it from saving all the unnecessary fields as well
TheRanger
TheRanger9mo ago
u could try this
MODiX
MODiX9mo ago
TheRanger
REPL Result: Success
using System.Drawing;
using System.Text.Json;
public class ColorSerializer
{
struct col
{
public byte R{get;set;}
public byte G{get;set;}
public byte B{get;set;}
public byte A{get;set;}
}
public static string Serialize(Color color)
{
var foo = new col{R=color.R,G=color.G,B=color.B,A=color.A};
return JsonSerializer.Serialize(foo);
}

public static Color Deserialize(string str)
{
var foo = JsonSerializer.Deserialize<col>(str);
return Color.FromArgb(foo.A, foo.R, foo.G, foo.B);
}
}

Color toJson = Color.FromArgb(0xFF, 0xF, 0x36);
string inJson = ColorSerializer.Serialize(toJson);
Color fromJson = ColorSerializer.Deserialize(inJson);
Console.WriteLine(fromJson);
using System.Drawing;
using System.Text.Json;
public class ColorSerializer
{
struct col
{
public byte R{get;set;}
public byte G{get;set;}
public byte B{get;set;}
public byte A{get;set;}
}
public static string Serialize(Color color)
{
var foo = new col{R=color.R,G=color.G,B=color.B,A=color.A};
return JsonSerializer.Serialize(foo);
}

public static Color Deserialize(string str)
{
var foo = JsonSerializer.Deserialize<col>(str);
return Color.FromArgb(foo.A, foo.R, foo.G, foo.B);
}
}

Color toJson = Color.FromArgb(0xFF, 0xF, 0x36);
string inJson = ColorSerializer.Serialize(toJson);
Color fromJson = ColorSerializer.Deserialize(inJson);
Console.WriteLine(fromJson);
Console Output
Color [A=255, R=255, G=15, B=54]
Color [A=255, R=255, G=15, B=54]
Compile: 811.230ms | Execution: 124.396ms | React with ❌ to remove this embed.
Conner
Conner9mo ago
Thanks but I dont want to only serialize one color. I have a bunch of dictionaries with dictionaries with colors in them
TheRanger
TheRanger9mo ago
u mean a color array/list?
Conner
Conner9mo ago
No I mean dictionaries with more dictionaries and then colors in those
TheRanger
TheRanger9mo ago
i see, then ud probably need a custom converter then
Conner
Conner9mo ago
So I am having trouble writing this converter I would like my colors to be converted to the following "FieldName" : "R, G, B" Obviously for writing I could just do
public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
{
writer.WriteStringValue($"{value.R}, {value.G}, {value.B}");
}
public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
{
writer.WriteStringValue($"{value.R}, {value.G}, {value.B}");
}
but I am not sure how the reader would work with this
TheRanger
TheRanger9mo ago
read the docs u can define a method called Read
Conner
Conner9mo ago
yes I know I dont know how to properly extract the values though would I have to just call ReadString and then do some string manipulation there? Because obviously its all in one string
TheRanger
TheRanger9mo ago
you can use .Split, or regex
Conner
Conner9mo ago
Ok
Jimmacle
Jimmacle9mo ago
i'm late but the contents of "fromJson" aren't valid json to begin with looks like it just .ToString()ed the color
Conner
Conner9mo ago
what fromJson isnt even a string
Jimmacle
Jimmacle9mo ago
ignore me i can't read
TheRanger
TheRanger9mo ago
theyre writing the converter now
Jimmacle
Jimmacle9mo ago
too many variables called json when
Conner
Conner9mo ago
happens to the best of us
reflectronic
reflectronic9mo ago
internal sealed class ColorJsonConverter : JsonConverter<Color>
{
private static ColorConverter converter = new();

public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return (Color)converter.ConvertFromString(reader.GetString() ?? "")!;
}

public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
{
writer.WriteStringValue(converter.ConvertToString(value));
}
}
internal sealed class ColorJsonConverter : JsonConverter<Color>
{
private static ColorConverter converter = new();

public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return (Color)converter.ConvertFromString(reader.GetString() ?? "")!;
}

public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options)
{
writer.WriteStringValue(converter.ConvertToString(value));
}
}
this is what you want
TheRanger
TheRanger9mo ago
it allocates more data tho theres a space after each when
Conner
Conner9mo ago
does ConvertFromString work if the colors are seperated by commas opposed to semicolons?
reflectronic
reflectronic9mo ago
yes that is how it serializes by default as well well. ColorConverter does some special stuff. consider:
Conner
Conner9mo ago
it does not work with commas it seems, unfortunate
MODiX
MODiX9mo ago
reflectronic
REPL Result: Success
using System.Drawing;
var converter = new ColorConverter();
new
{
NoAlpha = converter.ConvertToString(Color.FromArgb(100, 80, 60)),
WithAlpha = converter.ConvertToString(Color.FromArgb(50, 100, 80, 60)),
WellKnown = converter.ConvertToString(Color.CornflowerBlue),
System = converter.ConvertToString(SystemColors.MenuHighlight)
}
using System.Drawing;
var converter = new ColorConverter();
new
{
NoAlpha = converter.ConvertToString(Color.FromArgb(100, 80, 60)),
WithAlpha = converter.ConvertToString(Color.FromArgb(50, 100, 80, 60)),
WellKnown = converter.ConvertToString(Color.CornflowerBlue),
System = converter.ConvertToString(SystemColors.MenuHighlight)
}
Result: <>f__AnonymousType0#1<string, string, string, string>
{
"noAlpha": "100, 80, 60",
"withAlpha": "50, 100, 80, 60",
"wellKnown": "CornflowerBlue",
"system": "MenuHighlight"
}
{
"noAlpha": "100, 80, 60",
"withAlpha": "50, 100, 80, 60",
"wellKnown": "CornflowerBlue",
"system": "MenuHighlight"
}
Compile: 520.415ms | Execution: 74.759ms | React with ❌ to remove this embed.
MODiX
MODiX9mo ago
reflectronic
REPL Result: Success
using System.Drawing;
var converter = new ColorConverter();
converter.ConvertFromString("50,80,120")
using System.Drawing;
var converter = new ColorConverter();
converter.ConvertFromString("50,80,120")
Result: Color
{
"r": 50,
"g": 80,
"b": 120,
"a": 255,
"isKnownColor": false,
"isEmpty": false,
"isNamedColor": false,
"isSystemColor": false,
"name": "ff325078"
}
{
"r": 50,
"g": 80,
"b": 120,
"a": 255,
"isKnownColor": false,
"isEmpty": false,
"isNamedColor": false,
"isSystemColor": false,
"name": "ff325078"
}
Compile: 563.665ms | Execution: 36.646ms | React with ❌ to remove this embed.
Conner
Conner9mo ago
huh
reflectronic
reflectronic9mo ago
what do you mean by it not working
Conner
Conner9mo ago
Im not sure either now
Conner
Conner9mo ago
I get this exception
Conner
Conner9mo ago
but this might be due to a bad json file? ill check
reflectronic
reflectronic9mo ago
oh, i see what the problem is
Conner
Conner9mo ago
no defnitely doesnt work with commas in the json
reflectronic
reflectronic9mo ago
use ConvertToString(null, CultureInfo.InvariantCulture, value)
TheRanger
TheRanger9mo ago
huh it works here
reflectronic
reflectronic9mo ago
yeah it uses the list separator based on the current culture
TheRanger
TheRanger9mo ago
oh their culture
reflectronic
reflectronic9mo ago
oh, actuall
TheRanger
TheRanger9mo ago
but wait shouldnt converter.ConvertToString(value) return 255. 255. 255?
reflectronic
reflectronic9mo ago
you can just use (Color)converter.ConvertFromInvariantString(reader.GetString() ?? "") and converter.ConvertToInvariantString(color)
TheRanger
TheRanger9mo ago
or whatever the list seperator their culture uses
reflectronic
reflectronic9mo ago
it would but i imagine this JSON was serialized before
TheRanger
TheRanger9mo ago
or maybe they used an already serialized json when
Conner
Conner9mo ago
whats this whole culture thing like is it due to me living in a different country I have different list seperators?
reflectronic
reflectronic9mo ago
yes
Conner
Conner9mo ago
what a stupid feature
TheRanger
TheRanger9mo ago
based on ur pc settings its not some cultures uses . as the default seperator
reflectronic
reflectronic9mo ago
it is actually much more stupid to show someone that lives in Germany 27.5 instead of 27,5 in their user interface
Conner
Conner9mo ago
it is, I wouldnt mind having to use semicolons but if people in other countries share their files they would be incompatible I guess
reflectronic
reflectronic9mo ago
that is why you use ConvertFromInvariantString like i said it fixes this issue
Conner
Conner9mo ago
Yea I get it. I just didnt expect list seperators to be different in other cultures I thought there would be some standard to it Yea thanks I will try that
Accord
Accord9mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.