1

I have a window:

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="150" Height="100"
        MouseLeftButtonDown="OnClick">
    <StackPanel Orientation="Horizontal">
        <Image Source="{Binding Image1}" />
        <Image Source="{Binding Image2}" />
    </StackPanel>
</Window>

codebehind:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new
        {
            Image1 = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAKhJREFUWIXtltEJgzAURU+l7Qg6S+kiHaOLdBL9EgKlEzhTUrA/fkgM+Ah5FeUdCAmSvHvUEAKGsaQBHOCBsVALU81GIuAKBsfNxWGnhIAHLhLTDAJwXRMYlcKTmZVy2CrnzHUvYIie3YHnvwQGoCtRa7e/oJ2NUxtZzOZfwARMwARMIPcknPOY+lvOYrsPpAS+inlBIvBRFHhLJmlcyz3QA3WxVzEOww83D06TNQuS8AAAAABJRU5ErkJggg=="),
            Image2 = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAPFJREFUWIXtlksKwjAURY9iBQcORLArcOAanLsChQ7dggtwU0JBBKduxIF7aAt1YJy0iUnz8UcuPGhKbt55r2kIREW1lQI5UAC1pyjFmqkJQO4xcTPyZrKeBKAAEhNSC5XAUAdQB0ouzdkPnEyrgYVno1hnBWyRd7WTdBvplfaOfmeAyTsAZLG2LeAnNyHADbgAlRhf/eA8pGvhERgpvAsDvzPAXOEbA+euADYn4dOzBHbiORHjqcarytkCMKkgM5j7/X+ByydQqZP/4x2wOQcynwDxPiADqCTvfKk0ATgFBDiaTApxLS+AAzDzVkrU3+gOjt+/W2ggWToAAAAASUVORK5CYII="),
        };
    }

    private void OnClick(object sender, MouseButtonEventArgs e)
    {
        using (var xps = new XpsDocument(@"1.xps", FileAccess.Write))
            XpsDocument.CreateXpsDocumentWriter(xps).Write((Visual)this.Content);
    }
}

As you can see, it displays two images and writes itself to an XPS file on mouse click.

This is what I see on the screen:

This is what I get in the XPS:

So the first image is displayed instead of the second one. In fact, if I have multiple images, all of them are replaced with the first one in the resulting XPS.

However, if instead of byte[] I set image's source to a file URL, then XPS correctly displays all the images.

What is going on?

torvin
  • 6,515
  • 1
  • 37
  • 52

1 Answers1

4

Investigation shows, that when Image.Source is assigned to a byte array, ImageSourceConverter class is used by WPF to convert the array to the proper ImageSource. BitmapFrame.Create() is called inside to perform the actual bitmap loading. So this code have absolutely the same effect:

var view = new StackPanel
{
    Orientation = Orientation.Horizontal,
    Children =
    {
        new Image { Source = BitmapFrame.Create(new MemoryStream(pic1Bytes), BitmapCreateOptions.None, BitmapCacheOption.Default) },
        new Image { Source = BitmapFrame.Create(new MemoryStream(pic2Bytes), BitmapCreateOptions.None, BitmapCacheOption.Default) },
    }
};
using (var xps = new XpsDocument(@"1.xps", FileAccess.Write))
    XpsDocument.CreateXpsDocumentWriter(xps).Write(view);

However, if I load image using BitmapImage class, the problem no longer exists. This code works both on screen and in XPS:

private static BitmapSource ImageFromBytes(byte[] bytes)
{
    var bmp = new BitmapImage();
    using (var stream = new MemoryStream(bytes))
    {
        bmp.BeginInit();
        bmp.CacheOption = BitmapCacheOption.OnLoad;
        bmp.StreamSource = stream;
        bmp.EndInit();
    }
    return bmp;
}

// usage example:
new Image { Source = ImageFromBytes(picBytes) }

This is probably a bug in ImageSourceConverter. One could create a custom converter using ImageFromBytes inside to continue using XAML binding.

torvin
  • 6,515
  • 1
  • 37
  • 52
  • This can't be a bug in ImageSourceConverter. I can successfully bind two Image controls to two different `byte[]` image properties in a view model (without any explicit conversion). Something else must be going on in your application. – Clemens Nov 24 '15 at 09:35
  • It's not "my application". The minimal code from the question reproduces the bug, try it yourself. – torvin Nov 24 '15 at 19:58
  • I did that already, with two Image controls bound to two view model properties of type `byte[]`. This setup uses implicit conversion provided by the ImageSourceConverter class. No error though... – Clemens Nov 24 '15 at 20:06
  • What error are you talking about? The main question is - what do you see in the XPS. If your XPS is displayed correctly - then post the working code as your answer. If it is not - my point stands. – torvin Nov 24 '15 at 22:00
  • I'm talking about your "probably a bug in ImageSourceConverter" assumption. There's no such bug. – Clemens Nov 24 '15 at 22:02
  • 1
    If it doesn't work in XPS with `ImageSourceConverter` and does work without it - it is a natural assumption. I assume initialising `BitmapFrame` like that is not entirely correct, but documentation on this topic is not very helpful... – torvin Nov 24 '15 at 22:20
  • I have same issue. Simple fix was to call again BitmapFrame.Create( on existing BitmapFrame, but this actually creates new image (but worked). Thank you for your fix, seems to work and maintain original file in XPS file result. – Ales Ruzicka Feb 18 '21 at 08:59