2013-03-19 31 views
5

Tôi đang sử dụng Newtonsoft.Json để deserialize đầu ra từ webservice của tôi cho một đối tượng. Nó hoạt động tốt cho đến khi tôi thêm tài sản Bitmap vào lớp học của tôi (tên là User) để giữ hình đại diện.Newtonsoft.Json deserializing hình ảnh base64 không thành công

Webservice sẽ trả về đúng như chuỗi Base64, như mong đợi. Vấn đề là khi tôi cố gắng để chuyển đổi lại JSON từ WS đến một List<User>, một JsonSerializationException được ném trong khối mã này:

// 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 từ ngoại lệ là:

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

và tìm kiếm ở ngoại lệ bên trong:

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

Rõ ràng là nó không phân tích cú pháp chuỗi Base64, nhưng không rõ tại sao.

Bất kỳ ý tưởng/giải pháp nào?

EDIT Tôi biết tôi có thể sử dụng Convert.FromBase64String để nhận mảng byte và tải bitmap từ đó. Sau đó, tôi muốn cập nhật câu hỏi của mình để hỏi về cách tôi có thể bỏ qua hoặc phân tích cú pháp theo cách thủ công chỉ trường đó. Tôi muốn tránh, phải phân tích cú pháp tất cả JSON theo cách thủ công. Điều này có thể thực hiện được không?

CHỈNH SỬA 2 Tôi phát hiện ra vấn đề gốc: JSON không được sắp xếp chính xác trong webservice (và tôi không thấy lý do tại sao). Tôi nghĩ rằng this là một vấn đề hơi khác, nhưng không. Webservice của tôi chỉ đơn giản trả về một chuỗi "System.Drawing.Bitmap" thay vì nội dung base64 của nó. Do đó, JsonSerializationException.

Tôi không thể giải quyết vấn đề đó, giải pháp duy nhất tôi tìm thấy là biến trường của tôi thành byte [].

Trả lời

9

đọc rằng lĩnh vực như chuỗi,

chuyển đổi sang byte mảng sử dụng Convert.FromBase64String

có được hình ảnh sử dụng Bitmap.FromStream(new MemoryStream(bytearray));

EDIT

Bạn có thể thực hiện hình ảnh serialization/deserialization với trợ giúp của bộ chuyển đổi tùy chỉnh

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

Đây là 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())); 
    } 
} 
+0

Vui lòng tham khảo câu hỏi thay đổi nội dung của tôi. Có cách nào để làm cho 'JsonConvert.DeserializeObject (json)' bỏ qua một trường chỉ? Đây là bên trong một phương pháp chung, vì vậy tôi muốn tránh một phân tích thủ công đầy đủ ... – Joel

+0

@Joel Xem chỉnh sửa của tôi ..... Không cần regex hoặc phân tích cú pháp chuỗi json theo cách thủ công. – I4V

+0

Với mã này, tôi phải sắp xếp theo cách thủ công đối tượng của mình trong webservice, phải không? – Joel

1

Tôi nghĩ rằng deserializing Base64-System.Drawing.Bitmap không được hỗ trợ.Có thể bạn có thể thử deserializing mọi thứ excepts các Avatar tài sản

EDIT CHO chỉnh sửa câu hỏi

Đây là một cuộc thảo luận thú vị về cách để làm điều đó: JSON.Net Ignore Property during deserialization

Tôi nghĩ rằng tốt nhất mà bạn có thể làm đang sử dụng Regex để xóa thuộc tính khỏi chuỗi json:

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

và sau đó deserialize thứ là newJsonString không có thuộc tính Hình đại diện.

Sau đó bạn có thể phân tích các chuỗi json bản gốc để lấy base64 và xây dựng 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; 
} 

Bạn có thể cải thiện các biểu thức thông thường hay phương pháp, nhưng đó là ý tưởng cơ bản.

+0

"bạn có thể thử deserializing tất cả mọi thứ excepts các tài sản Avatar ..." Có cách nào để này mà không cần phải phân tích cú pháp tất cả các yếu tố theo cách thủ công? – Joel

+1

a) Mã hóa Base64 yêu cầu 64 ký tự nhưng tôi chỉ thấy 62 trong regex này 'A-Za-z0-9' b) Cố gắng phân tích cú pháp json với regex là không tốt. c) "* Tôi nghĩ rằng Deserializing từ Base64 đến System.Drawing.Bitmap không được hỗ trợ. *" không chính xác. d) bạn có thể khai báo trường 'avatar' thành chuỗi và tạo hình ảnh trong C# không có regex. –

6

Đây là giải pháp của tôi, tôi đã sử dụng chú thích

[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 
Các vấn đề liên quan