Слияние двух изображений

Мне нужно объединить два изображения (BufferedImage) в Java. Это не было бы проблемой, если бы не было прозрачности. Базовое изображение уже имеет некоторую прозрачность. Я хочу сохранить это как есть и применить к нему "маску", второе изображение. Это второе изображение не имеет непрозрачных пикселей, фактически оно почти полностью прозрачно, просто имеет несколько менее прозрачных пикселей, чтобы создать некий "световой эффект", такой как рефлекс. Важная деталь: я не хочу делать это на экране, с графикой, мне нужно получить BufferedImage с результирующим слиянием.

Может кто-нибудь мне помочь? Спасибо!

ДЕТАЛИ: объедините два изображения, сохраняя прозрачность. Это то, что мне нужно сделать.

Примечание: эта альфа-маска Set BufferedImage в Java не делает то, что мне нужно, потому что она плохо обрабатывает два изображения с прозрачностью - она ​​изменяет прозрачность первого изображения.

3 ответа

Решение

Просто создайте новый BufferedImage с прозрачностью, затем нарисуйте два других изображения (с полной или полупрозрачностью) на нем. Вот как это будет выглядеть:

Имидж плюс наложение

Пример кода (изображения называются "image.png" и "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);

// Save as new image
ImageIO.write(combined, "PNG", new File(path, "combined.png"));

Объединить файлы любого типа по вертикали.

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

Я не могу дать вам конкретный ответ, но java.awt.AlphaComposite здесь ваш друг. Вы получите абсолютный контроль над слиянием двух изображений. Однако использовать его не просто - сначала нужно немного изучить теорию графики.

Не зная больше о том эффекте, которого вы пытаетесь достичь, я просто укажу, что вы также можете рисовать прямо на BufferedImage. Так что все, что вы можете сделать на экране, вы можете сделать прямо на самом изображении.

Так что, если все, что вам нужно, это нарисовать один поверх другого, это действительно легко. Просто возьмите объект Graphics для базового изображения и нарисуйте другой объект.

Опять же, в зависимости от того, какой именно эффект вы добьетесь, это может не сработать. Более подробная информация позволит лучше помочь. Например, является ли это заданием для AlphaComposite, как упоминает другой респондент, или пользовательским ImageOp (или некоторой комбинацией существующих ImageOps).

Другие вопросы по тегам