Como você clona um BufferedImage

120

Eu tenho um objeto que tem muitas imagens em buffer, quero criar um novo objeto copiando todas as imagens em buffer para o novo objeto, mas essas novas imagens podem ser alteradas e não quero que as imagens do objeto original sejam alteradas alterando o novas imagens de objetos.

está claro?

Isso é possível e alguém pode sugerir uma boa maneira de fazê-lo, por favor? Eu pensei em getSubImage, mas li em algum lugar que quaisquer alterações na subimagem são refletidas de volta na imagem pai.

Eu só quero ser capaz de obter uma cópia totalmente separada ou clone de um BufferedImage

f1wade
fonte
1
você não pode chamar o clone()método? Ou eu perdi alguma coisa? Não sei muito sobre a BufferedImageaula
Noel M
1
clone fornece apenas uma cópia superficial para conter as referências às imagens armazenadas em buffer; não cópias deles.
Ultimate Gobblement
7
@NoelM, UltimateGobblement: BufferedImagenão implementa Cloneablee o clone()método tem acesso protegido.
Robert de

Respostas:

173

Algo assim?

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
fonte
4
Também estou pegando emprestado no meu programa =)
Daniel Kats
tenho problemas com este método na cópia de subimagem
mishka
7
Embora isso funcione na maioria das circunstâncias, não funciona corretamente quando o BufferedImage foi cortado (ele retorna a imagem inteira antes de ser cortada). Uma solução simples para isso é alterar a última linha para:
HaydenStudios
3
retornar novo BufferedImage (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios
copyData (null) nem sempre funciona porque pode funcionar em um raster pai (ou seja, quando a imagem é uma
subimagem
46

Eu faço isso:

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

Funciona muito bem e é simples de usar.

Uma pessoa
fonte
3
Isso parece muito simples. Por que essa não é a melhor resposta? Existe uma falha da qual não estou ciente?
WVrock
2
@WVrock Não funciona se o tipo de imagem for 0 (personalizado)
Tilman Hausherr
3
substituir Graphics g = b.getGraphics (); por Graphics2D g = b.createGraphics (); e é perfeito
Nadir
1
Acho que esta é a resposta mais limpa. Embora haja alguma diferença de desempenho entre esta e a resposta aceita? Eu me sinto insignificante se houver não? Isso poderia ser mais rápido porque a criação do objeto é otimizada no jvm. Também usando openjdk 11. Se alguém puder responder a essa pergunta.
thekevshow
18

O procedimento mencionado anteriormente falha quando aplicado a sub-imagens. Aqui está uma solução mais 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);
}
user1050755
fonte
Obrigado, estava recebendo um erro de deslocamento ao tentar clonar uma subimagem. Esta versão é exatamente o que eu precisava.
rococó
5

Outra maneira é usar a Graphics2Dclasse para desenhar a imagem em uma nova imagem em branco. Isso realmente não clona a imagem, mas resulta em uma cópia da imagem sendo produzida.

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
fonte
4

Eu sei que essa questão é muito antiga, mas para futuros visitantes, aqui está a solução que eu usaria:

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

Por favor, corrija-me se a alteração do recém-obtido newImagetambém afeta a imagem original de alguma forma.
-> Javadoc para getScaledInstance
-> Javadoc para SCALE_DEFAULT (as outras constantes estão listadas logo abaixo dessa)

PixelMaster
fonte
Eu acho que não iria realmente copiar a imagem, ou seja, se você alterou o original a escala também irá mudar, mas já faz um tempo tão mal que alguém diga com certeza.
f1wade
1
Isso realmente copia a imagem, pois as alterações no original não alteram a cópia. Essa resposta é curta e concisa e não se limita nem ao BufferedImages. O único problema é que ele retorna Image, não BufferedImage.
Kröw