【问题标题】:Is it possible to persist the original data used to build a BitmapImage without reencoding?是否可以在不重新编码的情况下保留用于构建 BitmapImage 的原始数据?
【发布时间】:2021-02-12 14:47:08
【问题描述】:

稍微详细说明一下标题,我们有一些代码可以从磁盘加载图像文件,然后将其转换为BitmapImage 以显示在屏幕上。然后我们需要将该数据作为字节数组保存到不同的存储机制中,以便以后可以按原样重新加载。

据我了解,问题在于,要将 BitmapImage 转换回字节数组,您必须使用编码器,但如果您使用编码器,则每次保存时都会重新编码图像,除非如果您使用无损格式,则可能会降低图像质量,但使用无损格式意味着您可能会将存储空间翻倍,而不是 jpeg 数据。

我的想法是创建一个 'holder' 类型来保存原始的原始数据(同样,例如来自 jpg 文件),并使用它按需创建 BitmapImage,缓存它以供将来检索。

这是我目前所拥有的“持有人”类型。 (注意隐式转换器,所以我可以在任何接受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 属性),另一次是已实现/扩展的 @ 987654331@ 财产。唯一的好处是后者只有在访问时才会“实现”,而压缩的前者是持久化的。

我还是觉得有点“恶心”。有没有办法在不保存图像数据两次的情况下做到这一点?

【问题讨论】:

  • 我完全不懂这个问题。如果您想将位图“保留”在其原始形式中,为什么不在第一次加载位图时复制原始数据?您要在这里解决的实际问题是什么?你的问题写满了XY Problem。 :( Stack Overflow 无法有效地回答唯一陈述的问题是“icky”的问题。
  • 你需要那个属性吗?你能用返回MakeBitmapImage()结果的方法来代替它吗?
  • bitmapImage.StreamSource 属性怎么样?它有吸气剂,我希望它存储您传递给它的原始内存流,然后您可以访问并取回您的字节数组(可能首先需要将位置重置为 0,因为 BitmapImage 已读取它)
  • 如果确实需要属性,则不需要支持字段。
  • @PeterDuniho,这正是我上面的解决方案所做的......它保留了原始图像数据,专门为存储而预解压缩。

标签: c# arrays wpf bitmapimage encoder


【解决方案1】:

你可以避免在这里处理MemoryStream(处理MemoryStream虽然好的做法并没有做任何有趣的事情,没有资源可以处理):

using var ms = new MemoryStream(bytes);

然后可以稍后通过访问bitmapImage.StreamSource 访问相同的内存流。请注意,返回的流Position 可能不是 0,因为BitmapImage 可能已经读取了它,所以如果需要,不要忘记将位置重置为 0。通常调用MemoryStream.GetBuffer() 是个坏主意(首选ToArray()),但在这种特殊情况下,避免不必要的复制可能是合适的。

【讨论】:

  • 完美!谢谢!仍然可能有理由保留我的 PersistentBitmapImage 类以用于延迟加载方面,但对于更简单的实现,这将非常有用!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-07
  • 2020-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多