GDI +、JPEGイメージからMemoryStreamへの一般的なエラーが発生しました


326

これはウェブ全体で少し悪名高いエラーのようです。私のシナリオが合わないので、問題の答えを見つけることができませんでした。画像をストリームに保存すると、例外がスローされます。

奇妙なことに、これはpngで完全に機能しますが、jpgとgifで上記のエラーが発生し、かなり混乱します。

そこにある最も類似した問題は、許可なしに画像をファイルに保存することに関連しています。皮肉なことに、解決策は私がやっているようにメモリストリームを使用することです...

public static byte[] ConvertImageToByteArray(Image imageToConvert)
{
    using (var ms = new MemoryStream())
    {
        ImageFormat format;
        switch (imageToConvert.MimeType())
        {
            case "image/png":
                format = ImageFormat.Png;
                break;
            case "image/gif":
                format = ImageFormat.Gif;
                break;
            default:
                format = ImageFormat.Jpeg;
                break;
        }

        imageToConvert.Save(ms, format);
        return ms.ToArray();
    }
}

例外の詳細。これが非常に多くの問題を引き起こす理由は、説明の欠如です:(

System.Runtime.InteropServices.ExternalException was unhandled by user code
Message="A generic error occurred in GDI+."
Source="System.Drawing"
ErrorCode=-2147467259
StackTrace:
   at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters    encoderParams)
   at System.Drawing.Image.Save(Stream stream, ImageFormat format)
   at Caldoo.Infrastructure.PhotoEditor.ConvertImageToByteArray(Image imageToConvert) in C:\Users\Ian\SVN\Caldoo\Caldoo.Coordinator\PhotoEditor.cs:line 139
   at Caldoo.Web.Controllers.PictureController.Croppable() in C:\Users\Ian\SVN\Caldoo\Caldoo.Web\Controllers\PictureController.cs:line 132
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
 InnerException: 

これまでに試したことはありますか。

  1. イメージのクローンを作成し、それに取り組んでいます。
  2. jpeg品質設定でそれを渡すそのMIMEのエンコーダーを取得します。



3
私にとっての問題は、フォルダが存在しないことでした。フォルダを作成するだけで修正されました。
hazjack 2017

私にとっては、範囲外の指標が飲み込まれることでした。
ビリージェイクオコナー

回答:


189

OK私はただの運で原因を見つけたようで、その特定のメソッドでは何も問題はありません。それは、コールスタックをさらにバックアップすることです。

以前に画像のサイズを変更し、そのメソッドの一部として、サイズ変更したオブジェクトを次のように返します。上記のメソッドへの2つの呼び出しと、ファイルへの直接保存を挿入しました。

// At this point the new bitmap has no MimeType
// Need to output to memory stream
using (var m = new MemoryStream())
{
       dst.Save(m, format);

       var img = Image.FromStream(m);

       //TEST
       img.Save("C:\\test.jpg");
       var bytes = PhotoEditor.ConvertImageToByteArray(img);


       return img;
 }

オブジェクトが作成されたメモリストリームは、オブジェクトの保存時に開いている必要があるようです。これがなぜかはわかりません。誰でも私を啓発することができ、どうすればこれを回避できるでしょうか?

これと同様のサイズ変更コードを使用した後、宛先ファイルには不明なMIMEタイプ(img.RawFormat.Guid)があり、汎用的な書き込みが困難になるため、すべての画像オブジェクトでMIMEタイプが正しいので、ストリームからのみ戻ります。それ以外の場合はコードを処理します。

編集

これが私の最初の検索で来ませんでしたが、ここにあるジョンスキートからの答えは


4
メモリストリームからビットマップを取得するときに、ストリームを閉じないでください。とても参考になりました。ありがとう
mcdon

38
ありがとうございました。これはおそらく私の髪の最後を保存しました。
NotMe

6
ありがとう!これにより多くの時間を節約できましたが、1つですが、回答の最初にエラーの原因を強調していただけますか。 DO NOT CLOSE THE MEMORY STREAMの目的で使用するTHEイメージを予定がある場合AGAIN」素晴らしいことだ; D
DORD

6
「dst」変数は何ですか?
WEFX

1
@madcapnmckayは、「dst」変数とは何か、およびその重要性を説明してください
Mike T

131

このエラーが発生する場合、アプリケーションに一部のディレクトリに対する書き込み権限がないと言えます。

