Roman
Roman

Reputation: 137

How to assign StreamSource to BitmapImage in codebehind?

I have zip file in whick I store FlowDocument (Card.xaml) and folder with images (Media). Images in my FlowDocument have Tag, in which stores their path relative to FlowDocument. For image searching in FlowDocument (FindImages method): Finding all images in a FlowDocument

How I open this zip in RichTextBox. Please pay attention on how I create this images (bitmap), maybe problem there, but i can't understand what's wrong:

string nameOfXamlCardDefault = "Card.xaml";
    private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        OpenFileDialog dlg = new OpenFileDialog();
        if (dlg.ShowDialog() == true)
        {
            //Open zip file
            using (FileStream fullCardZipFile = File.Open(dlg.FileName, FileMode.Open, FileAccess.ReadWrite))
            {
                //Open zip by ZipArchive
                using (ZipArchive archive = new ZipArchive(fullCardZipFile, ZipArchiveMode.Update))
                {
                    //Get entry for xaml (FlowDocument)
                    ZipArchiveEntry xamlFileEntry = archive.GetEntry(nameOfXamlCardDefault);
                    //Open xaml
                    using (Stream xamlFileStreamInZip = xamlFileEntry.Open())
                    {
                        //Load FlowDocument into rtbEditor.Document
                        rtbEditor.Document = XamlReader.Load(xamlFileStreamInZip) as FlowDocument;
                        //Searching images
                        List<Image> images = FindImages(rtbEditor.Document).ToList();
                        foreach (var image in images)
                        {
                            var imageFileEntry = archive.GetEntry(image.Tag.ToString());
                            var bitmap = new BitmapImage();
                            using (Stream imageFileStream = imageFileEntry.Open())
                            {
                                var memoryStream = new MemoryStream();
                                imageFileStream.CopyTo(memoryStream);
                                bitmap.BeginInit();
                                bitmap.CacheOption = BitmapCacheOption.OnLoad;
                                bitmap.StreamSource = memoryStream;
                                bitmap.EndInit();
                                image.Source = bitmap;
                            }
                        }
                    }
                }
            }
        }
        return;
    }

All images in RichTextBox displays well, but there is no StreamSource in BitmapImage. And it will lead to error later:

<FlowDocument xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" NumberSubstitution.CultureSource="User" AllowDrop="True" PagePadding="5,0,5,0">
<Paragraph>
    <Image Tag="Media/image0.png">
        <Image.Source>
            <BitmapImage CacheOption="OnLoad" BaseUri="{x:Null}"/>
        </Image.Source>
    </Image>
    <Image Tag="Media/image1.png">
        <Image.Source>
            <BitmapImage CacheOption="OnLoad" BaseUri="{x:Null}"/>
        </Image.Source>
    </Image>
</Paragraph>

If just copy image and paste in RichTextBox, then it looks like this and this is good:

<Image Height="400" Width="600">
<Image.Source>
    <BitmapImage CacheOption="OnLoad" UriSource="./Image1.bmp" 
        BaseUri="pack://payload:,,wpf1,/Xaml/Document.xaml"/>
</Image.Source>

Is it possible to embed images from zip like copy them and paste? I tried to use Clipboard and worked with MemoryStream. But it didn't help.

Upvotes: 0

Views: 889

Answers (1)

Clemens
Clemens

Reputation: 128013

You should rewind the MemoryStream after copying the bitmap data, by setting its Position property or calling its Seek() method.

var imageFileEntry = archive.GetEntry(image.Tag.ToString());

if (imageFileEntry != null)
{
    using (var imageFileStream = imageFileEntry.Open())
    using (var memoryStream = new MemoryStream())
    {
        imageFileStream.CopyTo(memoryStream);
        memoryStream.Position = 0; // here

        var bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = memoryStream;
        bitmap.EndInit();

        image.Source = bitmap;
    }
}

Instead of a BitmapImage, you could also decode a BitmapFrame from the stream.

var imageFileEntry = archive.GetEntry(image.Tag.ToString());

if (imageFileEntry != null)
{
    using (var imageFileStream = imageFileEntry.Open())
    using (var memoryStream = new MemoryStream())
    {
        imageFileStream.CopyTo(memoryStream);
        memoryStream.Position = 0;

        image.Source = BitmapFrame.Create(
            memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    }
}

Upvotes: 1

Related Questions