代码之家  ›  专栏  ›  技术社区  ›  Joel user3568717

Newtonsoft.Json反序列化base64映像失败

  •  6
  • Joel user3568717  · 技术社区  · 11 年前

    我正在使用Newtonsoft.Json将Web服务的输出反序列化为一个对象。 它一直很好,直到我加了一个 Bitmap 属性到我的类(名为 User )拿着一个化身。

    Web服务正在以Base64字符串的形式返回该属性,这是预期的。 问题是当我试图将JSON从WS转换回 List<User> JsonSerializationException 在此代码块中引发:

    // 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! 
         });
    

    异常的输出为:

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

    并查看内部异常:

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

    很明显,它无法解析Base64字符串,但原因尚不清楚。

    有什么想法/解决办法吗?

    编辑 我知道我可以用 Convert.FromBase64String 一定要获取一个字节数组并从中加载一个位图。然后我想更新我的问题以询问 怎样 我可以跳过还是手动解析 只有 那个领域。 我希望避免手动解析所有JSON。 这可能吗?

    编辑2 我发现了根本问题:JSON没有在webservice中正确序列化(我不知道为什么)。我认为 this 是一个有点不同的问题,但不是。我的Web服务只是返回一个字符串 "System.Drawing.Bitmap" 而不是其base64内容。因此 Json序列化异常 .

    我一直无法解决这个问题,我找到的唯一解决方案是将我的领域变成 byte [] .

    3 回复  |  直到 7 年前
        1
  •  11
  •   I4V    11 年前

    将该字段作为字符串读取,

    使用转换为字节数组 Convert.FromBase64String

    使用获取图像 Bitmap.FromStream(new MemoryStream(bytearray));

    编辑

    您可以在自定义的帮助下执行图像序列化/反序列化 转换器

    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());
    

    这是 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()));
        }
    }
    
        2
  •  7
  •   Radim Köhler    11 年前

    这是我的解决方案,我使用了注释

    [Serializable]
    public class MyClass
    {
        [JsonConverter(typeof(CustomBitmapConverter))]
        public Bitmap MyImage { get; set; }
    
    
        #region JsonConverterBitmap
        internal class CustomBitmapConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return true;
            }
    
            //convert from byte to bitmap (deserialize)
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                string image = (string)reader.Value;
    
                byte[] byteBuffer = Convert.FromBase64String(image);
                MemoryStream memoryStream = new MemoryStream(byteBuffer);
                memoryStream.Position = 0;
    
                return (Bitmap)Bitmap.FromStream(memoryStream);
            }
    
            //convert bitmap to byte (serialize)
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                Bitmap bitmap = (Bitmap)value;
    
                ImageConverter converter = new ImageConverter();
                writer.WriteValue((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
            }
    
            public static System.Drawing.Imaging.ImageFormat GetImageFormat(Bitmap bitmap)
            {
                ImageFormat img = bitmap.RawFormat;
    
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
                    return System.Drawing.Imaging.ImageFormat.Jpeg;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
                    return System.Drawing.Imaging.ImageFormat.Bmp;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Png))
                    return System.Drawing.Imaging.ImageFormat.Png;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Emf))
                    return System.Drawing.Imaging.ImageFormat.Emf;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Exif))
                    return System.Drawing.Imaging.ImageFormat.Exif;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Gif))
                    return System.Drawing.Imaging.ImageFormat.Gif;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Icon))
                    return System.Drawing.Imaging.ImageFormat.Icon;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
                    return System.Drawing.Imaging.ImageFormat.MemoryBmp;
                if (img.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
                    return System.Drawing.Imaging.ImageFormat.Tiff;
                else
                    return System.Drawing.Imaging.ImageFormat.Wmf;
            }
    
        }
    
        #endregion
    
        3
  •  0
  •   Community TheSoundDefense    7 年前

    我认为从 Base64 System.Drawing.Bitmap 不支持。可能您可以尝试反序列化除 Avatar 所有物

    编辑已编辑的问题

    以下是关于如何做到这一点的有趣讨论: JSON.Net Ignore Property during deserialization

    我认为你能做的最好的事情就是使用 Regex 要从json字符串中删除属性:

    var newJsonString = Regex.Replace(jsonString, 
                                      "(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"", 
                                      String.Empty);
    

    然后将其反序列化 newJsonString 没有Avatar属性。

    稍后您可以解析原始json字符串以获得 base64 并构建 Bitmap

    var avatarBase64 = Regex.Match(
                            Regex.Match(json, "(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"")
                                 .ToString(), 
                            "[A-Za-z0-9]+", RegexOptions.RightToLeft)
                            .ToString();
    
    ...
    
    byte[] fromBase64 = Convert.FromBase64String(avatarBase64);
    using (MemoryStream ms = new MemoryStream(fromBase64))
    {
        Bitmap img = (Bitmap)Image.FromStream(ms);
        result.Avatar = img;
    }
    

    您可以改进正则表达式或方法,但这是基本思想。