【问题标题】:Create thumbnail image directly from header-less image byte array直接从无标题图像字节数组创建缩略图图像
【发布时间】:2013-08-12 14:24:08
【问题描述】:

我的应用程序一次显示大量图像缩略图。目前,我将所有全尺寸图像保存在内存中,并简单地在 UI 中缩放图像以创建缩略图。但是,我宁愿只在内存中保留小缩略图,并仅在必要时加载全尺寸图像。

我认为这很容易,但与仅在 UI 中缩放全尺寸图像相比,我生成的缩略图非常模糊。

图像是没有标题信息的字节数组。我提前知道大小和格式,所以我可以使用 BitmapSource.Create 创建一个 ImageSource。

 //This image source, when bound to the UI and scaled down creates a nice looking thumbnail
 var imageSource = BitmapSource.Create(
     imageWidth,
     imageHeight,
     dpiXDirection,
     dpiYDirection,
     format,
     palette,
     byteArray,
     stride);

using (var ms = new MemoryStream())
{
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(imageSource);
    encoder.Save(ms);

    var bi = new BitmapImage();
    bi.BeginInit();
    bi.CacheOption = BitmapCacheOption.OnLoad;

    //I can't just create a MemoryStream from the original byte array because there is no header info and it doesn't know how to decode the image!
    bi.StreamSource = ms;
    bi.DecodePixelWidth = 60;
    bi.EndInit();

    //This thumbnail is blurry!!!
    Thumbnail = bi;
}

我猜它是模糊的,因为我首先将它转换为 png,但是当我使用 BmpBitmapEncoder 时,我得到了“没有可用的成像组件”错误。在这种情况下,我的图像是 Gray8,但我不确定为什么 PngEncoder 可以识别它,而 BmpEncoder 却不能。

肯定有某种方法可以从原始 ImageSource 创建缩略图,而不必先将其编码为位图格式?我希望 BitmapSource.Create 让您像 BitmapImage 类一样指定解码宽度/高度。

编辑

最终的答案是使用带有 WriteableBitmap 的 TransformBitmap 来创建缩略图并消除原始的全尺寸图像。

var imageSource = BitmapSource.Create(...raw bytes and stuff...);
var width = 100d;
var scale = width / imageSource.PixelWidth;
WriteableBitmap writable = new WriteableBitmap(new TransformedBitmap(imageSource, new ScaleTransform(scale, scale)));
writable.Freeze();

Thumbnail = writable;

【问题讨论】:

  • 为什么你认为“我将它转换为 png 后它变得模糊”? PNG 是一种无损格式,因此没有理由认为它会产生比 BMP 更模糊的结果。我怀疑你试图解决这个问题的错误部分。尝试将 PNG 保存到磁盘,然后用 Paint 之类的工具打开它以查看它的外观。如果结果看起来没问题,那么问题很可能出在您使用缩略图的方式上。

标签: wpf bitmapimage imagesource


【解决方案1】:

您应该能够从原来的 TransformedBitmap 创建一个:

var bitmap = BitmapSource.Create(...);
var width = 60d;
var scale = width / bitmap.PixelWidth;
var transform = new ScaleTransform(scale, scale);
var thumbnail = new TransformedBitmap(bitmap, transform);

为了最终摆脱原始位图,您可以从 TransformedBitmap 创建一个 WriteableBitmap:

var thumbnail = new WriteableBitmap(new TransformedBitmap(bitmap, transform));

【讨论】:

  • 啊,是的,这确实更好。但是,使用此类时的内存占用是多少?我假设原始 BitmapSource 仍然通过 TransformedBitmap 实例被引用并在内存中?
  • 由于 TransformedBitmap 实现了 ISupportInitialize,我假设它会在初始化完成后立即删除对原始位图的引用。试一试。
  • 关键似乎是使用WriteableBitmap来消除对原始全尺寸图像的引用。
猜你喜欢
  • 1970-01-01
  • 2011-10-12
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多