web-dev-qa-db-ja.com

System.Drawing.Image.FromFile()のメモリ不足例外

サムネイルを作成する画像アップローダーとクロッパーを使用していますが、次の行でメモリ不足の例外が発生することがあります。

Dim bm As Bitmap = System.Drawing.Image.FromFile(imageFile)

エラーの発生はごくわずかであり、非常にまれですが、私は常に何が原因であるかを知りたいです。 imageFile変数は、画像のパスへの単なるServer.MapPathです。

誰かが以前にこの問題を経験したことがあるのか​​、そして何がそれを引き起こしているのか考えているのか興味がありました。それはおそらく画像のサイズですか?

必要に応じてコードと私が持っているサポート情報を投稿できますが、これに関する人々の意見を聞きたいです。

41
dooburt

OutOfMemoryExceptionが常に実際にであるとは限らないことを知っておく価値があります-特にファイルを扱う場合はそうではありません。何らかの理由でハンドルが足りなくなった場合にも起こると思います。

ビットマップを使い終わったら、すべてのビットマップを破棄していますか?これは単一の画像で繰り返し発生しますか?

40
Jon Skeet

これが悪いイメージファイルではなく、実際にファイルハンドルを開いたままにする_Image.FromFile_の通常の問題である場合、解決策は代わりに_Image.FromStream_を使用することです。

