我刚写了一个函数,它接受一个目录,创建一个新的“resizedDirectory”(如果它不存在),调整每个.bmp的大小,并将其保存到“resizedDirectory”。这是我第一次写这样的函数(用于某些部分的互联网),这里是代码:
protected void directorySelected(object sender, EventArgs e) {
// Make sure the directory exists
if (Directory.Exists(inputDirectory.Text)) {
string[] filePaths = Directory.GetFiles(inputDirectory.Text);
// Determine if there are any files in inputDirectory
if (filePaths.Length == 0) messageLog.InnerHtml = "<strong>No files found in:</strong> "+inputDirectory.Text;
else {
// Determine if "resizedDirectory" exists, create it if it does not exist
string resizedDirectory = inputDirectory.Text+"\\"+"resizedDirectory";
if (!Directory.Exists(resizedDirectory)) {
Directory.CreateDirectory(resizedDirectory);
messageLog.InnerHtml = "<strong>Created:</strong> "+resizedDirectory+"<br/><br/>";
}
// For each file in inputDirectory...
for (var i = 0; i < filePaths.Length; i++) {
string[] extensionSplit = filePaths[i].Split('.');
// Make sure filePath[i] ends with the appropriate extension
if (extensionSplit.Length == 2 && extensionSplit[1].Equals("bmp")) {
Bitmap currImage = new Bitmap(filePaths[i]);
messageLog.InnerHtml += "<strong>"+i.ToString()+":</strong> "+filePaths[i]+"<br/><div class='indent'>";
// Calculate new dimensions
int newWidth = maxWidth;
int newHeight = maxHeight;
if (currImage.Width > currImage.Height) newHeight = (int)(((float)maxWidth)/((float)currImage.Width)*currImage.Height);
else newWidth = (int)(((float)maxHeight)/((float)currImage.Height)*currImage.Width);
messageLog.InnerHtml += "<strong>Old dimensions:</strong> ("+currImage.Width+","+currImage.Height+")<br/><strong>New dimensions:</strong> ("+newWidth+", "+newHeight+")<br/>";
// Settings before saving
Bitmap targetImage = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(targetImage)) {
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawImage(currImage, 0, 0, newWidth, newHeight);
}
ImageCodecInfo ici = this.GetEncoderInfo(ImageFormat.Bmp);
Encoder eq = Encoder.Quality;
EncoderParameters eps = new EncoderParameters(1);
EncoderParameter ep = new EncoderParameter(eq, 100L); // 100L is the higest quality (goes from 0 - 100)
eps.Param[0] = ep;
// Save image
string targetPath = resizedDirectory+"\\foo"+i.ToString()+".bmp";
targetImage.Save(targetPath, ici, eps);
messageLog.InnerHtml += "<strong>Saved:</strong> "+targetPath+"</div><br/>";
}
else messageLog.InnerHtml += "<strong>IGNORED "+i.ToString()+":</strong> "+filePaths[i]+"<br/>";
}
}
}
else if (inputDirectory.Text.Equals("")) messageLog.InnerHtml = "<strong>No directory specified</strong>";
else messageLog.InnerHtml = "<strong>Cannot find:</strong> "+inputDirectory.Text;
}
protected ImageCodecInfo GetEncoderInfo(ImageFormat format) {
return ImageCodecInfo.GetImageDecoders().SingleOrDefault(c => c.FormatID == format.Guid);
}
这很好用小.bmps。问题是我需要转换的.bmps目录很大,例如.bmp是16073 x 13231(或608MB)。我尝试使用一些.bmp和一个巨大的.bmps代码,然后创建了“resizedDirectory”,在那里创建了一个新的重新调整大小的.bmp,然后崩溃了“Out of memory”消息。
我应该如何调整庞大的.bmps?
编辑:它在一个巨大的.bmp上失败(但不是小的)
答案 0 :(得分:1)
首先,使用单个位图测试您的代码。虽然它们很大,但您可能会发现您的程序仍然可以一次处理它们,在这种情况下,您不需要做太多工作就能完成它。 (如果它不适用于单个海量图像,那么您将需要开始寻找与内置.net类不同的图像加载或处理库)
如果它适用于一个图像但不适用于它们的序列,那么在尝试加载下一个图像之前,请确保释放一个位图使用的所有内存。基本上你需要在对位图进行所有处理之后(在循环结束内)调用currImage.Dispose();
来释放它正在使用的内存。
但是,实现此目的的正确方法是将处理代码写入using
块中,该块将自动为您调用Dispose(即使抛出异常):
using (Bitmap currImage = new Bitmap(filePaths[i]))
{
// Process the bitmap here
}
你需要为targetImage做一个类似的事情,以确保它在写完之后也会被处理掉。
一旦完成处理,它将释放位图使用的所有内存,以便下一个位图可供使用。
答案 1 :(得分:0)
必须处理所有GDI +资源。我认为问题是你的USING语句没有处理Graphics对象。我自己做了很多次的错误:)
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.dispose.aspx
g.Dispose();