Elaborating on the title a little bit more, we have some code that loads an image file from disk, then converts it into a BitmapImage
for display on screen. We then need to persist that data to a different storage mechanism as a byte array so it can be reloaded as-is later.
The issue is from what I understand, to convert a BitmapImage
back into a byte array, you have to use an encoder, but if you use an encoder, you're re-encoding the image on every save so unless you use a lossless format, you could be downgrading the quality of your image, but to not use a lossless format means you're potentially doubling storage space over something like jpeg data.
My thought is to create a 'holder' type that holds the original, raw data (again, say from a jpg file) and use it to create a BitmapImage
on-demand, caching it for future retrieval.
Here's what I have so far for the 'holder' type. (Note the implicit converter so I can use it wherever a BitmapImage
is accepted):
#nullable enable
class PersistableBitmapImage{
public PersistableBitmapImage(byte[] bytes)
=> _bytes = bytes;
private byte[] _bytes;
public byte[] Bytes {
get => _bytes;
set{
_bytes = value;
_bitmapImage = null;
}
}
private BitmapImage? _bitmapImage;
public BitmapImage BitmapImage
=> _bitmapImage ?? (_bitmapImage = Bytes.MakeBitmapImage());
#region Implicit Operators
public static implicit operator BitmapImage(PersistableBitmapImage persistableBitmapImage)
=> persistableBitmapImage.BitmapImage;
#endregion Implicit Operators
}
Here's the helper extension to create the BitmapImage
:
public static class ByteArrayExtensions {
public static BitmapImage MakeBitmapImage(this byte[] bytes){
using var ms = new MemoryStream(bytes);
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = ms;
bitmapImage.EndInit();
return bitmapImage;
}
}
The issue I have with this design is in cases where that BitmapImage
is accessed, I'm now holding the image data twice, once in compressed format (the Data
property) and another in the realized/expanded BitmapImage
property. The only up-side is the latter is only 'realized' if accessed and the compressed former is what's persisted.
Still feels a little 'icky' to me. Is there a way to do this without holding the image data twice?