Beim Lesen der vorherigen Antworten machte ich mir Sorgen, dass die Pixeldaten von geklonten Instanzen von Bitmap gemeinsam genutzt werden könnten. Also habe ich einige Tests durchgeführt, um die Unterschiede zwischen Bitmap.Clone()
und herauszufinden new Bitmap()
.
Bitmap.Clone()
hält die Originaldatei gesperrt:
Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
original.Dispose();
File.Delete("Test.jpg");
Wenn Sie new Bitmap(original)
stattdessen verwenden, wird die Datei danach entsperrt original.Dispose()
, und die Ausnahme wird nicht ausgelöst. Wenn Sie die Graphics
Klasse zum Ändern des Klons verwenden (erstellt mit .Clone()
), wird das Original nicht geändert:
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);
In ähnlicher Weise LockBits
ergibt die Verwendung der Methode unterschiedliche Speicherblöcke für das Original und den Klon:
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);
Die Ergebnisse sind bei beiden object ICloneable.Clone()
und gleich Bitmap Bitmap.Clone(Rectangle, PixelFormat)
.
Als nächstes habe ich einige einfache Benchmarks mit dem folgenden Code ausprobiert.
Das Speichern von 50 Kopien in der Liste dauerte 6,2 Sekunden und führte zu einer Speichernutzung von 1,7 GB (das Originalbild ist 24 bpp und 3456 x 2400 Pixel = 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));
Mit Clone()
stattdessen könnte ich 1 000 000 Kopien in der Liste während 0,7 Sekunden und mit 0,9 GB speichern. Wie erwartet, Clone()
ist sehr leicht im Vergleich zu new Bitmap()
:
for(int i = 0; i < 1000000; i++)
{
list.Add((Bitmap) original.Clone());
}
Klone, die diese Clone()
Methode verwenden, werden beim Schreiben kopiert. Hier ändere ich ein zufälliges Pixel in eine zufällige Farbe auf dem Klon. Dieser Vorgang scheint eine Kopie aller Pixeldaten des Originals auszulösen, da wir jetzt wieder bei 7,8 Sekunden und 1,6 GB sind:
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);
}
Wenn Sie nur ein Graphics
Objekt aus dem Bild erstellen, wird die Kopie nicht ausgelöst:
for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
Graphics.FromImage(clone).Dispose();
list.Add(clone);
}
Sie müssen mit dem Graphics
Objekt etwas zeichnen , um die Kopie auszulösen. Schließlich Verwendung LockBits
auf der anderen Seite, werden die Daten kopieren , selbst wenn ImageLockMode.ReadOnly
angegeben wird:
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);
}
new Bitmap(A)
gab eine 32-Bit-Bitmap pro Pixel zurück, während(Bitmap)A.Clone()
noch 1 Bit pro Pixel vorhanden war. Da ich das Bild für spätere E-Mails in eine PDF-Datei einbettete, war es wichtig, das Bild auf 1 Bit zu halten. @Aelios @HansPassant