【问题标题】:Datacontract serialization/serialization with imagesDatacontract序列化/带图像的序列化
【发布时间】:2016-06-10 20:32:16
【问题描述】:

我有一个类,其图像必须(有时)根据图像是否嵌入的事实进行序列化/反序列化。

[DataContract(IsReference = true)]
public class Data
{
  [DataContract(IsReference = true)]
  public class MyImage
  {

  [DataMember]
  int WidthStorage
  [DataMember]
  int HeightStorage;

  [DataMember]
  public string strImageLocation;
  [DataMember]
  public Image ImageEmbedded = new Image();<----- not working null
  public bool GetImage(Image image, int width, int height)
  {
    ...
  }

  public void SetImageFSlocation(string _strImageLocation, int _widthStorage, int _heightStorage)
  {
    ...        
  }

  public void SetImageEmbedded(string strPathFilename, int _widthStorage, int _heightStorage)
  {
    ...
  }

}

所以问题是尽管放了

public Image ImageEmbedded = new Image();

ImageEmbedded 始终为空。 所以我把它放在像

这样的构造函数中
[DataContract(IsReference = true)]
  public class MyImage
  {
    public MyImage()
    {
      ImageEmbedded = new Image();
    }
    ...

但是当我这样做时,我得到一个序列化错误。 那我该怎么办? 我不会将 Image 转换为 byte[] 或其他。我选择了 Datacontract 序列化,因为我认为它可以序列化图像。 谢谢

【问题讨论】:

  • 哪里说DataContractSerializer可以序列化一个Image?
  • 那么数据契约序列化器有什么优势???
  • 比什么有优势?
  • 超过标准的 MS 二进制序列化
  • 与 .NET 以外的其他系统的兼容性。二进制序列化几乎是 .NET 特定的,不太可能可靠地与其他任何东西一起使用。

标签: c# wpf image datacontractserializer


【解决方案1】:

您的代码中存在一个主要问题:在 WPF 中,如果您序列化一个图像,您将序列化 System.Windows.Controls.Image。所以简而言之,序列化控件是没有意义的。相反,您可能想要序列化 ​​BitmapSource,但这里再次无法序列化,因此您必须将它们转换为 byte[],如前所述。

[DataMember]
public byte[] bytesBitmapEmbedded;

然后通过这个简单地将其更改为 BitmapSource 或 byte[]:

bytesBitmapEmbedded = Converter.BitmapSource2ByteArray(bitmapSource);

bitmapSource = Converter.ByteArray2BitmapSource(bytesBitmapEmbedded);

public static class Converter
{
    public static byte[] BitmapSource2ByteArray(BitmapSource bitmap)
    {
        using (var stream = new MemoryStream())
        {
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitmap));
            encoder.Save(stream);
            return stream.ToArray();
        }
    }

    public static BitmapSource ByteArray2BitmapSource(byte[] buffer)
    {
        using (var stream = new MemoryStream(buffer))
        {
            return BitmapFrame.Create(stream,
                BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }
    }
}

【讨论】:

  • 这工作谢谢!!但是请在序列化/反序列化后我失去背景透明度。
  • 非常简单:使用 PngBitmapEncoder 代替 BmpBitmapEncoder
【解决方案2】:

如果您的序列化程序不直接知道如何转换字段的类型,那么您将面临逆风。更简单的解决方案是恢复到大多数语言中的更原始类型;创建一个Data-Transfer Object。例如,我用protobuf.net 存储了相当多的一维数据,使用类似的东西(根据您的需要进行编辑):

[DataContract]
class ImageDTO
{
    [DataMember(Order = 1)]
    public int Width { get; set; }

    [DataMember(Order = 2)]
    public int Height { get; set; }

    [DataMember(Order = 3)]
    public ImageFormat Format { get; set; }

    [DataMember(Order = 4)]
    public byte[] Data { get; set; }

    [DataMember(Order = 5)]
    public string AltUrl { get; set; }
}

因此,在您的情况下,您只需要处理图像格式枚举代码并从图像中获取二进制数据。见Fastest way to convert Image to Byte arrayWPF Image to byte[]https://github.com/teichgraf/WriteableBitmapEx/

然后你可以简单地将这个ImageDTO 的任何实例扔给几乎大多数基于合同的序列化器/反序列化器。例如,如果您选择协议缓冲区,在 .net 中您可以使用protobuf.net 进行序列化,而在 javascript 中您可以使用protobuf.js 进行反序列化,因为.proto

message ImageDTO {
   optional int32 Width = 1 [default = 0];
   optional int32 Height = 2 [default = 0];
   optional ImageFormat Format = 3 [default = RGB];
   optional bytes Data = 4;
   optional string AltUrl = 5;
}
enum ImageFormat {
   RGB = 0;
   RGBA = 1;
   PNG = 2;
   JPEG = 3;
}

【讨论】:

  • 谢谢,如果我没记错的话,protobuf.net 是一种不同类型的数据合同序列化吗?如果是这样,我想坚持标准数据合同。在任何情况下,我都在尝试更改 Image-->byte[]。然后尝试了“将图像转换为字节数组的最快方法”链接。但这不适用于 WPF!
  • 我添加了更多链接来询问该问题 WPF 图像 > 字节。您可能会发现 WriteableBitmapEx 也有一些访问方法可以提供帮助。 protobuf.net 是一个 Contract 序列化器(可以使用 DataContract 属性),但它序列化为协议缓冲区二进制格式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多