是否可以在不重新编码的情况下保留用于构建 BitmapImage 的原始数据?
Is it possible to persist the original data used to build a BitmapImage without reencoding?
再详细说明一下标题,我们有一些代码可以从磁盘加载图像文件,然后将其转换为 BitmapImage
以在屏幕上显示。然后我们需要将该数据作为字节数组保存到不同的存储机制,以便稍后可以重新加载它。as-is。
问题是据我了解,要将 BitmapImage
转换回字节数组,您必须使用编码器,但如果使用编码器,则 re-encoding每次保存时都会保存图像,因此除非您使用无损格式,否则您可能会降低图像质量,但是不使用无损格式意味着您可能会加倍存储space 在诸如 jpeg 数据之类的东西上。
我的想法是创建一个 'holder' 类型来保存原始的原始数据(同样,从 jpg 文件中说)并用它来创建一个 BitmapImage
on-demand,缓存它以供将来检索。
这是我目前对 'holder' 类型的了解。 (注意隐式转换器,所以我可以在接受 BitmapImage
的任何地方使用它):
#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
}
这是创建 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;
}
}
我在这个设计中遇到的问题是在访问 BitmapImage
的情况下,我现在将图像数据保存两次,一次是压缩格式(Data
属性) 和 realized/expanded BitmapImage
属性 中的另一个。唯一的 up-side 是后者只有 'realized' 如果访问并且压缩的前者是持久的。
对我来说还是有点'icky'的感觉。有没有办法不用两次保存图像数据就可以做到这一点?
您可以避免在此处处理 MemoryStream
(处理 MemoryStream
虽然好的做法无论如何都不会做任何有趣的事情,但没有可处理的资源):
using var ms = new MemoryStream(bytes);
然后可以通过访问 bitmapImage.StreamSource
访问相同的内存流。请注意,返回的流 Position
可能不是 0,因为 BitmapImage
可能已经读取了它,所以不要忘记在必要时将位置重置为 0。通常调用 MemoryStream.GetBuffer()
是个坏主意(首选 ToArray()
),但在这种特殊情况下,避免不必要的复制可能是合适的。
再详细说明一下标题,我们有一些代码可以从磁盘加载图像文件,然后将其转换为 BitmapImage
以在屏幕上显示。然后我们需要将该数据作为字节数组保存到不同的存储机制,以便稍后可以重新加载它。as-is。
问题是据我了解,要将 BitmapImage
转换回字节数组,您必须使用编码器,但如果使用编码器,则 re-encoding每次保存时都会保存图像,因此除非您使用无损格式,否则您可能会降低图像质量,但是不使用无损格式意味着您可能会加倍存储space 在诸如 jpeg 数据之类的东西上。
我的想法是创建一个 'holder' 类型来保存原始的原始数据(同样,从 jpg 文件中说)并用它来创建一个 BitmapImage
on-demand,缓存它以供将来检索。
这是我目前对 'holder' 类型的了解。 (注意隐式转换器,所以我可以在接受 BitmapImage
的任何地方使用它):
#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
}
这是创建 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;
}
}
我在这个设计中遇到的问题是在访问 BitmapImage
的情况下,我现在将图像数据保存两次,一次是压缩格式(Data
属性) 和 realized/expanded BitmapImage
属性 中的另一个。唯一的 up-side 是后者只有 'realized' 如果访问并且压缩的前者是持久的。
对我来说还是有点'icky'的感觉。有没有办法不用两次保存图像数据就可以做到这一点?
您可以避免在此处处理 MemoryStream
(处理 MemoryStream
虽然好的做法无论如何都不会做任何有趣的事情,但没有可处理的资源):
using var ms = new MemoryStream(bytes);
然后可以通过访问 bitmapImage.StreamSource
访问相同的内存流。请注意,返回的流 Position
可能不是 0,因为 BitmapImage
可能已经读取了它,所以不要忘记在必要时将位置重置为 0。通常调用 MemoryStream.GetBuffer()
是个坏主意(首选 ToArray()
),但在这种特殊情况下,避免不必要的复制可能是合适的。