たとえば、メモリストリームからファイルシステムに画像を保存しようとすると、そのエラーが発生する場合があります。

XPを使用している場合は、そのフォルダーにaspnetアカウントの書き込み権限を必ず追加してください。

Windowsサーバー(2003、2008)またはVistaを使用している場合は、ネットワークサービスアカウントの書き込み権限を追加してください。

それが誰かを助けることを願っています。


7
しなかった!私はいまいましい書き込み許可で2時間を無駄にしました...これを投稿するためにここに来ました。より多くの賛成票を獲得してください。:)
Gleno

2
これが私にとっての解決策でした。完全に+1!
Grandizer、2012

5
ビットマップを保存する前に、File.WriteAllText( "filename.jpg"、 "")を実行してから、File.DeleteFile( "filename.jpg")を実行できます。私のベンマークでは、これはたった.001秒で完了し、「filename.jpgをそこに保存する権限がありません」という素晴らしい結果が得られます
Despertar

@DespertarはFile.Delete()を意味しますが、これは非常に便利なトリックです。ビットマップを保存するときは必ずこれを使用します。
D Coetzee、2015

2
私の場合、ディレクトリは存在しませんでした。
silencedmessage

54

このエラーの原因も追加し、将来のインターネット旅行者の助けになることを期待しています。:)

GDI +は画像の最大の高さを65500に制限します

基本的な画像のサイズ変更を行いますが、サイズ変更ではアスペクト比を維持しようとします。この仕事がやや上手すぎるQA担当者がいます。彼はこれを480ピクセルの高さである1ピクセル幅の写真でテストすることにしました。画像が私たちの寸法に合わせてスケーリングされたとき、高さは68,000ピクセルの北であり、アプリはで爆発しましたA generic error occurred in GDI+

あなたはテストでこれを自分で確認できます:

  int width = 480;
  var height = UInt16.MaxValue - 36; //succeeds at 65499, 65500
  try
  {
    while(true)
    {
      var image = new Bitmap(width, height);
      using(MemoryStream ms = new MemoryStream())
      {
        //error will throw from here
        image.Save(ms, ImageFormat.Jpeg);
      }
      height += 1;
    }
  }
  catch(Exception ex)
  {
    //explodes at 65501 with "A generic error occurred in GDI+."
  }

ArgumentExceptionのコンストラクタでフレンドリーな.netがスローされないのは残念ですBitmap


17
ありがとう-このインターネットの時間旅行者は、このメッセージを残すあなたにかなり感謝しています。
トムウェスト

私のテストでは、65535が実際の最大値です。65536で、一般的なエラーが発生し始めます。
ChaseMedallion 2017年

もう一度試してみてください:Win10 .net 4.5と.net 4.6.1で、65501で爆発しました。コードにも構文エラーがあり、更新されます:)
Fred

37

この記事では、正確に何が起こるかを詳しく説明します:ビットマップとイメージコンストラクターの依存関係

つまり、ストリームImageから構築されたの存続期間中、ストリームを破棄してはなりません。

したがって、代わりに

using (var strm = new ... )  {
    myImage = Image.FromStream(strm);
}

これを試して

Stream imageStream;
...

    imageStream = new ...;
    myImage = Image.FromStream(strm);

フォームを閉じるか、Webページを閉じるときにimageStreamを閉じます。


うん、これは私を手に入れた。私は良心的で、自分のストリームをにラップし、using後でイメージをメモリストリームにコピーしようとして、恐ろしい「GDI +の一般エラー」メッセージを受け取りました。
Applebyが2017年

あなたのリンクは私に無限のリダイレクトを与えていました。これは機能します。保存に問題がありましたが、問題はありPixelFormat.Format32bppArgbませんでしたPixelFormat.Format1bppIndexed。リンクした記事はその理由を説明しています。GDI+は、すべてをメモリに保持するのではなく、ソースストリームからビットマップデータを再デコードすることを選択する場合があります。私の推測では、1bpp画像は再デコードされません。
ラブロイアー2017年

新しいリンクでさえ機能しなくなります。単純なGoogle検索では正しいページが表示されないようです。しかし、私はこの答えを見つけてとても嬉しかったです!この問題の
回避策

28

無効なパスに保存しようとした場合や、権限の問題がある場合にも、この例外が発生します。

ファイルパスが使用可能で、権限が正しいことを100%確信していない場合は、テキストファイルにを書き込んでみてください。非常に簡単な修正を除外するのに数秒しかかかりません。

