嘿得到这个错误:
发生了'System.OutOfMemoryException'类型的异常 System.Drawing.dll但未在用户代码中处理
其他信息:内存不足。
它出现在DrawImage
调用
/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <returns>The resized image.</returns>
public Bitmap ResizeImage(Image image, System.Drawing.Size newSize)
{
var destRect = new Rectangle(0, 0, newSize.Width, newSize.Height);
var destImage = new Bitmap(newSize.Width, newSize.Height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
我不确定它为什么会发生,我多次调用此方法,结果转换为Base64字符串并存储在ObservableCollection中。
/// <summary>
/// Convert Image and Resize
/// </summary>
/// <param name="loc"></param>
/// <returns></returns>
public async Task<string> GenerateThumbnailBinary(string loc)
{
return await Task<string>.Factory.StartNew(() =>
{
Image image = Image.FromFile(loc, true);
// Figure out the ratio
double ratioX = (double)Properties.Settings.Default.ThumbnailWidth.Width / (double)image.Width;
double ratioY = (double)Properties.Settings.Default.ThumbnailWidth.Height / (double)image.Height;
// use whichever multiplier is smaller
double ratio = ratioX < ratioY ? ratioX : ratioY;
System.Drawing.Size newSize =
new System.Drawing.Size(
(int)(image.Width * ratio),
(int)(image.Height * ratio));
Image resized = ResizeImage(image, newSize);
return ImageToBase64(resized, ImageFormat.Jpeg);
});
}
我还通过绑定到Collection并使用转换器将Base64字符串转换回Bitmap,将每个字符串显示为图像,这只是UI显示已转换的内容。
我的问题将从哪里开始?当我在UI上显示太多图像并使用转换器将字符串转换为图像时,我是否可以尝试在内存中存储太多图像?
下面图片中的高点显然是在运行方法循环时,但它似乎仍然保持高于最后运行方法之前,这有帮助吗?
编辑: 这是启动任务并运行方法的循环。
// Generate List of images to upload
var files = Directory.EnumerateFiles(sel.Name, "*.*", SearchOption.AllDirectories)
.Where(s => s.EndsWith(".jpeg") ||
s.EndsWith(".jpg") ||
s.EndsWith(".png") ||
s.EndsWith(".JPG"));
int b = 1;
if (files.Count() > 0)
{
/// <summary>
/// Resize Images
/// </summary>
/// Set current Task first
UploadTask = Steps[0].Message;
try
{
foreach (string item in files)
{
// Generate new name
string oldname = Path.GetFileNameWithoutExtension(item);
string newName = Common.Security.KeyGenerator.GetUniqueKey(32);
string t = await GenerateThumbnailBinary(item);
ImageUploadObjects.Add(
new ImageUploadObject { OldName = oldname,
NewName = newName,
ByteImage = t });
UploadProgress = (int)Math.Round((double)(100 * b / files.Count()));
b++;
}
// Complete
Steps[0].Complete = true;
}
catch(Exception e)
{
Steps[0].Error = e.InnerException.ToString();
}
/// <summary>
/// Move full resoluation images
/// </summary>
/// Set current Task first
UploadTask = Steps[1].Message;
try
{
foreach (string item in files)
{
}
// Complete
Steps[1].Complete = true;
}
catch (Exception e)
{
Steps[1].Error = e.InnerException.ToString();
}
}
}
编辑:
如何判断内存是否仍在使用?我在下面添加了另一张图片,第一张快照是在我执行方法之前,最后一张是在它完成时,2 - 4是在它运行时
答案 0 :(得分:1)
我认为解决问题的最简单方法是以块/批次的方式完成。例如,如果您有100个文件,则创建100个任务,这些任务将文件内容加载到内存中。也许做10(或其他一些数字),一旦完成,做下一个10(或其他一些数字)。我相信这会解决你的问题。
还要确保在任何实现Disposable的类上调用Dispose,即Image和Bitmap等。
除了上述内容之外,这里简要介绍了您要做的事情: 1.读取目录并获取所有文件。 2.为每个文件创建缩略图图像。 3.将缩略图添加到内存中的集合。 4.将图像传输到另一个位置。
对于上面的第2项,我不会将所有缩略图保留在内存中。即使我需要在UI中显示它,我将合并分页并根据需要拉它们。
答案 1 :(得分:0)
Image resized = ResizeImage(image, newSize)
未被处理。因为分配的内存在终结器线程运行之前不会被释放,所以你可能会在整个地方泄漏内存。
Image image = Image.FromFile(loc, true);
...
Image resized = ResizeImage(image, newSize);
image.Dispose();
string base64Image = ImageToBase64(resized, ImageFormat.Jpeg);
resized.Dispose();
return base64Image;