7

ビットマップイメージのロード、変更、および保存については、次のコードを検討してください。

    using (Bitmap bmp = new Bitmap("C:\\test.jpg"))
    {
        bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
        bmp.Save("C:\\test.jpg");
    }

例外なく実行されます。しかし、これを考慮してください:

    using (Bitmap bmp = new Bitmap("C:\\test.jpg"))
    {
        using (Bitmap bmpClone = (Bitmap)bmp.Clone())
        {
            //You can replace "bmpClone" in the following lines with "bmp",
            //exception occurs anyway                    
            bmpClone.RotateFlip(RotateFlipType.Rotate180FlipNone);
            bmpClone.Save("C:\\test.jpg");
        }
    }

「GDI+で一般的なエラーが発生しました」というメッセージでExternalExceptionで終了します。ここで何が問題になっていますか?開いているファイルに何らかのロックがありますか?もしそうなら、なぜ最初のブロックが機能するのですか?メインオブジェクトまたはそのクローンをメモリ内で編集し、両方をメモリにロードする必要がある場合に、System.Drawing.Bitmapのクローンを作成するための適切なコードは何ですか?

4

4 に答える 4

5

はい、最初のビットマップオブジェクトがロードされるとファイルがロックされます。したがってbmpClone.Save()、論理的なデッドロックがあるため、同じファイルへのアクセスは失敗します。

ファイル名でビットマップを開くと、ファイルはビットマップの存続期間中ロックされます。ストリームを使用する場合、ストリームは開いたままにする必要があります。

更新

現在使用しているメソッドのスコープ外で使用するために2つのビットマップをメモリに入れたい場合は、usingブロックを使用しません。

ファイルから最初のイメージを作成してから、クローンを作成します。UIライフサイクル全体で必要に応じてそれらを利用しますがDispose()、基盤となるリソースが解放されるように、不要になったときに使用してクリーンアップするようにしてください。

また、MSDNから:

画像を作成元のファイルと同じファイルに保存することは許可されておらず、例外がスローされます

それはかなり厄介です。を使用して作成されたオブジェクトclone()が画像ソースの情報(元のファイルのハンドルなど)を保持している場合、またはビットマップインスタンスの使用中にファイルのロックを解除できない場合は、新しいファイルに保存するか、新しいファイルに保存する必要があります。オリジナルの一時的なコピーから開きます。

代わりにこれを試してください:

// ... make a copy of test.jpg called test_temp.jpg

Bitmap bmpOriginal = new Bitmap("C:\\test_temp.jpg"))
Bitmap bmpClone = (Bitmap)bmp.Clone();

// ... do stuff          
bmpClone.RotateFlip(RotateFlipType.Rotate180FlipNone);

bmpClone.Save("C:\\test.jpg");

// ... cleanup
bmpOriginal.Dispose();
bmpClone.Dispose();
于 2009-08-23T18:04:30.380 に答える
5

これが私がビットマップをコピーする方法です:

[DllImport("kernel32.dll", EntryPoint = "CopyMemory")]
static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);

public static Bitmap KernellDllCopyBitmap(Bitmap bmp, bool CopyPalette = true)
{
    Bitmap bmpDest = new Bitmap(bmp.Width, bmp.Height, bmp.PixelFormat);

    if (!KernellDllCopyBitmap(bmp, bmpDest, CopyPalette))
        bmpDest = null;

    return bmpDest;
}


/// <summary>
/// Copy bitmap data.
/// Note: bitmaps must have same size and pixel format.
/// </summary>
/// <param name="bmpSrc">Source Bitmap</param>
/// <param name="bmpDest">Destination Bitmap</param>
/// <param name="CopyPalette">Must copy Palette</param>
public static bool KernellDllCopyBitmap(Bitmap bmpSrc, Bitmap bmpDest, bool CopyPalette = false)
{
    bool copyOk = false;
    copyOk = CheckCompatibility(bmpSrc, bmpDest);
    if (copyOk)
    {
        BitmapData bmpDataSrc;
        BitmapData bmpDataDest;

        //Lock Bitmap to get BitmapData
        bmpDataSrc = bmpSrc.LockBits(new Rectangle(0, 0, bmpSrc.Width, bmpSrc.Height), ImageLockMode.ReadOnly, bmpSrc.PixelFormat);
        bmpDataDest = bmpDest.LockBits(new Rectangle(0, 0, bmpDest.Width, bmpDest.Height), ImageLockMode.WriteOnly, bmpDest.PixelFormat);
        int lenght = bmpDataSrc.Stride * bmpDataSrc.Height;

        CopyMemory(bmpDataDest.Scan0, bmpDataSrc.Scan0, (uint)lenght);

        bmpSrc.UnlockBits(bmpDataSrc);
        bmpDest.UnlockBits(bmpDataDest);

        if (CopyPalette && bmpSrc.Palette.Entries.Length > 0)
            bmpDest.Palette = bmpSrc.Palette;
    }
    return copyOk;
}

    public static bool CheckCompatibility(Bitmap bmp1, Bitmap bmp2)
    {
        return ((bmp1.Width == bmp2.Width) && (bmp1.Height == bmp2.Height) && (bmp1.PixelFormat == bmp2.PixelFormat));
    }

## ImageCopyBenchmark ##

画像サイズ:{幅= 1024、高さ=1024}。
画像PixelFormat:Format8bppIndexed。
Bitmap.Clone():0,00 ms(DeepCopyではありません...同じピクセルデータ-ここを参照
Bitmap.Clone()+ RotateFlip(ディープコピーを推測するため):2,02 ms
KernellDllCopyBitmap:0,52 ms( THE BEST!)
MarshalCopyBitmap:2,21 ms

于 2013-05-03T15:27:45.550 に答える
4

簡単な回避策を使用して、ファイルロックなしでビットマップをロードすることもできます。

using (Stream s = File.OpenRead(@"\My Documents\My Pictures\Waterfall.jpg"))
Bitmap _backImage = (Bitmap)Bitmap.FromStream(s);
于 2009-09-08T13:21:29.513 に答える
0

これが私の虚栄心の方法です:

    プライベート静的安全でないビットマップDuplicateBitmap(ビットマップinputBitmap)
    {{
        byte [] buffer = new byte [inputBitmap.Height * inputBitmap.Width *
                            Image.GetPixelFormatSize(inputBitmap.PixelFormat)/ 8];  

        固定(バイト* p =バッファ)
        {{
            BitmapData b1Data = new BitmapData()
            {{
                Scan0 =(IntPtr)p、
                高さ=inputBitmap.Height、
                幅=inputBitmap.Width、
                PixelFormat = inputBitmap.PixelFormat、
                ストライド=inputBitmap.Width* Image.GetPixelFormatSize(inputBitmap.PixelFormat)/ 8、
            };

            inputBitmap.LockBits(new Rectangle(Point.Empty、inputBitmap.Size)、
                ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer、inputBitmap.PixelFormat、b1Data); // コピーアウト。   

            ビットマップb2=new Bitmap(b1Data.Width、b1Data.Height、b1Data.Stride、inputBitmap.PixelFormat、b1Data.Scan0);

            inputBitmap.UnlockBits(b1Data);

            b2を返します。
        }
    }

10%高速(ビットマップサイズによって異なります...)

于 2014-11-28T22:19:39.410 に答える