Come si clona un'immagine Buffered


120

Ho un oggetto che contiene molte immagini tamponate, voglio creare un nuovo oggetto copiando tutte le immagini tamponate nel nuovo oggetto, ma queste nuove immagini potrebbero essere alterate e non voglio che le immagini dell'oggetto originale vengano alterate alterando il nuove immagini di oggetti.

è chiaro?

È possibile e qualcuno può suggerire un buon modo per farlo, per favore? Ho pensato a getSubImage ma ho letto da qualche parte che qualsiasi modifica alla sottoimmagine è correlata all'immagine genitore.

Voglio solo essere in grado di ottenere una nuova copia completamente separata o un clone di BufferedImage


1
non puoi chiamare il clone()metodo? O mi sono perso qualcosa? Non so molto sulla BufferedImageclasse
Noel M

1
clone fornisce solo una copia superficiale in modo da contenere i riferimenti alle immagini memorizzate nel buffer; non copie di loro.
Ultimate Gobblement

7
@NoelM, UltimateGobblement: BufferedImagenon implementa Cloneablee il clone()metodo ha accesso protetto.
Robert

Risposte:


173

Qualcosa come questo?

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

4
Lo prendo in prestito anche nel mio programma =)
Daniel Kats

hanno problemi con questo metodo sulla copia
dell'immagine secondaria

7
Sebbene funzioni nella maggior parte dei casi, non funziona correttamente quando BufferedImage è stata ritagliata (restituisce l'intera immagine prima che fosse ritagliata). Una soluzione semplice è modificare l'ultima riga in:
HaydenStudios

3
restituisce nuova BufferedImage (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios

copyData (null) non funziona sempre perché potrebbe funzionare su un raster genitore (ad esempio quando l'immagine è un'immagine secondaria), vedere la mia risposta modificata
user1050755

46

Lo faccio:

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

Funziona abbastanza bene ed è semplice da usare.


3
Sembra piuttosto semplice. Perché questa non è la risposta migliore? C'è un difetto di cui non sono a conoscenza?
WVrock

2
@WVrock Non funziona se il tipo di immagine è 0 (personalizzato)
Tilman Hausherr

3
sostituire Graphics g = b.getGraphics (); di Graphics2D g = b.createGraphics (); ed è perfetto
Nadir

1
Penso che questa sia la risposta più pulita. Sebbene ci siano differenze di prestazioni tra questa e la risposta accettata? Mi sento trascurabile se no? Potrebbe essere più veloce semplicemente perché la creazione di oggetti è ottimizzata nella jvm. Anche usando openjdk 11. Se qualcuno può rispondere a questa domanda.
thekevshow

18

La procedura menzionata in precedenza non riesce se applicata alle sotto immagini. Ecco una soluzione più completa:

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

Grazie, ho ricevuto un errore di offset durante il tentativo di clonare un'immagine secondaria. Questa versione è esattamente ciò di cui avevo bisogno.
rococò

5

Un altro modo è usare la Graphics2Dclasse per disegnare l'immagine su una nuova immagine vuota. Questo non clona davvero l'immagine, ma produce una copia dell'immagine.

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


4

So che questa domanda è piuttosto vecchia, ma per i futuri visitatori, ecco la soluzione che userei:

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

Correggimi se la modifica di quanto appena ottenuto newImageinfluisce in qualche modo anche sull'immagine originale.
-> Javadoc per getScaledInstance
-> Javadoc per SCALE_DEFAULT (le altre costanti sono elencate appena sotto quella)


Penso che in realtà non copierebbe l'immagine, cioè se cambiassi l'originale cambierà anche il ridimensionato, ma è passato un po 'di tempo quindi lascia che qualcun altro lo dica con certezza.
f1wade

1
Questo effettivamente copia l'immagine, in quanto le modifiche all'originale non cambieranno la copia. Questa risposta è breve e concisa e non è nemmeno limitata a BufferedImages. L'unico problema è che ritorna Image, no BufferedImage.
Kröw
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.