Newtonsoft.Json反序列化base64图像失败
本文关键字:图像 失败 base64 反序列化 Json Newtonsoft | 更新日期: 2023-09-27 18:04:50
我使用Newtonsoft。Json将webservice的输出反序列化为对象。它工作得很好,直到我添加了一个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中没有被正确序列化(我不知道为什么)。我以为这是一个不同的问题,但不是。我的web服务只是返回一个字符串"System.Drawing.Bitmap"
,而不是它的base64内容。因此JsonSerializationException
。
我一直无法解决这个问题,我找到的唯一解决方案是把我的字段变成byte []
.
将该字段读取为字符串,
使用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()));
}
}
这就是我的解决方案,我使用了注释
[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
我认为不支持从Base64
到System.Drawing.Bitmap
的反序列化。也许你可以尝试反序列化除Avatar
属性以外的所有内容
EDIT FOR已编辑的问题
这里有一个关于如何做到这一点的有趣讨论:JSON。反序列化期间的Net Ignore属性我认为你能做的最好的是使用Regex
从json字符串中删除属性:
var newJsonString = Regex.Replace(jsonString,
"('',)* '"Avatar'": '"[A-Za-z0-9]+'"",
String.Empty);
,然后反序列化这个没有Avatar属性的newJsonString
。
稍后您可以解析原始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;
}
您可以改进正则表达式或方法,但这是基本思想。