web-dev-qa-db-fra.com

Comment cloner une BufferedImage

J'ai un objet qui contient de nombreuses images tamponnées, je souhaite créer un nouvel objet en copiant toutes les images tamponnées dans le nouvel objet, mais ces nouvelles images peuvent être modifiées et je ne souhaite pas que les images de l'objet d'origine soient modifiées en modifiant le nouveaux objets images.

est-ce clair?

Est-ce possible et quelqu'un peut-il suggérer un bon moyen de le faire s'il vous plaît? J'ai pensé à getSubImage mais j'ai lu quelque part que toutes les modifications apportées à la sous-image sont renvoyées à l'image parent.

Je veux juste pouvoir obtenir une copie ou un clone entièrement séparé d'une BufferedImage

111
f1wade

Quelque chose comme ça?

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

Je fais ça:

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

Cela fonctionne assez bien et il est simple à utiliser.

41
APerson

La procédure mentionnée précédemment échoue lorsqu'elle est appliquée aux sous-images. Voici une solution plus complète:

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

Une autre façon consiste à utiliser le Graphics2D classe pour dessiner l'image sur une nouvelle image vierge. Cela ne clone pas vraiment l'image, mais il en résulte une copie de l'image produite.

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
HyperNeutrino

La classe BufferedImage n'implémente pas l'interface Cloneable. Ainsi, la méthode de clonage n'est pas annulée. Voici une alternative à la technique de copie en profondeur: Java Tip 76: Une alternative à la technique de copie en profondeur

4
Mike

Je sais que cette question est assez ancienne, mais pour les futurs visiteurs, voici la solution que j'utiliserais:

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

S'il vous plaît, corrigez-moi si le changement de newImage récemment obtenu affecte également l'image d'origine de quelque manière que ce soit.
-> Javadoc pour getScaledInstance
-> Javadoc pour SCALE_DEFAULT (les autres constantes sont listées juste en dessous de celle-ci)

3
PixelMaster

Cela était incroyablement utile pour un programme que j'utilise pour dessiner des éléments, et n'a pas pu implémenter les états Undo/Redo en raison de BufferedImages sur les piles étant pratiquement identique.

En passant, je suggère d'utiliser deux piles pour ce genre d'opérations! Chaque fois que vous faites quelque chose, créez immédiatement une nouvelle image, utilisez la méthode deepCopy mentionnée ci-dessus.

image = deepCopy((BufferedImage) stackUndo.peek());

modifiez l'image à votre guise, puis lorsque vous arrêtez de modifier (comme lorsque vous relâchez le bouton de la souris),

stackUndo.Push(image);                                                   

et toujours peindre l'élément en haut de la pile de gauche

g.drawImage(stackUndo.peek(),x,y,null);

et ensuite, si vous effectuez des opérations d'annulation/de restauration, suivez ce qui suit

public void undoOrRedo(String op) {
    if(op.equals("undo") && stackUndo.size()>1){
       stackRedo.Push(stackUndo.pop());
        repaint();
    }
    if(op.equals("redo") && stackRedo.size()>0){
        stackUndo.Push(stackRedo.pop());
        repaint();
    }
}

assurez-vous de toujours laisser quelque chose dans la pile de gauche, car pour la peinture, il utilisera toujours l'élément en haut (en avant)!

1
Santiago Zubieta