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 では問題なく機能しました。問題は、変換する必要がある .bmp のディレクトリが非常に大きいことです。.bmp の例は 16073 x 13231 (または 608MB) です。小さな .bmp と巨大な .bmp の 1 つを使用してコードを試してみたところ、「resizedDirectory」が作成され、そこに小さなサイズの新しい .bmp が作成され、「メモリ不足」というメッセージが表示されてクラッシュしました。

巨大な .bmps のサイズを変更するにはどうすればよいですか?

編集:1つの巨大な.bmpで失敗します(ただし、小さなものでは失敗しません)

4

2 に答える 2

1

まず、単一のビットマップでコードをテストします。サイズは大きいですが、プログラムで一度に 1 つずつ処理できる場合があります。(単一の大規模な画像で機能しない場合は、組み込みの .net クラスとは異なる画像の読み込みまたは処理ライブラリを探し始める必要があります)

1 つの画像では機能するが、一連の画像では機能しない場合は、次の画像をロードする前に、1 つのビットマップで使用されているすべてのメモリを解放してください。currImage.Dispose();基本的に、使用しているメモリを解放するには、ビットマップをすべて処理した後 (ループの最後で) を呼び出す必要があります。

usingただし、これを実現する適切な方法は、(例外がスローされた場合でも) Dispose を自動的に呼び出すブロック内に処理コードを記述することです。

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

targetImage が書き込まれた後に破棄されることを確認するために、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 に答える