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