Merging two images
Asked Answered
H

4

92

I need to merge two images (BufferedImage) in Java. It wouldn't be a problem if there was no transparency. The base image already has some transparency. I want to keep this as it is and apply a "mask" to it, the second image. This second image has no opaque pixels, in fact it's almost completely transparent, just has some less transparent pixels to give some sort of "light effect", like a reflex. Important detail: I don't want to do this on screen, with graphics, I need to obtain a BufferedImage with the resultant merge.

Can anyone help me? Thanks!

DETAILS: Merge two images maintaining transparency. This is what I need to do.

Note: this Set BufferedImage alpha mask in Java does not do what I need because it does not handle well with the two images having transparency - it modifies first picture transparency.

Hijoung answered 23/2, 2010 at 12:24 Comment(0)
I
208

Just create a new BufferedImage with transparency, then paint the other two images (with full or semi-transparency) on it. This is how it will look like:

Image plus overlay

Sample code (images are called 'image.png' and '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"));
Innis answered 23/2, 2010 at 15:21 Comment(5)
Is there way to have the second image at the center of the first?Englert
Shouldn't you invoke g.dispose(); at the end?Handkerchief
Hi, I followed this approach and saving only second image but not first image...Any help here would be appreciated..Clearsighted
@Peter The image is being greyed out when i right the combined file as jpeg file . Please helpPenland
@Mohammedshebin don't use jpgs, they are different don't handle transparencyCatalano
I
6

merge any type of file vertically.

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);
        }
    }
Instancy answered 18/2, 2020 at 13:19 Comment(1)
Pardon me, but what kind of java library "log" is? There is zillion of java libs having Log. Also Why to save as JPG when there might be PNG files having transparency - wouldn't be much better saving the file as transparent PNG then?Fremd
D
4

I can't give you a specific answer, but java.awt.AlphaComposite here is your friend. You'll get absolute control over how you want the two images to merge. However it is not straightforward to use - you need to learn a bit of graphics theory first.

Doyenne answered 23/2, 2010 at 12:43 Comment(0)
H
4

Without knowing more about the effect you are trying to achieve, I'll just point out that you can also draw right onto a BufferedImage. So anything you could do on screen you can do right on the image itself.

So if all you want is one drawn on top of the other, that's really easy. Just grab the Graphics object for the base image and draw the other onto it.

Again, depending on the exact effect you are going for that may not work. More detail would allow better help. For example, is this a job for AlphaComposite as the other responder mentions or a custom ImageOp (or some combination of existing ImageOps).

Hypocotyl answered 23/2, 2010 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.