3

Windows フォーム アプリケーションで、MemoryStream に保存するときに Bitmap.Save が失敗するという問題があります。この問題は (今のところ) 1 台のマシンで断続的に発生するだけのようで、悪い知らせは顧客のサイトにあります。マシン上でデバッグすることはできませんが、問題を 1 行のコードに絞り込むスタック トレースを取得しました。

これが私のコードの要約版です:

byte[] ConvertPixelsToBytes()
{
    // imagine a picture class that creates a 24 bbp image, and has
    // a method to get an unmanaged pixel buffer.
    // imagine it also has methods for getting the width,
    // height, pitch 

    // I suppose this line could return a bad address, but 
    // I would have expected that the Bitmap constructor would have 
    // failed if it was
    System.IntPtr pPixels = picture.GetPixelData();

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
            picture.width(),
            picture.height(),
            picture.pitch(),
            System.Drawing.Imaging.PixelFormat.Format24bppRgb,
            pPixels );

    // This line doesn't actually free the memory, but it could be freed in a 
    // background thread
    // (2)
    picture.releasePixelData(pPixels);

    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
    try
    {
        // I don't see how this line could fail, but it does
        // (3)
        bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
        return memStream.ToArray();
    }
   catch(System.Runtime.InteropServices.ExternalException e)
   {
       // e.Message is the very helpful " A generic error occurred in GDI+."
   }
   finally
   {
       memStream.Dispose();
   }
   return new byte[0];
}

何が起こっているのでしょうか?私のピクセル バッファは正しいと確信しています。開発/テスト マシンや他の顧客サイトでは常に機能します。

考えられる失敗の理由についての私の考えは、

a. ビットマップ コンストラクターはピクセル データをコピーしませんが、その参照を保持します。メモリが解放されるため、Save は失敗します。この点について MSDN ドキュメントは明確ではありませんが、Bitmap はピクセル データがロックされていると仮定するのではなく、ピクセル データをコピーすると仮定します。

b. ピクセル データが無効なため、Save メソッドが失敗します。私のピクセルデータはピクセルあたり24ビットであるため、これは疑わしいので、私が知る限り、それは無効であってはなりません。

c. .NET フレームワークに問題があります。

他の考えられる失敗の理由について考えていただければ幸いです。アプリに追加のチェックとログ情報を追加して、フィールドに何かを送信できるようにします。

4

2 に答える 2

5

その Bitmap コンストラクターの MSDN ドキュメントには、疑いの余地はありません。

備考 呼び出し元は、scan0 パラメータで指定されたメモリ ブロックの割り当てと解放を担当しますが、メモリは、関連する Bitmap が解放されるまで解放されるべきではありません。

于 2009-02-06T23:17:38.710 に答える
2

動かしてみましたか

   picture.releasePixelData(pPixels);

   finally
   {
       memStream.Dispose();
       picture.releasePixelData(pPixels);
   }

それは間違いなくスレッドの問題のように聞こえます(特に、 releasePixelData がバックグラウンドスレッドで発生する可能性があると述べているため)。スレッド化の問題は、常に 1 台のマシンでのみ発生する問題であり、常にクライアント マシンで発生します (おそらく、メモリが 256 メガバイトしかないか、ばかげた何かがあり、ガベージ コレクターが早期に起動している、またはマシンにクアッド コアがあるためです)。開発者のマシンはデュアルコアか何かです)。

于 2009-02-06T20:11:04.763 に答える