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é.