web-dev-qa-db-ja.com

GDI +、JPEG画像からMemoryStreamで一般的なエラーが発生しました

これはウェブ全体でちょっと悪名高い間違いのようです。私のシナリオに合わないので、私は自分の問題に対する答えを見つけることができなかったので、あまりにも多くの。画像をストリームに保存すると例外がスローされます。

奇妙なことにこれは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: 

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

  1. イメージを複製してそれに取り組んでいます。
  2. そのMIMEのエンコーダーを取得してjpeg品質設定でそれを渡します。
302
madcapnmckay

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;
 }

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

this に似たサイズ変更コードを使用した後、宛先ファイルの未知のMIMEタイプ(img.RawFormat.Guid)とIdがあるため、ストリームからのみ戻ります。そうでなければ一般的な処理コードを書くのが難しくなるので、Mimeタイプがすべての画像オブジェクトに対して正しくなるように。

編集

これは私の最初の検索では出てこなかったが、 これが Jon Skeetからの答えだ

171
madcapnmckay

あなたがそのエラーを受けているならば、私はあなたのアプリケーションがあるディレクトリに対する書き込み許可を持っていないと言うことができます。

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

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

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

それが誰かに役立つことを願っています。

120
Savindra

私はそれがある将来のインターネット旅行者を助けることを期待して同様にエラーのこの原因を加えます。 :)

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

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

あなたはtestでこれを自分で確かめることができます:

  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がスローされないのは残念です。

50
Fred

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

要するに、ストリームから構築されたImageの寿命の間、ストリームは破棄されてはいけません。

だから、の代わりに

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

これを試して

Stream imageStream;
...

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

フォームcloseまたはWebページcloseでcloseimageStream

37
Ivan Mesic

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

ファイルパスが利用可能でパーミッションが正しいことを100%確信が持てない場合は、テキストファイルにaを書いてみてください。これはほんの数秒で非常に簡単な修正になるでしょう。

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

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

そして、あなたのファイルを片付けるのを忘れないでください。

28
Kirk Broadhurst

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

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

万が一誰かが私のようにばかげたことをしているのであれば。 1.パスが存在することを確認してください。 2.書き込み権限があることを確認してください。あなたのパスが正しいことを確認してください、私の場合私はTargetPathにファイル名がありませんでした:(

「GDI +で一般的なエラーが発生しました」より、あなたのパスは吸うことができるはずです

13
ahsant

私はまた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;
}
13
Aximili

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

言い換えれば、私が「C:¥Documents and Settings¥myusername¥Local Settings¥Temp¥ABC DEF M1 Trended Values¥Images¥picture.png」に保存しようとすると、一般的な例外がスローされます。

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

13
Igilima

これは、「GDIは画像の高さを65534に制限する」と述べたFredの回答の拡張/限定です。私たちは.NETアプリケーションの1つでこの問題に遭遇しました、そしてポストを見て、私たちのアウトソーシングチームは空中で彼らの手を上げて、彼らは大きな変化なしで問題を解決できないと言いました。

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

    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を使用することができます。

これは私にとって10万の高さ/幅に達する - 私は限界をテストしなかった。それが起こるように。Tiffは私達にとって実行可能なオプションでした。

警告されます

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

11
vipes

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

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ブロックから戻ってきたためと考えられます。

10
dhinesh

非常によく似た問題を抱えていて、うまくいかないイメージを複製してみました。最善の解決策は、メモリストリームからロードされたイメージから新しいBitmapオブジェクトを作成することです。そのようにして、流れを処分することができる。

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

お役に立てれば。

9
HU.

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

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")
5
vivek shaushi

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

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

5
Marco

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

だから最初にあなたが保存しようとしているあなたのフォルダを確認してください。その特定のフォルダに対するすべての(読み取りおよび書き込み)権限が必要です。

4
Jaimin

私の場合、問題は保存していたパス(ルートC:\)にありました。これをD:\111\に変更すると、例外は解消されました。

4
Ani

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

フルパスではなくファイル名を渡したため、このエラーが発生しただけです。

それは起こります!

4
MytyMyky

私の番!

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

Using()はファイルを開いたままにしているので上書きできません。多分これは将来の誰かを助けるでしょう。

4
Andy

もう一つの可能​​な解決策を山に投げるために、私は私がこのエラーメッセージで遭遇したケースについて言及するつもりです。私が変換して表示していたビットマップを保存するとき、メソッドBitmap.Saveはこの例外を投げます。ステートメントにブレークポイントがある場合でも例外がスローされないこと、またBitmap.Saveの前にThread.Sleep(500)がある場合でも例外がスローされないことがわかったため、何らかのリソースの競合が発生していると思います。

この例外が表示されないようにするには、単にイメージを新しいBitmapオブジェクトにコピーするだけで十分です。

new Bitmap(oldbitmap).Save(filename);
2
Segfault

