0

我刚刚编写了一个函数,它接受一个目录,创建一个新的“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 和一个巨大的 .bmp 尝试了代码,它生成了“resizedDirectory”,在那里创建了一个新的调整大小的 .bmp,然后崩溃并显示“内存不足”消息。

我应该如何调整巨大的 .bmps 的大小?

编辑:它在一个巨大的 .bmp 上失败(但不是在小的)

4

2 回答 2

1

首先,使用单个位图测试您的代码。尽管它们很大,但您可能会发现您的程序仍然可以一次处理一个,在这种情况下,您不需要做太多事情就可以让它工作。(如果它不适用于单个海量图像,那么您将需要开始寻找与内置 .net 类不同的图像加载或处理库)

如果它适用于一个图像但不适用于它们的序列,则确保在尝试加载下一个位图之前释放一个位图使用的所有内存。本质上,您需要currImage.Dispose();在对位图进行所有处理后(在循环末尾)调用以释放它正在使用的内存。

然而,实现这一点的正确方法是在一个using块内编写处理代码,它会自动为您调用 Dispose(即使抛出异常):

using (Bitmap currImage = new Bitmap(filePaths[i]))
{
    // Process the bitmap here
}

您需要为 targetImage 做类似的事情,以确保它在写入后也被释放。

这将在您完成处理后立即释放位图使用的所有内存,以便下一个要使用的位图可用。

于 2013-08-05T23:11:41.743 回答
0

必须释放所有 GDI + 资源。我认为问题在于您的 USING 语句没有处理 Graphics 对象。这是我自己犯过很多次的错误:)

http://msdn.microsoft.com/en-us/library/system.drawing.graphics.dispose.aspx

g.Dispose();
于 2013-08-05T23:12:50.107 回答