_using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
   using (Image original = Image.FromStream(fs))
   {
      ...
_

明示的なDispose()using()ステートメントを使用するか、ビットマップでnullに値を設定しても、_Image.FromFile_の問題は解決しません。

そのため、アプリをしばらく実行して多くのファイルを開く場合は、代わりにImage.FromStream()を使用することを検討してください。

33
Ian Mercer

画像でいっぱいのフォルダにサムネイル画像を作成しているときに、今日同じ問題にぶつかりました。 「メモリ不足」は毎回まったく同じ時点で発生したことがわかります。変換する画像のあるフォルダーを見ると、問題を引き起こしているファイルはthumbs.dbであることがわかりました。画像ファイルのみが変換され、問題が解決されるようにコードを追加しました。

私のコードは基本的に

For Each imageFile as FileInfo in fileList
If imageFile.Extension = ".jpg" Or imageFile.Extension = ".gif" Then
    ...proceed with the conversion
End If
Next

お役に立てれば。

7

また、読み取りモードで開くことができます(同時に2か所で使用する場合)

 public Image OpenImage(string previewFile)
        {
            FileStream fs = new FileStream(previewFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            return Image.FromStream(fs);
        }
3
Avram

また、同じファイルを別の場所で開いていないかどうかも確認してください。どうやら、ファイルを2回開くと(File.Open()であっても)OutOfMemoryExceptionもスローされます...

2
pinus.acer

TIFFをPDFに変換するために作成したユーティリティでも同じ問題が発生しました。多くの場合、「メモリ不足」エラーが同じ行に表示されます。

System.Drawing.Image.FromFile(imageFile)

次に、ファイル拡張子が「.tiff」のときにのみエラーが発生することを発見し、「。tif」の拡張子で名前を変更した後は正常に動作しました

1
Jeff Chapin

今日、画像のサイズを変更してからトリミングしようとしたときに、同様の問題が発生しました。このコードを使用して画像のサイズを変更しました。

private static Image resizeImage(Image imgToResize, Size size)
{
   int sourceWidth = imgToResize.Width;
   int sourceHeight = imgToResize.Height;

   float nPercent = 0;
   float nPercentW = 0;
   float nPercentH = 0;

   nPercentW = ((float)size.Width / (float)sourceWidth);
   nPercentH = ((float)size.Height / (float)sourceHeight);

   if (nPercentH < nPercentW)
      nPercent = nPercentH;
   else
      nPercent = nPercentW;

   int destWidth = (int)(sourceWidth * nPercent);
   int destHeight = (int)(sourceHeight * nPercent);

   Bitmap b = new Bitmap(destWidth, destHeight);
   Graphics g = Graphics.FromImage((Image)b);
   g.InterpolationMode = InterpolationMode.HighQualityBicubic;

   g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
   g.Dispose();

   return (Image)b;
}

そして、収穫のためのこのコード...

private static Image cropImage(Image img, Rectangle cropArea)
{
   Bitmap bmpImage = new Bitmap(img);
   Bitmap bmpCrop = bmpImage.Clone(cropArea,
   bmpImage.PixelFormat);
   return (Image)(bmpCrop);
}

次に、これは私が上記のコードを呼び出す方法です...

Image img = Image.FromFile(@"C:\Users\****\Pictures\image.jpg");
img = ImageHandler.ResizeImage(img, new Size(400, 300));
img = ImageHandler.CropImage(img, new Rectangle(0, 25, 400, 250));
long quality = 90;

トリミング部分でエラーが発生し続け、リサイザーは正常に機能しました!

結局のところ、リサイザーの内部で起こっていたことは、クロップ機能でエラーを投げていました。サイズ変更された計算により、画像の実際の寸法は、渡された400ではなく399のようになりました。

したがって、トリミングの引数として400を渡したとき、幅400ピクセルのbmpで399ピクセルの幅の画像をトリミングしようとしていたため、メモリ不足エラーがスローされました。

上記のコードのほとんどは http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing で見つかりました

1
jcreamer898

画像がアイコンの場合、次の機能のように、異なる読み込み処理が必要です。

public static Image loadImage(string imagePath)
    {
        Image loadedImage = null;
        if (!File.Exists(imagePath)) return loadedImage;
        try
        {
            FileInfo fileInfo = new FileInfo(imagePath);
            if (fileInfo.Extension.Equals(".jpg") || fileInfo.Extension.Equals(".jpeg") ||
               fileInfo.Extension.Equals(".bmp") || fileInfo.Extension.Equals(".png") ||
               fileInfo.Extension.Equals(".gif"))
            {
                loadedImage = Image.FromFile(imagePath);
            }
            else if (fileInfo.Extension.Equals(".ico"))
            {
                Bitmap aBitmap = Bitmap.FromHicon(new
                                           Icon(imagePath, new Size(200, 200)).Handle);
                loadedImage = ImageFuncs.ResizeImage(aBitmap, new Size(30, 30));
            }
        }
        catch (Exception eLocal)
        {
            MessageBox.Show(imagePath + " loading error: " + eLocal.Message);
        }
        return loadedImage;
    }
1
IrinaL

私は同じ問題を抱えていましたが、他のコードを探す前に、任意の画像ビューアーで画像を開くことができるかどうかを確認し、1KBサイズの.PNGファイルであるにもかかわらず画像が破損/破損していることを確認しました。同じ場所に新しいイメージを追加し、それはうまくいきました。

0
Kiran Modini

IISからサービスを提供している場合は、アプリケーションプールをリサイクルしてみてください。これにより、同様の画像アップロードの「メモリ不足」エラーが解決されました。

0
Rich

これは、画像ファイルが破損している場合に発生します。メモリはそれとは何の関係もないので、それは悪いエラーメッセージです。コーディングはうまくいきませんでしたが、try/catch/finallyはプログラムの異常終了を防ぎます。

0
David Grund

Tiffファイルのバッチ処理で同じ問題が発生しています。ほとんどのファイルは例外をスローしていませんが、ASP.NET 4.0では「メモリ不足」例外をスローしているファイルはほとんどありません。バイナリデータを使用して、同じファイル内からいくつかのファイルだけの理由を見つけました。他のファイルは作業ファイルであるため、ASP.NET ASPNETまたはNETWORK SERVICEアカウントの権限の問題になることはありません。

ITextSharp.text.Imageクラスを開いたところ、GetInstance()にはオーバーロードされたメソッドが多数あることがわかりました。次のコードを使用して問題を解決しました。注:catchブロックは問題のあるファイルに対して実行されます。

                iTextSharp.text.Image image = null;
            try
                {
                    var imgStream = GetImageStream(path);
                     image = iTextSharp.text.Image.GetInstance(imgStream);
                }
                catch {
                    iTextSharp.text.pdf.RandomAccessFileOrArray ra = null;
                    ra = new iTextSharp.text.pdf.RandomAccessFileOrArray(path);
                    image = iTextSharp.text.pdf.codec.TiffImage.GetTiffImage(ra, 1);

                    if (ra != null)
                        ra.Close();

                }
0
Nilesh Hirpara