What is the difference between Bitmap.Clone () and the new bitmap (Bitmap)?

As far as I can tell, there are two ways to copy a bitmap.

Bitmap.Clone ()

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

new bitmap ()

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

How do these approaches differ? I am particularly interested in the difference in memory and thread.

+51
c # clone bitmap
Oct 03 '12 at 13:18
source share
2 answers

This is the usual difference between a deep and shallow copy, as well as a problem with the almost obsolete IClonable interface. The Clone () method creates a new Bitmap object, but the pixel data is shared with the original raster object. The Bitmap constructor (Image) also creates a new Bitmap object, but one that has its own copy of the pixel data.

Using Clone () is very rarely useful. There are many questions about this in SO, where the programmer hopes that Clone () will avoid the typical problem with bitmaps, locking the file from which it was loaded. This is not true. Use only Clone () when you pass a link to the code that hosts the bitmap and you don't want to lose the object.

+49
Oct 03
source share

After reading the previous answers, I was worried that the pixel data would be shared between the cloned Bitmap instances. So I did some tests to find out the differences between Bitmap.Clone() and new Bitmap() .

Bitmap.Clone() keeps the source file locked:

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

Using new Bitmap(original) instead will open the file after original.Dispose() and no exception will be thrown. Using the Graphics class to modify a clone (created using .Clone() ) will not change the original:

  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 

Similarly, using the LockBits method gives different memory blocks for the original and the clone:

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

The results are the same with object ICloneable.Clone() and Bitmap Bitmap.Clone(Rectangle, PixelFormat) .

Then I tried some simple tests using the following code.

Saving 50 copies in the list took 6.2 seconds and led to the use of 1.7 GB of memory (the original image is 24 bit / s and 3456 x 2400 pixels = 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)); 

Using Clone() , instead, I could store 1,000,000 copies in a list for 0.7 seconds and use 0.9 GB. As expected, Clone() is very lightweight compared to new Bitmap() :

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

Clones using the Clone() method are copy-on-write. Here I change one random pixel to a random color on a clone. This operation seems to cause a copy of all the pixel data from the original, because we returned 7.8 seconds and 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); } 

Just creating a Graphics object from an image will not result in copying:

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

You must draw something using the Graphics object to invoke the copy. Finally, using LockBits , on the other hand, will copy the data, even if ImageLockMode.ReadOnly is 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); } 
+87
Dec 18 '12 at 15:15
source share



All Articles