我必须从大图像的特定部分制作一些缩略图,并将它们保存为png / jpeg图像。这就是我正在做的事情:
public static void Save(BitmapImage srcBitmap, Int32Rect srcRegion, Rect destRegion)
{
var cropped = new CroppedBitmap(srcBitmap, srcRegion);
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawImage(cropped, destRegion);
}
var bmp = new RenderTargetBitmap(256, 256, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
var bitmapEncoder = new PngBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(bmp));
using (var filestream = new FileStream(path, FileMode.Create))
{
bitmapEncoder.Save(filestream);
}
}
我可以使用具有不同Bitmap
的单个大srcRegion
来调用此方法一千次,应用程序越来越多地使用RAM并最终抛出System.OutOfMemoryException
!似乎这个功能有内存泄漏,但我不知道它在哪里。有人可以帮忙吗?
编辑:我也不确定这是获取大图像的一部分并将该部分调整为较小的图像(例如256 * 256)并保存它的最佳方法。有没有更好的主意?
答案 0 :(得分:1)
RenderTargetBitmap
不是IDisposable
,但应该是(因为它使用原生资源),这是一个奇怪的设计实现,但事实就是如此。您可以尝试在退出之前调用bmp.Clear()
,这应该会释放本机资源。
RenderTargetBitmap
自己检查GC压力(使用SafeMILHandle)来释放非托管资源,但根据我的经验,效果不是很好(这是很久以前的事了,这些天的事情可能会更新)
此外,不是为了生产代码,而是为了测试目的,我添加了一个:
GC.Collect();
GC.WaitForPendingFinalizers();
在你的方法之上(或者在调用它之后,从调用者那里),只是为了确保问题不是托管资源,而GC没有内存压力来释放它们(你可能有更多的内存可用)系统比你可以持有本机句柄,这将使它全部混淆。)
答案 1 :(得分:0)
好的,我使用TransformedBitmap
改进了这段代码(实际上我从@Clemens中得到了这个想法)并且不再抛出任何异常。
public static void Save(BitmapImage srcBitmap, Int32Rect srcRegion, Rect destRegion)
{
var cropped = new CroppedBitmap(srcBitmap, srcRegion);
var drawingVisual = new DrawingVisual();
//Here is the changes:
var scale = 256.0 / srcRegion.Width;
var transform = new ScaleTransform(scale, scale);
//
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
//Here is the changes:
drawingContext.DrawImage(new TransformedBitmap(cropped, transform), destRegion);
//
}
var bmp = new RenderTargetBitmap(256, 256, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
var bitmapEncoder = new PngBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(bmp));
using (var filestream = new FileStream(path, FileMode.Create))
{
bitmapEncoder.Save(filestream);
}
}