var img = System.Drawing.Image.FromStream(incomingStream);

// img.Save(path);
System.IO.File.WriteAllText(path, "Testing valid path & permissions.");

そして、ファイルをクリーンアップすることを忘れないでください。


これは私にとっての問題でした...エラーが曖昧でなくてよかったのですが、多くの時間を節約できたでしょう。
Oofpez 2012

はい!保存先のフォルダが存在している必要があります。画像を保存しようとする前に、まずそれを確認します。(それでも、エラーは私に、年に1回程度発生します。)
Magnus Smith

私のパスはファイルではなくディレクトリでした。
Asen Kasimov

20

画像をビットマップ変数に保存

using (var ms = new MemoryStream())
{
    Bitmap bmp = new Bitmap(imageToConvert);
    bmp.Save(ms, format);
    return ms.ToArray();
}

これで私の問題は解決しました。画像をビットマップに保存すると例外が怖くなるのはなぜですか?
jmc 2015

私の日を保存しました。問題の原因はわかりませんが、ビットマップの保存は機能します。System.Drawing.Imageはメモリストリームに保存されませんが、ビットマップは保存されます!!!
サン・

これは私にとって最良の解決策でした。新しいビットマップを作成して変換します。
uzay95

17

誰かが私と同じくらい愚かなことをしている場合に備えて。1.パスが存在することを確認します。2.書き込み権限があることを確認してください。3.パスが正しいことを確認します。私の場合、TargetPathにファイル名がありませんでした:(

あなたのパスは「GDI +で一般的なエラーが発生しました」よりも悪い


16

JPEGの保存時にもこのエラーが発生しましたが、これは特定の画像についてのみです。

私の最後のコード:

  try
  {
    img.SaveJpeg(tmpFile, quality); // This is always successful for say image1.jpg, but always throws the GDI+ exception for image2.jpg
  }
  catch (Exception ex)
  {
    // Try HU's method: Convert it to a Bitmap first
    img = new Bitmap(img); 
    img.SaveJpeg(tmpFile, quality); // This is always successful
  }

画像を作成しなかったので、違いがわかりません。
どなたかご説明いただければ幸いです。

これは私の参考までに、SaveJpeg関数です。

private static void SaveJpeg(this Image img, string filename, int quality)
{
  EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)quality);
  ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
  EncoderParameters encoderParams = new EncoderParameters(1);
  encoderParams.Param[0] = qualityParam;
  img.Save(filename, jpegCodec, encoderParams);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
    var encoders = ImageCodecInfo.GetImageEncoders();
    var encoder = encoders.SingleOrDefault(c => string.Equals(c.MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase));
    if (encoder == null) throw new Exception($"Encoder not found for mime type {mimeType}");
    return encoder;
}

1
これは髪を引っ張る日々を解決しました。これは私がこれまで書いた中で最もwtfのコードです:)
Jeff Dunlop

13

ファイルを保存している親フォルダーの1つに末尾のスペースがある場合、GDI +が一般的な例外をスローすることがわかりました。

つまり、「C:\ Documents and Settings \ myusername \ Local Settings \ Temp \ ABC DEF M1 Trended Values \ Images \ picture.png」に保存しようとすると、一般的な例外がスローされました。

私のフォルダー名は、たまたま末尾にスペースがあるファイル名から生成されていたため、.Trim()を使用して先に進むのは簡単でした。


3
すごい-ディレクトリパスをよく見ようとは思わなかったでしょう
jharr100 2014年

11

あなたのコードが次のようであれば、このエラーも発生します

private Image GetImage(byte[] byteArray)
{
   using (var stream = new MemoryStream(byteArray))
   {
       return Image.FromStream(stream);
    }
}

正しいのは

private Image GetImage(byte[] byteArray)
{
   var stream = new MemoryStream(byteArray))
   return Image.FromStream(stream);        
}

これは、usingブロックから戻っているためかもしれません。


私にとっては、usingブロックに戻ることでした。私はまだusingを使用していますが、ブロックの外側の値を返します。ありがとう!
Dragouf 2010年

1
私が「難しい方法」を見つけた場合、その画像を新しいストリーム(たとえば、HttpContext.Response.OutputStreamなど)に再度保存する場合は、エラーが発生しない場合は、stream.Flush()も実行する必要があります。再び。
Lucian

