位图克隆问题

时间:2009-08-23 17:56:38

标签: c# exception bitmap clone

考虑使用此代码加载,修改和保存位图图像:

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

它以ExternalException结束,并显示以下消息:“GDI +中发生了一般错误”。 这有什么不对?打开文件的任何类型的锁定?如果是这样,为什么第一个块有效?克隆System.Drawing.Bitmap的正确代码是什么,而我们可能需要在内存中编辑主对象或其克隆并仍然将它们都加载到内存中?

4 个答案:

答案 0 :(得分:5)

是的,当加载第一个位图对象时,文件被锁定,因此bmpClone.Save()因同一个逻辑死锁而失败,因此using会失败。

按文件名打开位图时,文件在Bitmap的整个生命周期内都会被锁定。如果您使用流,则流必须保持打开状态。

<强>更新

如果您希望在内存中有两个位图,以便在您所使用的方法范围之外使用,那么您将不会使用Dispose()块。

从文件创建第一个图像,然后克隆它。在整个UI生命周期中根据需要使用它们,但确保在不再需要它们时使用clone()进行清理,以便释放底层资源。

另外,来自MSDN:

  

将图像保存到同一文件中   是不允许的   并抛出异常

这很尴尬。如果使用// ... 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(); 创建的对象保留有关图像源的信息(例如原始文件上的句柄),或者在使用Bitmap实例时无法解锁文件,那么您可能需要保存到新文件,或从原始文件的临时副本打开。

请改为尝试:

{{1}}

答案 1 :(得分:5)

您还可以使用简单的解决方法加载位图而无需文件锁定:

using (Stream s = File.OpenRead(@"\My Documents\My Pictures\Waterfall.jpg"))
Bitmap _backImage = (Bitmap)Bitmap.FromStream(s);

答案 2 :(得分: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} Image PixelFormat:Format8bppIndexed。
Bitmap.Clone():0,00 ms(不是DeepCopy ... Same pixel data - look here
Bitmap.Clone()+ RotateFlip(以获取深拷贝):2,02 ms
KernellDllCopyBitmap:0,52毫秒(最好!)
MarshalCopyBitmap:2,21毫秒

答案 3 :(得分:0)

这是我的虚荣方法:

    private static unsafe Bitmap DuplicateBitmap(Bitmap inputBitmap)
    {
        byte[] buffer = new byte[inputBitmap.Height * inputBitmap.Width *
                            Image.GetPixelFormatSize(inputBitmap.PixelFormat) / 8];  

        fixed (byte* p = buffer)
        {
            BitmapData b1Data = new BitmapData()
            {
                Scan0 = (IntPtr)p,
                Height = inputBitmap.Height,
                Width = inputBitmap.Width,
                PixelFormat = inputBitmap.PixelFormat,
                Stride = inputBitmap.Width * Image.GetPixelFormatSize(inputBitmap.PixelFormat) / 8,
            }; 

            inputBitmap.LockBits(new Rectangle(Point.Empty, inputBitmap.Size),
                ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer, inputBitmap.PixelFormat, b1Data); // copy out.   

            Bitmap b2 = new Bitmap(b1Data.Width, b1Data.Height, b1Data.Stride, inputBitmap.PixelFormat, b1Data.Scan0);

            inputBitmap.UnlockBits(b1Data); 

            return b2;
        }
    }

快10%(取决于位图大小......)