私はあなたの "jpeg"のケースが実際にあることに気づきます:

            default:
                format = ImageFormat.Jpeg;
                break;

フォーマットはjpegで、他のものではないと確信していますか?

私がしようと思います:

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

あるいはimageToConvert.MimeType()が実際に何を返しているのか確認してください。

UPDATE

MemoryStreamオブジェクトに必要なその他の初期化はありますか?

2
ChrisF
  • この問題はテストサーバーではありましたが、ライブサーバーではありませんでした。
  • 私は画像をストリームに書き込んでいたので、許可の問題ではありませんでした。
  • 私はいくつかの.dllをテストサーバーに直接デプロイしていました。
  • ソリューション全体をデプロイすることで問題が解決したので、おそらくコンパイル時の奇妙なミスマッチでした
2
Chris Halcrow

私は以前に保存した画像と同じ名前で画像を保存しようとしているので私もこのエラーが出ます。

重複した名前で画像を保存しないでください。

例えば「乱数」関数( C#の乱数生成器はどのように動作しますか? )またはGuidを生成する( http://betterexplained.com/)記事/ the-quick-guide-to-guids /

1
Bruno Ferreira
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
jeka

画像を遠隔地に保存しようとしている場合は、NETWORK_SERVICEユーザーアカウントをセキュリティ設定に追加し、そのユーザーに読み取りおよび書き込み権限を付与してください。さもなければそれは働かないでしょう。

1
JAH

本番サーバーでPDFを生成する際にも、同じ問題が発生しました。

アプリケーションプールをリサイクルすることで問題を解決できます。

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

1
tech-gayan

コンソールアプリにも同じエラーメッセージが表示されました。「GDI +で一般的なエラーが発生しました。」次のコードを参照して、newImage.Save行でエラーが発生しました。

for (int i = 1; i <= 1000; i++)
{
   Image newImage = Image.FromFile(@"Sample.tif");
   //...some logic here
   newImage.Save(i + ".tif", , ImageFormat.Tiff);
}

RAMの使用量が約4GBの場合、プログラムはエラーを返し、プロジェクトプロパティでProgram Targetx64に変更することで解決しました。

0
Soon Khai

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

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

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

image_instance = Image.FromFile(file_name);

の代わりに

image_instance.Load(file_name);

image_instanceはSystem.Windows.Forms.PictureBox型です。 PictureBoxのLoad()は、画像のロード元のストリームを破棄しますが、そのことは知りませんでした。

0
Klaus

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

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

私はこれが助けになることを願っています、これは私の問題の修正でした、私は単に出力イメージを保存する前に出力ディレクトリが存在することを確認しました!

0
Ihab Hajj

@savindraからの回答に基づき、あなたのアプリケーションでRHMを実行し、管理者として実行してみます。 それからそれはあなたの問題を解決するはずです。

私の許可問題だったようです。

0
AltF4_

私にとってはImage.Save(Stream, ImageCodecInfo, EncoderParameters)を使っていましたが、どうやらこれは悪名高いA generic error occurred in GDI+エラーを引き起こしていました。

私はEncoderParameterを使ってJPEGを100%の品質で保存しようとしていました。これは「私のマシン」(doh!)で完全に機能していましたが、本番では機能していませんでした。

代わりにImage.Save(Stream, ImageFormat)を使ったとき、エラーは消えました!だから私はばかのように私は後者を使用し続けたがそれは私がたったの50%であると思うデフォルトの品質でそれらを救うが。

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

0

このエラーのもう1つの原因は、私の問題を解決するもので、アプリケーションが特定のディレクトリに対する書き込み権限を持たないことです。

savindraの答えを完成させるために: https://stackoverflow.com/a/7426516/6444829

IIS_IUSERSへのファイルアクセスを許可する方法は次のとおりです。

ASP.NETアプリケーションへのアクセスを提供するには、IIs_IUSERSへのアクセスを許可する必要があります。

特定のファイルまたはフォルダーへの読み取り、書き込み、および変更のアクセス許可を付与するには

  1. Windowsエクスプローラーで、必要なファイルを見つけて選択します。

  2. ファイルを右クリックし、[プロパティ]をクリックします。

  3. [プロパティ]ダイアログボックスで、[セキュリティ]タブをクリックします。

  4. [セキュリティ]タブで、ユーザーのリストを調べます。 (アプリケーションがネットワークサービスとして実行されている場合は、リストにネットワークサービスアカウントを追加し、許可を与えます。

  5. [プロパティ]ダイアログボックスで[IIs_IUSERS]をクリックし、[ネットワークサービスのアクセス許可]セクションで、読み取り、書き込み、および変更のアクセス許可を選択します。

  6. [適用]をクリックし、[OK]をクリックします。

これは、Windows Server 2016のIISおよびローカルIIS windows 10で機能しました。

0
Khalil Liraqui