11

これは、フレッドの応答の拡張/資格です:「GDIは画像の高さを65534に制限します」。私たちは.NETアプリケーションの1つでこの問題に遭遇し、この投稿を見て、私たちのアウトソーシングチームは手を上げて、大きな変更なしに問題を修正することはできないと述べました。

私のテストによると、それは65534よりも大きな高さで画像を操作/作成することは可能ですが、ストリームまたはファイルに保存するときに問題が発生しCERTAINフォーマットで。次のコードでは、t.Save()メソッド呼び出しは、ピクセルの高さが65501の場合、フレンドに一般的な例外をスローします。好奇心の理由で、幅のテストを繰り返しましたが、同じ制限が保存に適用されました。

    for (int i = 65498; i <= 100000; i++)
    {
        using (Bitmap t = new Bitmap(800, i))
        using (Graphics gBmp = Graphics.FromImage(t))
        {
            Color green = Color.FromArgb(0x40, 0, 0xff, 0);
            using (Brush greenBrush = new SolidBrush(green))
            {
                // draw a green rectangle to the bitmap in memory
                gBmp.FillRectangle(greenBrush, 0, 0, 799, i);
                if (File.Exists("c:\\temp\\i.jpg"))
                {
                    File.Delete("c:\\temp\\i.jpg");
                }
                t.Save("c:\\temp\\i.jpg", ImageFormat.Jpeg);
            }
        }
        GC.Collect();
    }

同じエラーは、メモリストリームに書き込む場合にも発生します。

これを回避するには、上記のコードを繰り返し、ImageFormat.JpegをImageFormat.TiffまたはImageFormat.Bmpに置き換えます。

これは、高さ/幅が100,000に達します-制限をテストしていません。たまたま.Tiffは私たちにとって実行可能なオプションでした。

警告する

メモリ内のTIFFストリーム/ファイルは、JPG形式のものより多くのメモリを消費します。


10

非常によく似た問題があり、機能しないイメージの複製も試​​みました。最善の解決策は、メモリストリームから読み込まれた画像から新しいBitmapオブジェクトを作成することであることがわかりました。そうすれば、ストリームを破棄できます。

using (var m = new MemoryStream())
{
    var img = new Bitmap(Image.FromStream(m));
    return img;
}

お役に立てれば。


6

権限が原因でエラーが発生しました。フォルダにすべての権限があることを確認してください。

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        return image;
    }

 img.Save("YOUR PATH TO SAVE IMAGE")

私はあなたに同意します。私はこの問題をPERMISSIONで解決しました
プラグアン

5

解決済み-私はこの正確な問題を抱えていました。私にとっての修正は、IISサーバーのIUSRのディスククォータを増やすことでした。この例では、アイテムの画像などを含むカタログアプリがあります。「匿名Webユーザー」のアップロードクォータは、この特定のホスティング会社のIISサーバーのデフォルトである100MBに設定されました。私はそれを400MBに増やし、エラーなく画像をアップロードすることができました。

これはあなたの問題ではないかもしれませんが、もしそうなら、それは簡単な修正です。


4

私の場合、問題は私が保存していたパス(ルートC:\)にありました。D:\111\例外をなくすように変更する。


4

このエラーのもう1つの原因-BitmapインスタンスのSaveメソッドで指定したパスが存在しないか、完全な/有効なパスが指定されていません。

フルパスではなくファイル名を渡していたため、このエラーが発生しました!

起こる!


4

私の番!

using (System.Drawing.Image img = Bitmap.FromFile(fileName))
{
      ... do some manipulation of img ...
      img.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}

.Save ...で取得しました。using()がファイルを開いたままにしているため、上書きできません。多分これは将来誰かを助けるでしょう。


4

私が直面していた同じ問題。しかし、私の場合、Cドライブにファイルを保存しようとしていて、アクセスできませんでした。そこで、完全にアクセス可能なDドライブに保存してみましたが、成功しました。

したがって、まず、保存しようとしているフォルダを確認してください。その特定のフォルダーに対するすべての(読み取りと書き込み)権限が必要です。


原因通常、cは管理者権限なしでは許可しません。
Aneeq Azam Khan

2

あなたの「jpeg」ケースは実際には次のとおりです。

            default:
                format = ImageFormat.Jpeg;
                break;

フォーマットがjpegであり、それ以外のものではないですか?

