序列化 WPF 图像

发布于 2024-08-20 07:40:24 字数 4608 浏览 2 评论 0原文

我试图了解图像序列化在 WPF 中的工作原理。我有以下课程:

[Serializable]
public class TestClass : ISerializable
{
    public TestClass() { }


    protected TestClass(SerializationInfo info, StreamingContext context)
    {
        SerializedImage = (byte[])info.GetValue("SerializedImage", typeof(byte[]));
    }


    public byte[] SerializedImage { get; set; }


    public Image Image { get; set; }


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("SerializedImage", SerializedImage);
    }


    [OnSerializing]
    private void OnSerializing(StreamingContext sc)
    {
        BitmapImage image = Image.Source as BitmapImage;

        MemoryStream stream = new MemoryStream();
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(image));
        encoder.Save(stream);

        SerializedImage = stream.ToArray();

        stream.Close(); ;
    }


    [OnDeserialized]
    private void OnDeserialized(StreamingContext sc)
    {
        MemoryStream stream = new MemoryStream(SerializedImage);
        Image = new Image
        {
            Source = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
        };

        stream.Close();
    }
}

这是 Xaml 代码:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="358" Width="300" ResizeMode="NoResize">
<StackPanel>

    <Image x:Name="Screenshot" Height="178" />
    <Button Width="80" Height="30" Content="Load Image" Click="Button_Click_1" />
    <Button Width="92" Height="30" Content="Save to file" Click="Button_Click_2" />
    <Button Width="92" Height="30" Content="Load File" Click="Button_Click_3" />
    <Button Width="92" Height="30" Content="Load File (1)" Click="Button_Click_4" />

</StackPanel>

这是背后的代码:

public partial class Window1 : Window
{
    TestClass test;


    public Window1()
    {
        InitializeComponent();

        test = new TestClass();
    }


    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "Bmp Image | *.bmp" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            Screenshot.Source = new BitmapImage(new Uri(dialog.FileName));
            test.Image = Screenshot;
        }
    }


    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog { DefaultExt = ".t", AddExtension = true };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Create);
            formatter.Serialize(stream, test);
            stream.Close();
        }
    }


    private void Button_Click_3(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot = test.Image;
        }
    }


    private void Button_Click_4(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot.Source = null;

            MemoryStream stream1 = new MemoryStream(test.SerializedImage);
            Screenshot.Source = BitmapFrame.Create(stream1, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
        }
    }
}

现在由于某种我不知道的原因,TestClass 中图像的反序列化效果不佳。如果我抓取字节数组并将其转换回图像(Button_Click_4),它就会工作并且图像会显示在我的表单上。相反,如果我直接从 TestClass 中的 Image 属性获取图像,则表单上不会显示任何内容。我不知道这怎么可能,因为两种情况涉及的代码是相同的,除非幕后发生了其他事情。

我做错了什么?我提供了完整的代码,你可以粘贴并运行看看问题所在。

I'm trying to understand how image serialization works in WPF. I have the following class:

[Serializable]
public class TestClass : ISerializable
{
    public TestClass() { }


    protected TestClass(SerializationInfo info, StreamingContext context)
    {
        SerializedImage = (byte[])info.GetValue("SerializedImage", typeof(byte[]));
    }


    public byte[] SerializedImage { get; set; }


    public Image Image { get; set; }


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("SerializedImage", SerializedImage);
    }


    [OnSerializing]
    private void OnSerializing(StreamingContext sc)
    {
        BitmapImage image = Image.Source as BitmapImage;

        MemoryStream stream = new MemoryStream();
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(image));
        encoder.Save(stream);

        SerializedImage = stream.ToArray();

        stream.Close(); ;
    }


    [OnDeserialized]
    private void OnDeserialized(StreamingContext sc)
    {
        MemoryStream stream = new MemoryStream(SerializedImage);
        Image = new Image
        {
            Source = BitmapFrame.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
        };

        stream.Close();
    }
}

This is the Xaml code:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="358" Width="300" ResizeMode="NoResize">
<StackPanel>

    <Image x:Name="Screenshot" Height="178" />
    <Button Width="80" Height="30" Content="Load Image" Click="Button_Click_1" />
    <Button Width="92" Height="30" Content="Save to file" Click="Button_Click_2" />
    <Button Width="92" Height="30" Content="Load File" Click="Button_Click_3" />
    <Button Width="92" Height="30" Content="Load File (1)" Click="Button_Click_4" />

</StackPanel>

And this is the code behind:

public partial class Window1 : Window
{
    TestClass test;


    public Window1()
    {
        InitializeComponent();

        test = new TestClass();
    }


    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "Bmp Image | *.bmp" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            Screenshot.Source = new BitmapImage(new Uri(dialog.FileName));
            test.Image = Screenshot;
        }
    }


    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog { DefaultExt = ".t", AddExtension = true };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Create);
            formatter.Serialize(stream, test);
            stream.Close();
        }
    }


    private void Button_Click_3(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot = test.Image;
        }
    }


    private void Button_Click_4(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog { Filter = "TEST file | *.t" };
        dialog.ShowDialog();

        if (dialog.FileName != string.Empty)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(dialog.FileName, FileMode.Open);
            test = formatter.Deserialize(stream) as TestClass;
            stream.Close();

            Screenshot.Source = null;

            MemoryStream stream1 = new MemoryStream(test.SerializedImage);
            Screenshot.Source = BitmapFrame.Create(stream1, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
        }
    }
}

Now for some reason that I don't know, the deserialization of the image in TestClass is not working well. If I grab the byte array and convert it back to an image myself (Button_Click_4), it works and the image is shown on my form. If, instead, I grab the image directly from the Image property in TestClass, nothing will show on the form. I don't know how this is possible, since the code involved in both situations is the same, unless something else is happening behind the scenes.

What am I doing wrong? I have provided the complete code, you can paste it and run it to see the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

§对你不离不弃 2024-08-27 07:40:24

可视化树中的 Image 对象由名为“Screenshot”的字段引用。将 this.Screenshot 分配给新图像根本不会改变您的视觉树。它只是分配屏幕截图字段。在设置源的情况下,您将更新可视化树中的图像。

理想情况下,您的测试类应该公开 ImageSource 属性,而不是 Image。单个 Image 实例只能在可视化树中出现一次。因此,通过公开 ImageSource 属性,您可以在 Image 的多个实例中重用该属性(可以在可视化树中的各个位置使用)。

The Image object in your visual tree is referenced by a field called "Screenshot". Assigning this.Screenshot to a new Image does not alter your visual tree at all. It just assigns the field Screenshot. In the case where you set the Source, you are updating the Image that is in your visual tree.

Ideally, your test class should expose an ImageSource property, not an Image. A single Image instance can only appear once in the visual tree. So by exposing an ImageSource property, you can reuse that in several instances of Image (that may be used in various locations in your visual tree).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文