以这种方式使用锁定位复制位图区域是否安全(双关语)?

时间:2013-02-07 14:58:14

标签: c# bitmap copy lockbits

我认为我发现了一种更快捷的方法来复制c#中的位图。 (如果它有效,我确定我不是第一个,但我还没有看到它。)

我能想到的最简单的方法就是断言我的想法是基于什么,如果没有人在其中发现漏洞,假设这个想法是合理的:

    void FastCopyRegion(Bitmap CopyMe, ref Bitmap IntoMe, Rectangle CopyArea)
    {
        //`IntoMe` need not be declared `ref` but it brings
        //   attention to the fact it will be modified
        Debug.Assert(CopyMe.PixelFormat == IntoMe.PixelFormat,
           "PixelFormat mismatch, we could have a problem");
        Debug.Assert(CopyMe.Width == IntoMe.Width,    //This check does not verify
           "Stride mismatch, we could have a problem");// sign of `stride` match
        BitmapData copyData = CopyMe.LockBits(CopyArea,
            ImageLockMode.ReadWrite, CopyMe.PixelFormat);
        IntoMe.UnlockBits(copyData);
    }

1)LockBits只是将位图中的像素数据块复制到固定内存中,然后使用UnlockBits

进行编辑和复制。

2)使用LockBits不会影响复制的内存块,因此它对从中复制的图像没有影响。

3)由于您从未输入unsafe代码,因此不存在破坏内存的风险。

我看到可能的漏洞:

1)如果两个位图的PixelFormat不同,则此方法可能无法始终正确复制。但是,由于LockBits需要指定pixelformat,所以似乎可以处理。 (如果是这样的话,对于那个开销而言,其他99.9%的时间我们没有切换像素格式!/ EndSarcasm)

2)如果两个位图的步幅不匹配,则可能存在问题(因为stride是复制操作中外部for循环的递增器。)此问题会限制复制到位图等于步幅。

编辑:我认为断言#2一定是错的......我在尝试稍后访问通过CopyMe传递的位图时发现了一个错误。下面的解决方法,但我不确定它是否留下了一块固定内存。 (内存泄漏警报!)

    void FastCopyRegion(Bitmap CopyMe, ref Bitmap IntoMe, Rectangle CopyArea)
    {
        //`IntoMe` need not be declared `ref` but it brings attention to the fact it will be modified
        Debug.Assert(CopyMe.PixelFormat == IntoMe.PixelFormat, "PixelFormat mismatch, we could have a problem");
        Debug.Assert(CopyMe.Width == IntoMe.Width, "Width mismatch, we could have a problem");
        BitmapData copyD = IntoMe.LockBits(CopyArea, ImageLockMode.ReadWrite, CopyMe.PixelFormat);
        BitmapData copyData = CopyMe.LockBits(CopyArea, ImageLockMode.ReadWrite, CopyMe.PixelFormat);
        CopyMe.UnlockBits(copyData);
        IntoMe.UnlockBits(copyData);
    }

1 个答案:

答案 0 :(得分:3)

请改用Bitmap.Clone()。 GDI +往往不会报告异常,因此很难跟踪产生的错误。

将图像复制到位图的非常快速方式是使用Graphics.DrawImage() ,只要您不转换像素格式或缩放图像。 / p>