77 votes

Quelle est la différence entre Bitmap.Clone () et le nouveau Bitmap (Bitmap)?

Autant que je sache, il existe deux manières de copier un bitmap.

Bitmap.Clone ()

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

nouvelle bitmap ()

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

Comment ces approches diffèrent-elles? Je suis particulièrement intéressé par la différence en termes de mémoire et de threading.

117voto

Anlo Points 1188

La lecture de la réponse à la question précédente, j'ai eu peur que les données de pixel serait partagé entre cloné instances de Bitmap. J'ai donc effectué quelques tests pour trouver les différences entre Bitmap.Clone() et new Bitmap().

Bitmap.Clone() conserve l'original du fichier verrouillé. À l'aide de new Bitmap(original) au lieu de débloquer le fichier après l' original.Dispose().

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

À l'aide de l' Graphics classe pour modifier le clone, ne va pas modifier l'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

À l'aide de l' LockBits méthode des rendements différents blocs de mémoire pour l'original et le 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);

Les résultats sont les mêmes avec les deux object ICloneable.Clone() et Bitmap Bitmap.Clone(Rectangle, PixelFormat).

Ensuite, j'ai essayé quelques simples repères en utilisant le code suivant.

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

Le stockage de 50 copies dans la liste a pris 6,2 secondes et a abouti à 1,7 GO d'utilisation de la mémoire (l'image d'origine est de 24 bpp et 3456 x 2400 pixels = 25 MO).

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

À l'aide de Clone() au lieu de cela j'ai pu stocker 1 000 000 d'exemplaires dans la liste lors de 0,7 secondes et à l'aide de 0,9 GO. Comme prévu, Clone() est très léger en comparaison à d' new Bitmap().

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

Ce test a fait une copie à l'aide de Clone() puis changé aléatoire des pixels d'une couleur aléatoire. Cette opération semble déclencher une copie de toutes les données de pixels à partir de l'original, parce que nous sommes maintenant de retour à 7,8 secondes et 1,6 GO.

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

Juste la création d'un Graphics objet à partir de l'image ne doit pas déclencher la copie, vous devez dessiner quelque chose en utilisant l' Graphics objet.

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

À l'aide de LockBits d'autre part, permet de copier les données, même si ImageLockMode.ReadOnly est spécifié.

80voto

Hans Passant Points 475940

C'est la différence entre une "profonde" et "superficielle" copie, également un problème avec la quasi-obsolète IClonable interface. La méthode Clone() crée un nouvel objet Bitmap, mais les données de pixel est partagée avec l'objet bitmap d'origine. L'image Bitmap(Image) constructeur crée un nouvel objet Bitmap, mais qui a sa propre copie des données de pixel.

À l'aide de Clone() est très rarement utile. Beaucoup de questions à ce sujet, DONC où le programmeur espère que Clone() évite le typique de la difficulté avec les bitmaps, le verrou sur le fichier à partir duquel il a été chargé. Il n'a pas. Utilisez uniquement Clone() lorsque vous passer une référence à du code qui dispose que le bitmap et vous ne voulez pas perdre l'objet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X