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?
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.