【问题标题】:WPF loading serialized imageWPF加载序列化图像
【发布时间】:2011-04-13 02:18:27
【问题描述】:

在一个应用程序中,我需要通过二进制写入器序列化图像,并在另一个应用程序中显示它。

这是我的“序列化”代码的一部分:

FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write);
BinaryWriter bin = new BinaryWriter(fs);                         

bin.Write((short)this.Animations.Count);

for (int i = 0; i < this.Animations.Count; i++)
{
    MemoryStream stream = new MemoryStream();
    BitmapEncoder encoder = new PngBitmapEncoder();

    encoder.Frames.Add(BitmapFrame.Create(Animations[i].Image));
    encoder.Save(stream);

    stream.Seek(0, SeekOrigin.Begin);

    bin.Write((int)stream.GetBuffer().Length);
    bin.Write(stream.GetBuffer());

    stream.Close();
}

bin.Close();

这是我的反序列化加载图像的部分:

FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader bin = new BinaryReader(fs);

int animCount = bin.ReadInt16();
int imageBytesLenght;
byte[] imageBytes;
BitmapSource img;

for (int i = 0; i < animCount; i++)
{    
    imageBytesLenght = bin.ReadInt32();
    imageBytes = bin.ReadBytes(imageBytesLenght);
    img = new BitmapImage();
    MemoryStream stream = new MemoryStream(imageBytes);
    BitmapDecoder dec = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    img = dec.Frames[0];
    stream.Close();
}

bin.Close();

当我使用这种方法时,我加载了图像(它似乎存储在“img”对象中)但无法显示。

有什么想法吗?

谢谢

风筝

UPD

我已经这样做了:更新我的绑定,甚至尝试通过窗口代码直接影响它。这些方法都不起作用:s

但是,当我添加这个时:

private void CreateFile(byte[] bytes)
{
    FileStream fs = new FileStream(Environment.CurrentDirectory + "/" + "testeuh.png", FileMode.Create, FileAccess.Write);
    fs.Write(bytes, 0, bytes.Length);     
    fs.Close();
}

在你函数的最后,它完美地创建了文件,可以毫无问题地读取它......所以我不知道问题出在哪里。

UPD 2

奇怪的事情发生了。

这是我使用的绑定:

<Image x:Name="imgSelectedAnim" Width="150" Height="150" Source="{Binding ElementName=lstAnims, Path=SelectedItem.Image}" Stretch="Uniform" />

(列表本身绑定在 observableCollection 上)。

当我通过应用手动创建动画时,它可以工作(显示图像)。

但是当我加载它时,它没有显示(我查看我的代码,没有任何“新”可以破坏我的绑定,因为还有其他属性以相同的方式绑定并且它们不会失败)。

此外,我在动画的属性 Image 的 getter/setter 上放置了一个断点。

当它被创建时,没有问题,它有很好的信息。

但是当它通过getter检索时,它第一次返回一个好的图像,然后是pixelWidth,pixelHeight,width,height只有1但不再通过setter的图像!

有什么想法吗?

UPD3

试过你说的这样:

在我的 viewModel 中添加了一个属性 TEST :

  private BitmapSource test;
        public BitmapSource TEST { get { return test; } set { test = value; RaisePropertyChanged("TEST"); } }

然后做到了:

img = getBmpSrcFromBytes(bin.ReadBytes(imageBytesLenght));
TEST = img;

(在之前显示和修改的代码中)

和我的绑定:

 <Image x:Name="imgSelectedAnim" Width="150" Height="150" Source="{Binding Path=TEST}" Stretch="Uniform" />

(datacontext 设置为我的 ViewModel)

它仍然无法正常工作并进行奇怪的图像修改(pixW、pixH、W 和 H 设置为 1)

最终更新:

看来我终于解决了这个问题。这就是我所做的:

byte[] bytes = bin.ReadBytes(imageBytesLenght);
MemoryStream mem = new MemoryStream(bytes);

