WPF加载序列化图像

时间:2010-09-16 08:14:01

标签: wpf image serialization binary

在应用程序中,我需要通过二进制文件来序列化图像,并将其放入其他应用程序中以显示它。

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

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

我已经这样做了:更新我的绑定,甚至试图通过窗口代码behing直接影响它。这些方法都不起作用: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上设置了一个断点。

创建时没有任何问题,它有良好的信息。

但是当它通过吸气剂后退时,它会在第一次返回一个好的图像,然后和pixelWidth,pixelHeight,宽度,高度只有1的图像,但不再通过设置器了!

有什么想法吗?

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的帮助

1 个答案:

答案 0 :(得分:0)

首先,我认为您应该将图片存储在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 在上面的代码中使用下面的函数:

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}"/>

<强> ADDED

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

我想说的是,如果您无法获得应有的图像,则需要在序列化/反序列化中搜索问题。