我有一些我正在加载到WPF应用程序中的ListBox中的图像。最初我使用GDI调整图像大小(原件占用的内存太多)。这很好,除了他们每张图片大约需要400毫秒。不太好。因此,在寻找另一种解决方案时,我发现了一种使用TransformedBitmap(继承自BitmapSource)的方法。那很好,我想,我可以用它。除了我现在在某处发生内存泄漏......
我正在使用BackgroundWorker异步加载图像:
BitmapSource bs = ImageUtils.ResizeBitmapSource(ImageUtils.GetImageSource(photo.FullName));
//BitmapSource bs = ImageUtils.GetImageSource(photo.FullName);
bs.Freeze();
this.dispatcher.Invoke(new Action(() => { photo.Source = bs; }));
GetImageSource只从路径中获取Bitmap,然后转换为BitmapSource。
以下是ResizeBitmapSource的代码段:
const int thumbnailSize = 200;
int width;
int height;
if (bs.Width > bs.Height)
{
width = thumbnailSize;
height = (int)(bs.Height * thumbnailSize / bs.Width);
}
else
{
height = thumbnailSize;
width = (int)(bs.Width * thumbnailSize / bs.Height);
}
BitmapSource tbBitmap = new TransformedBitmap(bs,
new ScaleTransform(width / bs.Width,
height / bs.Height, 0, 0));
return tbBitmap;
该代码本质上来自以下代码: http://rongchaua.net/blog/c-wpf-fast-image-resize/
任何可能导致泄漏的想法?
编辑: 这是GetImageSource的代码,按要求
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
using (var bmp = Image.FromStream(stream, false, false))
{
// Use WPF to resize
var bitmapSource = ConvertBitmapToBitmapSource(bmp);
bitmapSource = ResizeBitmapSource(bitmapSource);
return bitmapSource;
}
}
答案 0 :(得分:4)
我认为您误解了TransformedBitmap的工作原理。它保留对源位图的引用,并将其转换为内存。也许你可以将转换后的位图编码成一个内存流,然后立即将其读出来。我不确定这会有多快,但你不会坚持使用全尺寸的位图。
我发现这个blog post返回了一个带有TransformedBitmap作为源的WriteableBitmap。 WriteableBitmap会将像素数据复制到初始化程序中的内存缓冲区,因此它实际上不会保留对TransformedBitmap或全尺寸图像的引用。
答案 1 :(得分:1)
猜测,从查看代码开始,您可能需要处理调用ImageUtils.GetImageSource(photo.FullName)返回的位图。
我还在博客上指出,作者已经添加了一个关于插入using语句以防止内存泄漏的更新(3月11日)。