问题
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