Fusionando dos imágenes

84

Necesito fusionar dos imágenes (BufferedImage) en Java. No sería un problema si no hubiera transparencia. La imagen base ya tiene algo de transparencia. Quiero mantener esto como está y aplicarle una "máscara", la segunda imagen. Esta segunda imagen no tiene píxeles opacos, de hecho es casi completamente transparente, solo tiene algunos píxeles menos transparentes para dar una especie de "efecto de luz", como un reflejo. Detalle importante: no quiero hacer esto en la pantalla, con gráficos, necesito obtener una imagen de búfer con la combinación resultante.

¿Alguien puede ayudarme? ¡Gracias!

DETALLES: Fusiona dos imágenes manteniendo la transparencia. Esto es lo que necesito hacer.

Nota: esta máscara alfa de Set BufferedImage en Java no hace lo que necesito porque no se maneja bien con las dos imágenes que tienen transparencia; modifica la transparencia de la primera imagen.

GuilhermeA
fuente

Respuestas:

179

Simplemente cree una nueva imagen de búfer con transparencia, luego pinte las otras dos imágenes (con transparencia total o semitransparente) en ella. Así es como se verá:

Imagen más superposición

Código de muestra (las imágenes se denominan 'image.png' y 'overlay.png'):

File path = ... // base path of the images

// load source images
BufferedImage image = ImageIO.read(new File(path, "image.png"));
BufferedImage overlay = ImageIO.read(new File(path, "overlay.png"));

// create the new image, canvas size is the max. of both image sizes
int w = Math.max(image.getWidth(), overlay.getWidth());
int h = Math.max(image.getHeight(), overlay.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(image, 0, 0, null);
g.drawImage(overlay, 0, 0, null);

g.dispose();

// Save as new image
ImageIO.write(combined, "PNG", new File(path, "combined.png"));
Peter Walser
fuente
¿Hay alguna forma de tener la segunda imagen en el centro de la primera?
Ahmed
6
¿No debería invocar g.dispose (); ¿al final?
m-szalik
Hola, seguí este enfoque y guardé solo la segunda imagen, pero no la primera imagen ... Cualquier ayuda aquí sería apreciada ..
TP_JAVA
@Peter La imagen aparece atenuada cuando enderezo el archivo combinado como archivo jpeg. Por favor ayuda
Mohammed shebin
3

No puedo darte una respuesta específica, pero java.awt.AlphaComposite aquí es tu amigo. Obtendrá un control absoluto sobre cómo desea que se fusionen las dos imágenes. Sin embargo, no es fácil de usar; primero debe aprender un poco de teoría de gráficos.

Steve McLeod
fuente
3

Sin saber más sobre el efecto que está tratando de lograr, solo señalaré que también puede dibujar directamente en una imagen con búfer. Entonces, cualquier cosa que pueda hacer en la pantalla, puede hacerlo directamente en la imagen.

Entonces, si todo lo que quiere es uno encima del otro, es realmente fácil. Simplemente tome el objeto Graphics para la imagen base y dibuje el otro en él.

Nuevamente, dependiendo del efecto exacto que esté buscando, es posible que no funcione. Más detalles permitirían una mejor ayuda. Por ejemplo, ¿es este un trabajo para AlphaComposite como lo menciona el otro respondedor o un ImageOp personalizado (o alguna combinación de ImageOps existente)?

PSpeed
fuente
1

fusionar cualquier tipo de archivo verticalmente.

void mergeFiles(List<String> files, String fileName) {
        int heightTotal = 0;
        int maxWidth = 100;

        List<BufferedImage> images = new ArrayList<>();
        try {
            for (String file : files) {
                BufferedImage image = ImageIO.read(new File(file));
                images.add(image);
            }


        for (BufferedImage bufferedImage : images) {
            heightTotal += bufferedImage.getHeight();
            if (bufferedImage.getWidth() > maxWidth) {
                maxWidth = bufferedImage.getWidth();
            }
        }


        int heightCurr = 0;
        BufferedImage concatImage = new BufferedImage(maxWidth, heightTotal, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = concatImage.createGraphics();
        for (BufferedImage bufferedImage : images) {
            g2d.drawImage(bufferedImage, 0, heightCurr, null);
            heightCurr += bufferedImage.getHeight();
        }

        File compressedImageFile = new File(fileName);
        OutputStream outputStream = new FileOutputStream(compressedImageFile);

        float imageQuality = 0.7f;
        Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("jpeg");

        if (!imageWriters.hasNext())
            throw new IllegalStateException("Writers Not Found!!");

        ImageWriter imageWriter = imageWriters.next();
        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
        imageWriter.setOutput(imageOutputStream);

        ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();

        //Set the compress quality metrics
        imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        imageWriteParam.setCompressionQuality(imageQuality);

        //Created image
        imageWriter.write(null, new IIOImage(concatImage, null, null), imageWriteParam);

        // close all streams
        outputStream.close();
        imageOutputStream.close();
        imageWriter.dispose();
        log.info(" Files Merged");
        } catch (IOException e) {
            log.error("Error while merging files :::"+e);
            throw new RuntimeException(e);
        }
    }
Kumar Abhishek
fuente