Soweit ich das beurteilen kann, gibt es zwei Möglichkeiten, eine Bitmap zu kopieren.
Bitmap.Clone ()
Bitmap A = new Bitmap("somefile.png");
Bitmap B = (Bitmap)A.Clone();
neue Bitmap ()
Bitmap A = new Bitmap("somefile.png");
Bitmap B = new Bitmap(A);
Wie unterscheiden sich diese Ansätze? Ich interessiere mich besonders für den Unterschied in Bezug auf Speicher und Threading.
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 @HansPassantAntworten:
Es ist der gemeinsame Unterschied zwischen einer "tiefen" und einer "flachen" Kopie, auch ein Problem mit der fast veralteten IClonable-Schnittstelle. Die Clone () -Methode erstellt ein neues Bitmap-Objekt, aber die Pixeldaten werden mit dem ursprünglichen Bitmap-Objekt geteilt. Der Bitmap (Bild) -Konstruktor erstellt auch ein neues Bitmap-Objekt, das jedoch über eine eigene Kopie der Pixeldaten verfügt.
Viele Fragen zu Clone () bei SO, bei denen der Programmierer hofft, dass er die typischen Probleme mit Bitmaps vermeidet, die Sperre für die Datei, aus der sie geladen wurde. Das tut es nicht. Eine möglicherweise praktische Anwendung besteht darin, Probleme mit einer Bibliotheksmethode zu vermeiden, die Dispose () in einer übergebenen Bitmap unangemessen aufruft.
Die Überladungen können nützlich sein und die Pixelformatkonvertierung oder die Zuschneideoptionen nutzen.
quelle
.Dispose()
Methode auf", wenn Sie Folgendes sagen: "Verwenden Sie Clone () nur, wenn Sie einen Verweis auf Code übergeben, der die Bitmap entsorgt, und Sie das Objekt nicht verlieren möchten. ""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 herauszufindennew 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"); // Will throw System.IO.IOException
Wenn Sie
new Bitmap(original)
stattdessen verwenden, wird die Datei danach entsperrtoriginal.Dispose()
, und die Ausnahme wird nicht ausgelöst. Wenn Sie dieGraphics
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); // Will not equal Magenta unless present in the original
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 gleichBitmap 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 zunew 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 VerwendungLockBits
auf der anderen Seite, werden die Daten kopieren , selbst wennImageLockMode.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); }
quelle