¿Cómo se clona una imagen con búfer?

120

Tengo un objeto que tiene muchas imágenes en búfer, quiero crear un nuevo objeto copiando todas las imágenes en búfer en el nuevo objeto, pero estas nuevas imágenes pueden modificarse y no quiero que las imágenes del objeto original se alteren alterando el imágenes de nuevos objetos.

¿Está claro?

¿Es posible hacer esto y alguien puede sugerir una buena manera de hacerlo, por favor? He pensado en getSubImage, pero leí en alguna parte que cualquier cambio en la subimagen se refleja en la imagen principal.

Solo quiero poder obtener una copia o clon nueva completamente separada de un BufferedImage

f1wade
fuente
1
¿no puedes llamar al clone()método? ¿O me he perdido algo? No sé mucho sobre la BufferedImageclase
Noel M
1
clone solo proporciona una copia superficial para que contenga las referencias a las imágenes almacenadas en búfer; no copias de ellos.
Ultimate Gobblement
7
@NoelM, UltimateGobblement: BufferedImageno se implementa Cloneabley el clone()método tiene acceso protegido.
Robert

Respuestas:

173

¿Algo como esto?

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
fuente
4
También estoy tomando prestado esto en mi programa =)
Daniel Kats
tengo problemas con este método para copiar
subimagen
7
Si bien esto funciona en la mayoría de las circunstancias, no funciona correctamente cuando se ha recortado esa Imagen Buffered (devuelve la imagen completa antes de recortarla). Una solución simple para esto es cambiar la última línea a:
HaydenStudios
3
return new BufferedImage (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios
copyData (nulo) no siempre funciona porque puede funcionar en un ráster principal (es decir, cuando la imagen es una
subimagen
46

Hago esto:

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 bastante bien y es fácil de usar.

Una persona
fuente
3
Esto parece bastante simple. ¿Por qué esta no es la mejor respuesta? ¿Hay algún defecto del que no tenga conocimiento?
WVrock
2
@WVrock No funciona si el tipo de imagen es 0 (personalizado)
Tilman Hausherr
3
reemplazar Graphics g = b.getGraphics (); por Graphics2D g = b.createGraphics (); y es perfecto
Nadir
1
Creo que esta es la respuesta más limpia. Aunque, ¿hay alguna diferencia de rendimiento entre esto y la respuesta aceptada? Me siento insignificante si es que no? ¿Podría ser más rápido simplemente porque la creación de objetos está optimizada en el archivo jvm? También usando openjdk 11. Si alguien puede responder esa pregunta.
thekevshow
18

El procedimiento mencionado anteriormente falla cuando se aplica a subimágenes. Aquí hay una solución más 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);
}
usuario1050755
fuente
Gracias, estaba obteniendo un error de compensación al intentar clonar una subimagen. Esta versión es exactamente lo que necesitaba.
rococó
5

Otra forma es usar la Graphics2Dclase para dibujar la imagen en una nueva imagen en blanco. Esto realmente no clona la imagen, pero da como resultado una copia de la imagen que se produce.

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

Sé que esta pregunta es bastante antigua, pero para futuros visitantes, esta es la solución que usaría:

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

Por favor, corríjame si cambiar la que acaba de obtener newImagetambién afecta la imagen original de alguna manera.
-> Javadoc para getScaledInstance
-> Javadoc para SCALE_DEFAULT (las otras constantes se enumeran justo debajo de esa)

PixelMaster
fuente
Creo que en realidad no copiaría la imagen, es decir, si cambiaras el original, la escala también cambiará, pero ha pasado un tiempo, así que dejaré que alguien más lo diga con seguridad.
f1wade
1
Esto realmente copia la imagen, ya que los cambios en el original no cambiarán la copia. Esta respuesta es corta y concisa y ni siquiera se limita a BufferedImages. El único problema es que vuelve Image, no BufferedImage.
Kröw