Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Newtonsoft.Json deserializing base64 image fails

Tags:

json

c#

.net

image

I'm using Newtonsoft.Json to deserialize the output from my webservice to an object. It worked fine until I added a Bitmapproperty to my class (named User) to hold an avatar.

The webservice is returning that propert as a Base64 string, which is as expected. The problem is when I try to convert back the JSON from the WS to a List<User>, a JsonSerializationException is thrown in this block of code:

// T is IList<User>
response.Content.ReadAsStringAsync().Proceed(
    (readTask) =>
    {
        var json = ((Task<string>)readTask).Result;
        var result = JsonConvert.DeserializeObject<T>(json); //<-- it fails here

         // do stuff! 
     });

Output from exception is:

Error converting value "System.Drawing.Bitmap" to type 'System.Drawing.Bitmap'. Path '[2].Avatar

and looking at the inner exception:

{"Could not cast or convert from System.String to System.Drawing.Bitmap."}

It's clear that it fails to parse the Base64 string, but it's not clear why.

Any ideas/workaround?

EDIT I know I can use Convert.FromBase64String do get a byte array and load a bitmap from that. Then I'd like to update my question to ask about how can I skip or manually parse only that field. I would like to avoid, having to manually parse all the JSON. Is this even possible?

EDIT 2 I found out the root problem: JSON is not being correctly serialized in webservice (and I fail to see why). I thought that this was a somewhat different issue, but no. My webservice is simply returning a string "System.Drawing.Bitmap" instead of its base64 content. Hence the JsonSerializationException.

I have been unable to solve that issue, the only solution I've found is to turn my field into a byte [].

like image 651
Joel Avatar asked Mar 19 '13 21:03

Joel


1 Answers

Read that field as string,

convert to byte array using Convert.FromBase64String and

get the image using Bitmap.FromStream(new MemoryStream(bytearray));

EDIT

You can perform image serialization/deserialization with the help of a custom converter

public class AClass
{
    public Bitmap image;
    public int i;
}

Bitmap bmp = (Bitmap)Bitmap.FromFile(@"......");
var json = JsonConvert.SerializeObject(new AClass() { image = bmp, i = 666 }, 
                                       new ImageConverter());

var aclass = JsonConvert.DeserializeObject<AClass>(json, new ImageConverter());

This is the ImageConverter

public class ImageConverter : Newtonsoft.Json.JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Bitmap);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var m = new MemoryStream(Convert.FromBase64String((string)reader.Value));
        return (Bitmap)Bitmap.FromStream(m);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Bitmap bmp = (Bitmap)value;
        MemoryStream m = new MemoryStream();
        bmp.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);

        writer.WriteValue(Convert.ToBase64String(m.ToArray()));
    }
}
like image 96
I4V Avatar answered Sep 23 '22 07:09

I4V