Wie klonen Sie ein BufferedImage?

120

Ich habe ein Objekt, das viele gepufferte Bilder enthält. Ich möchte ein neues Objekt erstellen, das alle gepufferten Bilder in das neue Objekt kopiert. Diese neuen Bilder können jedoch geändert werden, und ich möchte nicht, dass die ursprünglichen Objektbilder durch Ändern des geändert werden neue Objekte Bilder.

Ist das klar?

Ist dies möglich und kann jemand bitte einen guten Weg vorschlagen, dies zu tun? Ich habe an getSubImage gedacht, aber irgendwo gelesen, dass alle Änderungen am Unterbild wieder auf das übergeordnete Bild übertragen werden.

Ich möchte nur in der Lage sein, eine neue, vollständig separate Kopie oder einen Klon eines BufferedImage zu erhalten

f1wade
quelle
1
Kannst du die clone()Methode nicht aufrufen ? Oder habe ich etwas verpasst? Ich weiß nicht viel über die BufferedImageKlasse
Noel M
1
Der Klon stellt nur eine flache Kopie bereit, sodass er die Verweise auf die gepufferten Bilder enthält. keine Kopien davon.
Ultimate Gobblement
7
@NoelM, UltimateGobblement: Wird BufferedImagenicht implementiert Cloneableund die clone()Methode hat geschützten Zugriff.
Robert

Antworten:

173

Etwas wie das?

static BufferedImage deepCopy(BufferedImage bi) {
 ColorModel cm = bi.getColorModel();
 boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
 WritableRaster raster = bi.copyData(null);
 return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
Klark
quelle
4
Ich leihe mir das auch in meinem Programm aus =)
Daniel Kats
habe ein Problem mit dieser Methode beim Kopieren von Teilbildern
Mischka
7
Während dies unter den meisten Umständen funktioniert, funktioniert es nicht richtig, wenn dieses BufferedImage zugeschnitten wurde (es gibt das gesamte Bild zurück, bevor es zugeschnitten wurde). Eine einfache Lösung besteht darin, die letzte Zeile in
Folgendes
3
neues BufferedImage zurückgeben (cm, Raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios
copyData (null) funktioniert nicht immer, da es möglicherweise auf einem übergeordneten Raster funktioniert (dh wenn das Bild ein
Unterbild
46

Ich mache das:

public static BufferedImage copyImage(BufferedImage source){
    BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
    Graphics g = b.getGraphics();
    g.drawImage(source, 0, 0, null);
    g.dispose();
    return b;
}

Es funktioniert ziemlich gut und ist einfach zu bedienen.

Eine Person
quelle
3
Das sieht ziemlich einfach aus. Warum ist dies nicht die beste Antwort? Gibt es einen Fehler, den ich nicht kenne?
WVrock
2
@ WVrock Es funktioniert nicht, wenn der Bildtyp 0 (benutzerdefiniert) ist
Tilman Hausherr
3
Grafik ersetzen g = b.getGraphics (); von Graphics2D g = b.createGraphics (); und es ist perfekt
Nadir
1
Ich denke, das ist die sauberste Antwort. Obwohl es einen Leistungsunterschied zwischen dieser und der akzeptierten Antwort gibt? Ich fühle mich vernachlässigbar, wenn überhaupt nein? Könnte dies schneller sein, nur weil die Objekterstellung im JVM optimiert ist. Verwenden Sie auch openjdk 11. Wenn jemand diese Frage beantworten kann.
Thekevshow
18

Das zuvor erwähnte Verfahren schlägt fehl, wenn es auf Teilbilder angewendet wird. Hier ist eine vollständigere Lösung:

public static BufferedImage deepCopy(BufferedImage bi) {
    ColorModel cm = bi.getColorModel();
    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
    WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster());
    return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
user1050755
quelle
Vielen Dank, ich habe einen Versatzfehler beim Klonen eines Teilbilds erhalten. Diese Version ist genau das, was ich brauchte.
Rokoko
5

Eine weitere Möglichkeit ist es, die verwenden Graphics2DKlasse das Bild auf ein neues leeres Bild zu zeichnen. Dadurch wird das Bild nicht wirklich geklont, es wird jedoch eine Kopie des Bildes erstellt.

public static final BufferedImage clone(BufferedImage image) {
    BufferedImage clone = new BufferedImage(image.getWidth(),
            image.getHeight(), image.getType());
    Graphics2D g2d = clone.createGraphics();
    g2d.drawImage(image, 0, 0, null);
    g2d.dispose();
    return clone;
}
HyperNeutrino
quelle
4

Ich weiß, dass diese Frage ziemlich alt ist, aber für zukünftige Besucher ist hier die Lösung, die ich verwenden würde:

Image oldImage = getImage();
Image newImage = oldImage.getScaledInstance(oldImage.getWidth(null), oldImage.getHeight(null), Image.SCALE_DEFAULT);

Bitte korrigieren Sie mich, wenn sich das Ändern des gerade erhaltenen newImageBildes in irgendeiner Weise auch auf das Originalbild auswirkt.
-> Javadoc für getScaledInstance
-> Javadoc für SCALE_DEFAULT (die anderen Konstanten sind direkt darunter aufgeführt)

PixelMaster
quelle
Ich denke, das würde das Bild nicht wirklich kopieren, dh wenn Sie das Original ändern, ändert sich auch der skalierte Wille, aber es ist eine Weile so krank, dass jemand anderes es mit Sicherheit sagen kann.
f1wade
1
Dadurch wird das Bild tatsächlich kopiert, da Änderungen am Original die Kopie nicht ändern. Diese Antwort ist kurz und prägnant und nicht einmal auf BufferedImages beschränkt. Das einzige Problem ist, dass es zurückkehrt Image, nicht BufferedImage.
Kröw