gpt4 book ai didi

c# - Bitmap.Clone() 和 new Bitmap(Bitmap) 有什么区别?

转载 作者:IT王子 更新时间:2023-10-29 03:42:21 30 4
gpt4 key购买 nike

据我所知,有两种复制位图的方法。

Bitmap.Clone()

Bitmap A = new Bitmap("somefile.png");
Bitmap B = (Bitmap)A.Clone();

新位图()

Bitmap A = new Bitmap("somefile.png");
Bitmap B = new Bitmap(A);

这些方法有何不同?我对内存和线程方面的差异特别感兴趣。

最佳答案

阅读之前的答案,我担心像素数据会在位图的克隆实例之间共享。所以我进行了一些测试以找出 Bitmap.Clone()new Bitmap() 之间的区别。

Bitmap.Clone() 保持原始文件锁定:

  Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
original.Dispose();
File.Delete("Test.jpg"); // Will throw System.IO.IOException

使用 new Bitmap(original) 将在 original.Dispose() 之后解锁文件,并且不会抛出异常。使用 Graphics 类修改克隆(使用 .Clone() 创建)不会修改原始的:

  Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
Graphics gfx = Graphics.FromImage(clone);
gfx.Clear(Brushes.Magenta);
Color c = original.GetPixel(0, 0); // Will not equal Magenta unless present in the original

同样,使用LockBits 方法会为原始和克隆产生不同的内存块:

  Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
BitmapData odata = original.LockBits(new Rectangle(0, 0, original.Width, original.Height), ImageLockMode.ReadWrite, original.PixelFormat);
BitmapData cdata = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadWrite, clone.PixelFormat);
Assert.AreNotEqual(odata.Scan0, cdata.Scan0);

object ICloneable.Clone()Bitmap Bitmap.Clone(Rectangle, PixelFormat) 的结果相同。

接下来,我使用以下代码尝试了一些简单的基准测试。

在列表中存储 50 个副本需要 6.2 秒,并导致 1.7 GB 内存使用(原始图像为 24 bpp,3456 x 2400 像素 = 25 MB):

  Bitmap original = new Bitmap("Test.jpg");
long mem1 = Process.GetCurrentProcess().PrivateMemorySize64;
Stopwatch timer = Stopwatch.StartNew();

List<Bitmap> list = new List<Bitmap>();
Random rnd = new Random();
for(int i = 0; i < 50; i++)
{
list.Add(new Bitmap(original));
}

long mem2 = Process.GetCurrentProcess().PrivateMemorySize64;
Debug.WriteLine("ElapsedMilliseconds: " + timer.ElapsedMilliseconds);
Debug.WriteLine("PrivateMemorySize64: " + (mem2 - mem1));

使用 Clone() 我可以在 0.7 秒内在列表中存储 1 000 000 个副本并使用 0.9 GB。正如预期的那样,Clone()new Bitmap() 相比非常轻量:

  for(int i = 0; i < 1000000; i++)
{
list.Add((Bitmap) original.Clone());
}

使用 Clone() 方法的克隆是写时复制。在这里,我将一个随机像素更改为克隆上的一种随机颜色。此操作似乎触发了原始所有像素数据的副本,因为我们现在回到 7.8 秒和 1.6 GB:

  Random rnd = new Random();
for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
clone.SetPixel(rnd.Next(clone.Width), rnd.Next(clone.Height), Color.FromArgb(rnd.Next(0x1000000)));
list.Add(clone);
}

仅仅从图像创建一个 Graphics 对象不会触发复制:

  for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
Graphics.FromImage(clone).Dispose();
list.Add(clone);
}

您必须使用 Graphics 对象绘制一些东西才能触发复制。最后,另一方面,使用 LockBits 将复制数据,即使指定了 ImageLockMode.ReadOnly:

  for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
BitmapData data = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadOnly, clone.PixelFormat);
clone.UnlockBits(data);
list.Add(clone);
}

关于c# - Bitmap.Clone() 和 new Bitmap(Bitmap) 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12709360/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com