img = new BitmapImage();
img.BeginInit();
img.StreamSource = mem;
img.EndInit();

奇怪的是它第一次没有工作,可能是由于我的 spriteanimation 类中的架构修改,但我不认为是。

非常感谢 Eugene Cheverda 的帮助

【问题讨论】:

    标签: wpf image serialization binary


    【解决方案1】:

    首先,我认为您应该将图像存储在BitmapSource 的列表中,并提供图像的反向编码以将stream 用作BitmapImage.StreamSource

    FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            BinaryReader bin = new BinaryReader(fs);
    
            int animCount = bin.ReadInt16();
            int imageBytesLenght;
            byte[] imageBytes;
            List<BitmapSource> bitmaps = new List<BitmapSource>();
    
            for (int i = 0; i < animCount; i++)
            {
                imageBytesLenght = bin.ReadInt32();
                imageBytes = bin.ReadBytes(imageBytesLenght);
                bitmaps.Add(getBmpSrcFromBytes(imageBytes));
            }
    
            bin.Close();
    

    UPD 在上面的代码中使用下面写的 func:

    private BitmapSource getBmpSrcFromBytes(byte[] bytes)
            {
                using (var srcStream = new MemoryStream(bytes))
                {
                    var dec = new PngBitmapDecoder(srcStream, BitmapCreateOptions.PreservePixelFormat,
                                                                 BitmapCacheOption.Default);
    
                    var encoder = new PngBitmapEncoder();
                    encoder.Frames.Add(dec.Frames[0]);
                    BitmapImage bitmapImage = null;
                    bool isCreated;
                    try
                    {
                        using (var ms = new MemoryStream())
                        {
                            encoder.Save(ms);
                            bitmapImage = new BitmapImage();
                            bitmapImage.BeginInit();
                            bitmapImage.StreamSource = ms;
                            bitmapImage.EndInit();
                            isCreated = true;
                        }
                    }
                    catch
                    {
                        isCreated = false;
                    }
                    return isCreated ? bitmapImage : null;
                }
            }
    

    希望这会有所帮助。

    UPD #2

    您的绑定不正确。您可能应该将所选项目绑定到例如CurrentImageSource。然后这个CurrentImageSource 绑定到Image 控件。

    代码:

    public class MyViewModel : INotifyPropertyChanged
        {
            public ObservableCollection<BitmapSource> ImagesCollection { get; set; }
            private BitmapSource _currentImage;
    
            public BitmapSource CurrentImage
            {
                get { return _currentImage; }
                set
                {
                    _currentImage = value;
                    raiseOnPropertyChanged("CurrentImage");
                }
            }
    
            private void raiseOnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }        
    
            public event PropertyChangedEventHandler PropertyChanged;
        }
    

    然后:

    <ListBox ItemsSource="{Binding ImagesCollection}" SelectedItem="{Binding CurrentImage}"/>
    <Image Source="{Binding CurrentImage}"/>
    

    添加

    Here is the sample project in which implemented technique as I described above. 它创建动画集合并在列表框中表示它们,选定的动画使用其 Image 属性显示在 Image 控件中。

    我想说的是,如果不能获得应有的图像,则需要寻找序列化/反序列化中的问题。

    【讨论】:

    • 它在 enc.save(stream) 处崩溃
    • 这会返回一个图像,但我无法显示它:s
    • 将其分配给Image 控件的Source 属性。如果Source 绑定到某个东西,则将获得的图像分配给该属性并调用PropertyChangedINotifyPropertyChanged
    • 问题是“SelectedItem”然后采用我的对象的类型,SpriteAnimation,它有一个属性“Image”。我的图像没有存储在特定的数组中,因为我只有一个 ObservableCollection,并且我通过那里访问 Image(和其他属性)
    • 查看更新,我已经为您创建了示例解决方案。它只是创建动画集合并在窗口中表示它。使用相同的绑定,它应该可以工作。如果不是在序列化/反序列化中搜索错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    相关资源
    最近更新 更多