Search code examples
javagraphics2d

Graying out a BufferedImage


I'm trying to gray out a BufferedImage (not convert it to gray scale, just add a gray tint on top). Right now, I'm doing this by using another image, make it translucent, and then overlay it on top of my original image. This is the code I have for now:

package com.mypkg;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;

import javax.imageio.ImageIO;

import org.imgscalr.Scalr;

public class Overlay {
    public static void main(String args[]){
        URL url = null;
        try{
            //The gray image used for overlay
            url = new URL("https://hoursofidleness.files.wordpress.com/2012/06/gray-card.jpg");
            BufferedImage img1 = ImageIO.read(url);

            //The original image which I want to gray out
            url = new URL("http://www.staywallpaper.com/wp-content/uploads/2016/01/Colorful-Wallpaper-HD-pictures-STAY015.jpg");
            BufferedImage img2 = ImageIO.read(url);
            BufferedImage reImg2 = Scalr.resize(img2, Scalr.Method.BALANCED, Scalr.Mode.FIT_EXACT, 150, 150);

            //Make the gray image, which is used as the overlay, translucent
            BufferedImage transparent = new BufferedImage(img1.getWidth(), img1.getHeight(),BufferedImage.TRANSLUCENT);
            Graphics2D g2d = transparent.createGraphics();
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) 0.50));
            g2d.drawImage(img1, null, 0, 0);
            g2d.dispose();
            BufferedImage reImg1 = Scalr.resize(transparent, Scalr.Method.BALANCED, Scalr.Mode.FIT_EXACT, 150, 150);

            //Merge both images
            BufferedImage result = new BufferedImage(150, 150, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = result.createGraphics();
            g.drawImage(reImg2, 0, 0, null);
            g.drawImage(reImg1, 0, 0, null);
            g.dispose();
            ImageIO.write(result,"png",new File("/result.png"));
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

Is there any other way to achieve this without using an additional image for overlay? Can I simply add a gray tint on top of my original image? I've tried many suggestions which I saw on other posts, but none of them work.

Thanks.


Solution

  • What your method basically does:

    • Loads a gray image, in which all the pixels have the same gray color.
    • Creates a new image.
    • Draws the gray image over that image so that it's half transparent.
    • Draws the half-transparent gray image over the image you want to gray out.

    First, there is no real need to create the transparent image. You can use the composite draw directly over the real image.

    Second, an image which is entirely gray is no different than a plain rectangle, and the Graphics2D class has a fillRect method that draws a filled rectangle, probably a lot faster than drawing an image.

    So, after you load and scale your original image into reImg2, you can use:

        Graphics2D g2d = reImg2.createGraphics();
        g2d.setColor(new Color(20,20,20,128));
        g2d.fillRect(0, 0, reImg2.getWidth(), reImg2.getHeight());
        g2d.dispose();
    

    That's it, now reImg2 is darkened and you can write it to your file. Play around with the values - change the 20s to lower value for a darker gray or higher value (up to 255) for lighter gray. Change the 128 (50% alpha) to higher value for a more grayed-out image or to lower value for a less grayed-out image.