Reputation: 1719
I have some problems while trying to serialize an object containing a BitmapSource field.
In fact, at the beginning, I had an ImageSource but it seems not to be serializable. So I tried to use the associated property to store a string and to convert & convert back the image to/from the string.but no image is displayed now :-(
here is the XAML image tag:
<Image
x:Name="bookCover"
Grid.Row="0"
Grid.RowSpan="1"
Grid.Column="0"
MaxWidth="200"
MaxHeight="320"
Margin="5"
Source="{Binding Image}" SizeChanged="bookCover_SizeChanged" >
</Image>
here is the Image property & field in the model class:
public string _image;
public BitmapSource Image
{
get => Base64ToImage(_image);
set
{
_image =ImageToBase64(value);
OnPropertyChanged("Image");
}
}
and their associated methods:
public static string ImageToBase64(BitmapSource bitmap)
{
var encoder = new JpegBitmapEncoder();
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = new MemoryStream())
{
encoder.Save(stream);
return Convert.ToBase64String(stream.ToArray());
}
}
public static BitmapSource Base64ToImage(string base64)
{
byte[] bytes = Convert.FromBase64String(base64);
using (var stream = new MemoryStream(bytes))
{
return BitmapFrame.Create(stream);
}
}
and here my program retrieves an image from internet via its URI and stores it:
var myUri=new Uri(book0.LargeImage.URL);
bookToInsert.Image = new BitmapImage(myUri);
thank you.
Upvotes: 0
Views: 565
Reputation: 128136
When you create a BitmapSource from a stream that is closed immediately after creation, you have to set BitmapCacheOption.OnLoad
. Otherwise the stream would have to be kept open until the BitmapSource is actually used, e.g. displayed in an Image element.
public static BitmapSource Base64ToImage(string base64)
{
using (var stream = new MemoryStream(Convert.FromBase64String(base64)))
{
return BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
A couple of notes:
byte[] Image
.Try a much simpler view model like this:
public class ViewModel : INotifyPropertyChanged
{
private byte[] image;
public byte[] Image
{
get => image;
set
{
image = value;
OnPropertyChanged(nameof(Image));
}
}
}
and set the Image property like this:
var webClient = new WebClient();
viewModel.Image = webClient.DownloadData(book0.LargeImage.URL);
Or asynchronously:
var httpClient = new HttpClient();
viewModel.Image = await httpClient.GetByteArrayAsync(book0.LargeImage.URL);
Upvotes: 1