私は試してみます:

            case "image/jpg": // or "image/jpeg" !
                format = ImageFormat.Jpeg;
                break;

または、imageToConvert.MimeType()実際に戻ってくるものを確認します。

更新

MemoryStreamオブジェクトに対して行う必要がある他の初期化はありますか?


ありがとう。これは間違いなく正しい形式で呼び出されています。jpgをロードしてデバッグし、mimeがimage / jpegとして認識され、形式がJPGであることを確認します。
madcapnmckay 2009年

3
まあ-私は常に最初に明白なものを排除しようとします。私はそれをしなかった回数を数えることができず、後で私を噛むために戻ってきます。
ChrisF

2
  • この問題はテストサーバーで発生しましたが、ライブサーバーでは発生しませんでした。
  • 画像をストリームに書き込んでいたので、許可の問題ではありませんでした。
  • 一部の.dllをテストサーバーに直接展開していました。
  • ソリューション全体をデプロイすると問題が修正されたので、おそらく奇妙なコンパイルの不一致でした

2

考えられる別の解決策を山積みにするために、このエラーメッセージで遭遇したケースについて触れます。このメソッドBitmap.Saveは、変換して表示していたビットマップを保存すると、この例外をスローします。ステートメントにブレークポイントがある場合は例外がスローされずBitmap.Save、前にThread.Sleep(500)ので、何らかのリソースの競合が発生していると思います。

画像を新しいビットマップオブジェクトにコピーするだけで、この例外が表示されなくなりました。

new Bitmap(oldbitmap).Save(filename);

2

PDFプロダクションサーバーでImageProcessor libを使用してイメージを生成したり、サイズを変更したりする際に同様の問題がありました。

アプリケーションプールをリサイクルして問題を修正します。


1

画像をリモートの場所に保存する場合は、NETWORK_SERVICEユーザーアカウントをセキュリティ設定に追加し、そのユーザーに読み取りと書き込みのアクセス許可を付与してください。それ以外の場合は機能しません。


1
byte[] bts = (byte[])page1.EnhMetaFileBits; 
using (var ms = new MemoryStream(bts)) 
{ 
    var image = System.Drawing.Image.FromStream(ms); 
    System.Drawing.Image img = image.GetThumbnailImage(200, 260, null, IntPtr.Zero);      
    img.Save(NewPath, System.Drawing.Imaging.ImageFormat.Png);
}


1

単純ですが、ビットマップの新しいインスタンスを作成すると問題が解決します。

string imagePath = Path.Combine(Environment.CurrentDirectory, $"Bhatti{i}.png");
Bitmap bitmap = new Bitmap(image);
bitmap.Save(imagePath);

0

私にとって私はを使用していましたがImage.Save(Stream, ImageCodecInfo, EncoderParameters)、明らかにこれが悪名高いA generic error occurred in GDI+エラーの原因でした。

私はEncoderParameter、JPEGを100%の品質で保存するために使用しようとしていました。これは「マイマシン」(doh!)で完全に機能し、プロダクションでは機能しませんでした。

Image.Save(Stream, ImageFormat)代わりに使ったところ、エラーが消えました!馬鹿のように私は後者を使い続けましたが、私はそれをデフォルトの品質で保存しますが、それは私がちょうど50%だと思います。

この情報が誰かに役立つことを願っています。


0

私も問題に遭遇しました。問題は、ロードストリームが破棄されたことによるものでした。しかし、私はそれを処分しませんでした、それは.Netフレームワークの中にありました。私がしなければならなかったすべては使用でした:

image_instance = Image.FromFile(file_name);

の代わりに

image_instance.Load(file_name);

image_instanceは、System.Windows.Forms.PictureBoxタイプです。PictureBoxのLoad()は、画像の読み込み元のストリームを破棄しますが、それを知りませんでした。


0

@savindraからの回答に基づいて、アプリケーションでRHMを実行して管理者として実行すると、問題が解決するはずです。

鉱山は許可の問題のようです。


0

このようなエラーを引き起こす可能性のある問題は次のとおりです。

  1. ディレクトリが存在しません(呼び出しているメソッドは、このディレクトリを自動的に作成しません)
  2. 出力ディレクトリに書き込むためのセキュリティ権限は、アプリを実行しているユーザーが書き込むことを許可していません

これが役に立てば幸いです。これが私の問題の修正でした。出力イメージを保存する前に、出力ディレクトリが存在することを確認しました!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.