【问题标题】:How to create a Bitmap deep copy如何创建位图深拷贝
【发布时间】:2011-08-18 11:26:04
【问题描述】:

我在我的应用程序中处理位图,出于某些目的,我需要创建位图的深层副本。有没有优雅的方法来做到这一点?

我试过了

Bitmap deepCopy = original.Clone();

,显然这不会创建深层副本,而是创建浅层副本。 我的下一个尝试是创建一个新的位图

Bitmap deepCopy = new Bitmap(original);

不幸的是,这个构造函数是 Bitmap(Image),而不是 Bitmap(Bitmap),Bitmap(Image) 会将我漂亮的 8bppIndexed Pixelformat 转换为不同的格式。

另一个尝试是使用 MemoryStream

public static Bitmap CreateBitmapDeepCopy(Bitmap source)
{
    Bitmap result;
    using (MemoryStream stream = new MemoryStream())
    {
        source.Save(stream, ImageFormat.Bmp);
        stream.Seek(0, SeekOrigin.Begin);
        result = new Bitmap(stream);
    }
    return result;
}

好吧,这也不起作用,因为 MemoryStream 必须在 Bitmap 的整个生命周期中打开。

所以,我总结了我所有的死胡同,我真的很想看到一个很好的优雅的方式来创建位图深拷贝。谢谢你:)

【问题讨论】:

    标签: c# bitmap deep-copy


    【解决方案1】:

    您可以在代码中放置以下类:

    public static class BitmapExtensions
    {
        public static Bitmap DeepClone(this Bitmap source)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using (stream)
            {
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (Bitmap)formatter.Deserialize(stream);
            }
        }
    }
    

    此方法已调整为与Bitmap 一起使用。如果您想要一个通用方法,请查看下面的链接。通过将方法命名为DeepClone(),我们消除了破坏现有代码的风险(在下面的答案中,该方法称为Clone(),因此它是一种覆盖方法)。

    来自这里的原文:https://stackoverflow.com/a/43042865/13574233

    虽然这种方法需要很多时间。如果您正在寻找一种性能良好的方法,那么这可能不是您想要的。

    【讨论】:

      【解决方案2】:

      我的环境:Windows 10、Visual Studio 2015、Framework 4.5.2

      它对我有用。

      Bitmap deepCopy = new Bitmap(original);
      

      【讨论】:

        【解决方案3】:

        假设您已经有一个名为 original 的位图,其中包含一些内容

        Bitmap original = new Bitmap( 200, 200 );     
        Bitmap copy = new Bitmap(original.Width, original.Height);
        using (Graphics graphics = Graphics.FromImage(copy))
        {
          Rectangle imageRectangle = new Rectangle(0, 0, copy.Width, copy.Height);
          graphics.DrawImage( original, imageRectangle, imageRectangle, GraphicsUnit.Pixel);
        }
        

        这应该创建一个相同大小的副本,并将原件绘制到副本中。

        【讨论】:

        • 它失去了原来的颜色格式。结果将始终为 32bpp ARGB。
        • Nyerguds 评论的附录:如果您尝试通过使用 New Bitmap(Width, Height, PixelFormat) 创建副本来保留原始像素格式格式,则可能会遇到 Graphics 对象不能的问题t 由索引像素格式创建。
        • @NigelHawkins I got around that,不过 :)
        【解决方案4】:

        我偶然发现的另一种实现相同目的的方法是旋转或翻转图像。在引擎盖下似乎创建了位图的全新副本。进行两次旋转或翻转可以让您最终获得原始图像的精确副本。

        result.RotateFlip(RotateFlipType.Rotate180FlipX);
        result.RotateFlip(RotateFlipType.Rotate180FlipX);
        

        【讨论】:

        • 所以你复制了两次
        【解决方案5】:
        B.Clone(new Rectangle(0, 0, B.Width, B.Height), B.PixelFormat)
        

        【讨论】:

        • 非常适合我。不需要我们自己序列化/反序列化。
        • 有关各种位图克隆选项的详细讨论,包括这些选项的工作和执行方式,请参阅this SO answer
        • 这不是深拷贝。以下似乎对我有用stackoverflow.com/questions/43039099/…
        • 不是深拷贝,静止图像数据是共享的。如果我处置对象 B,则克隆的数据也会消失
        【解决方案6】:

        您可以序列化位图,然后反序列化它。位图是可序列化的。

        【讨论】:

        • +1 - 这正是我过去解决浅拷贝与深拷贝问题的方法
        • -1,因为不需要序列化(至少在 .NET 4.0 中不需要)。请参阅@George Duckett 的回答。
        猜你喜欢
        • 2013-03-07
        • 2013-04-06
        • 2011-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-08
        • 2011-04-26
        相关资源
        最近更新 更多