136 votes

Comment cloner une BufferedImage ?

J'ai un objet qui contient de nombreuses images tampons, je veux créer un nouvel objet en copiant toutes les images tampons dans le nouvel objet, mais ces nouvelles images peuvent être modifiées et je ne veux pas que les images de l'objet original soient modifiées en modifiant les images du nouvel objet.

C'est clair ?

Est-ce possible de le faire et quelqu'un peut-il me suggérer une bonne façon de le faire ? J'ai pensé à getSubImage mais j'ai lu quelque part que toute modification apportée à la sous-image est répercutée sur l'image parent.

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

1 votes

Ne pouvez-vous pas appeler le clone() méthode ? Ou ai-je manqué quelque chose ? Je ne connais pas très bien la méthode de l BufferedImage classe

1 votes

Clone ne fournit qu'une copie superficielle, de sorte qu'elle contient les références aux images mises en mémoire tampon, et non des copies de celles-ci.

8 votes

@NoelM, UltimateGobblement : BufferedImage ne met pas en œuvre Cloneable y el clone() a un accès protégé.

188voto

Klark Points 3906

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

5 votes

Je vais aussi l'emprunter dans mon programme =)

0 votes

J'ai un problème avec cette méthode de copie de sous-image.

9 votes

Si cela fonctionne dans la plupart des cas, cela ne fonctionne pas correctement lorsque cette BufferedImage a été recadrée (elle renvoie l'image entière avant qu'elle ne soit recadrée). Une solution simple consiste à remplacer la dernière ligne par la suivante :

56voto

APerson Points 223

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

Il fonctionne assez bien et il est simple à utiliser.

3 votes

Cela semble assez simple. Pourquoi ce n'est pas la meilleure réponse ? Y a-t-il une faille dont je ne suis pas conscient ?

2 votes

@WVrock Cela ne fonctionne pas si le type d'image est 0 (personnalisé).

4 votes

Remplacer Graphics g = b.getGraphics() ; par Graphics2D g = b.createGraphics() ; et c'est parfait

2voto

Mike Points 6184

La classe BufferedImage ne met pas en oeuvre l'interface Cloneable. Ainsi, la méthode clone n'est pas surchargée. Voici une alternative pour une technique de copie profonde : Conseil Java 76 : Une alternative à la technique de la copie profonde

0 votes

BufferedImage n'est pas sérialisable, ce qui rend cette alternative difficile à utiliser .

2voto

Zubieta Points 29

C'était incroyablement utile pour un programme que j'utilise pour dessiner des choses, et qui était incapable d'implémenter les états Undo/Redo à cause des BufferedImages sur les piles qui sont virtuellement la même chose.

D'ailleurs, je vous conseille vivement d'utiliser plusieurs piles pour ce genre d'opérations ! A 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 comme vous le souhaitez, puis lorsque vous arrêtez l'édition (comme lorsque vous relâchez le bouton de la souris), procédez comme suit

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 faites une opération d'annulation/rétablissement, suivez quelque chose comme ceci

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 qui se trouve en haut (peek) de celle-ci !

-1voto

eMAD Points 13

Je fais cela pour enregistrer une copie de l'image. Et ensuite relire l'image copiée pour y apporter les modifications que vous souhaitez.

public static boolean saveImageCopy( String imageFile)
{
    BufferedImage img;
    String saveAs = "copy.png";
    try {
        img = ImageIO.read(new File(imageFile));
        //getting the output image file object
        File saveImage = new File("C:\\Users\\ABCD\\Desktop", saveAs );
        //saving the image by writing on above file
        ImageIO.write(img, "png", saveImage);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X