Graying out a BufferedImage

吃可爱长大的小学妹 提交于 2021-01-27 13:21:55

问题


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.


回答1:


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.




回答2:


This is certainly not the most efficient way (as you have to iterate over every pixel in the image), but this code desaturates the source image and saves the result to a new file. Note that I have removed the scaling code to try and make things concise:

package com.mypkg;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;

public class Overlay
{
    private static int adjust_saturation(int argb, float factor)
    {
        float[] hsb = new float[3];

        // Extract out the components of the color from the 32 bit integer
        int alpha = (argb >> 24) & 0xff;
        int red   = (argb >> 16) & 0xff;
        int green = (argb >> 8) & 0xff;
        int blue  = argb & 0xff;

        // Converts RGB into HSB and fills the 'hsv' array with 3 elements:
        //
        // hsb[0] = hue
        // hsb[1] = saturation
        // hsb[2] = brightness
        Color.RGBtoHSB(red, green, blue, hsb);

        // Adjust the saturation as desired
        hsb[1] *= factor;

        // Convert back to RGB and return
        return Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
    }

    public static void main(String args[])
            throws MalformedURLException, IOException
    {
        URL url = new URL("my-input-file.jpg");
        BufferedImage image = ImageIO.read(url);

        // For every column
        for (int x = 0; x < image.getWidth(); x++) {
            // For every row
            for (int y = 0; y < image.getHeight(); y++) {
                // For each pixel of the image, grab the RGB (alpha, red, green, blue)
                int argb = image.getRGB(x, y);

                // Calculate a desaturated pixel and overwrite the current pixel
                // A value of 0.2 will desaturate by 80%, a value of 1.5 will
                // increase the saturation by 50%, etc.
                image.setRGB(x, y, adjust_saturation(argb, 0.2f));
            }
        }

        ImageIO.write(image, "png", new File("my-output-file.png"));
    }
}

And here are the results, original on the left, desaturated on the right:



来源:https://stackoverflow.com/questions/35947921/graying-out-a-bufferedimage

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!