java 在java中对图像应用色调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4248104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 05:30:43  来源:igfitidea点击:

Applying a tint to an image in java

javaimageiconsjcheckboxjradiobutton

提问by Supuhstar

I am trying to create several similar visual styles for my programs, each with a different color theme. To do this, I have implemented the use of icons to represent the different states of JCheckBoxs and JRadioButtons. Instead of making one full set of icons for every possible color, is there any way I can just take one set and change the hue/saturation/luminosity/alpha of the image before displaying it?

我正在尝试为我的程序创建几种类似的视觉样式,每种样式都有不同的颜色主题。为此,我实现了使用图标来表示JCheckBoxs 和JRadioButtons的不同状态。除了为每种可能的颜色制作一套完整的图标之外,有什么方法可以让我在显示之前只使用一组并更改图像的色调/饱和度/亮度/阿尔法?

采纳答案by Berin Loritsch

There is a way, but you'll have to make use of some BufferedImage transformations. Once you create them, cache them or save them off to be easily reused later. Essentially, you want to start off with a black image (source color #000000) that only uses the alpha layer to turn off pixels (also providing smooth anti-aliasing). For example, in your source image, every pixel is black, but the alpha channel differs from pixel to pixel.

有一种方法,但您必须使用一些 BufferedImage 转换。创建它们后,将它们缓存或保存以便以后轻松重用。本质上,您希望从仅使用 alpha 层关闭像素(也提供平滑的抗锯齿)的黑色图像(源颜色 #000000)开始。例如,在您的源图像中,每个像素都是黑色的,但 Alpha 通道因像素而异。

First, read this article for some background information: http://www.javalobby.org/articles/ultimate-image/

首先,阅读这篇文章了解一些背景信息:http: //www.javalobby.org/articles/ultimate-image/

Once you get done with that primer, you need to load your image into a BufferedImage:

完成该入门后,您需要将图像加载到 BufferedImage 中:

BufferedImage loadImg = ImageUtil.loadImage("C:/Images/myimg.png");

Next you need to create a new BufferedImage to make the transform into:

接下来,您需要创建一个新的 BufferedImage 来进行转换:

public BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue) {
    BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
        BufferedImage.TRANSLUCENT);
    Graphics2D graphics = img.createGraphics(); 
    Color newColor = new Color(red, green, blue, 0 /* alpha needs to be zero */);
    graphics.setXORMode(newColor);
    graphics.drawImage(loadImg, null, 0, 0);
    graphics.dispose();
    return img;
}

Essentially, the setXORMode will XOR the color you provide with the color in the source image. If the source image is black, then whatever color you provide will be written as you specify it. With the new color using "0" for the alpha channel, the original alpha channel values will be respected. The end result is the composite you are looking for.

本质上,setXORMode 会将您提供的颜色与源图像中的颜色进行异或。如果源图像是黑色,那么您提供的任何颜色都将按照您指定的方式写入。对于 Alpha 通道使用“0”的新颜色,将遵守原始 Alpha 通道值。最终结果是您正在寻找的复合材料。

Edit:

编辑:

You can load the initial BufferedImage in one of two ways. The easiest is to use Java's newer ImageIO API: http://download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.htmlto load the file directly to a BufferedImage. The call would look something like this:

您可以通过以下两种方式之一加载初始 BufferedImage。最简单的方法是使用 Java 较新的 ImageIO API:http: //download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html将文件直接加载到 BufferedImage。调用看起来像这样:

BufferedImage img = ImageIO.read(url); 

Alternatively, you can create a method to read the image using the ToolKit.

或者,您可以创建一个使用 ToolKit 读取图像的方法。

public BufferedImage loadImage(String url) {
    ImageIcon icon = new ImageIcon(url);
    Image image = icon.getImage();

    // Create empty BufferedImage, sized to Image
    BufferedImage buffImage = 
      new BufferedImage(
        image.getWidth(null), 
        image.getHeight(null), 
        BufferedImage.TYPE_INT_ARGB);

    // Draw Image into BufferedImage
    Graphics g = buffImage.getGraphics();
    g.drawImage(image, 0, 0, null);
    return buffImage;
}

Of course, if you pay attention, we have to do the exact same thing to read the image into a buffered image as we do to tint it. In short, if you changed the signature of the colorImagemethod to accept the Imageobject you only need to make a couple changes to the getWidth() and getHeight() methods to get it to work.

当然,如果您注意的话,我们必须做与着色图像完全相同的事情来将图像读入缓冲图像。简而言之,如果您更改了colorImage方法的签名以接受Image对象,您只需要对 getWidth() 和 getHeight() 方法进行一些更改即可使其工作。

回答by dacwe

public static void tint(BufferedImage img) {

    for (int x = 0; x < img.getWidth(); x++) {
        for (int y = 0; y < img.getHeight(); y++) {

            Color color = new Color(img.getRGB(x, y));

            // do something with the color :) (change the hue, saturation and/or brightness)
            // float[] hsb = new float[3];
            // Color.RGBtoHSB(color.getRed(), old.getGreen(), old.getBlue(), hsb);

            // or just call brighter to just tint it
            Color brighter = color.brighter();

            img.setRGB(x, y, brighter.getRGB());
        }
    }
}

回答by Oleg Mikhailov

To calculate average for each color component and keep original alpha:

要计算每个颜色分量的平均值并保持原始 alpha:

public static void tint(BufferedImage image, Color color) {
    for (int x = 0; x < image.getWidth(); x++) {
        for (int y = 0; y < image.getHeight(); y++) {
            Color pixelColor = new Color(image.getRGB(x, y), true);
            int r = (pixelColor.getRed() + color.getRed()) / 2;
            int g = (pixelColor.getGreen() + color.getGreen()) / 2;
            int b = (pixelColor.getBlue() + color.getBlue()) / 2;
            int a = pixelColor.getAlpha();
            int rgba = (a << 24) | (r << 16) | (g << 8) | b;
            image.setRGB(x, y, rgba);
        }
    }
}

This works best for my case.

这最适合我的情况。

回答by RocketRuwan

The easiest way to do this would be by using the Image Filters by JH Labs. You can simply adjust HSB by calling,

最简单的方法是使用JH Labs图像过滤器。您可以通过调用简单地调整 HSB,

public BufferedImage setHSB(BufferedImage source, float hValue, float sValue, float bValue) {        
    com.jhlabs.image.HSBAdjustFilter hsb hsb = new HSBAdjustFilter();
    BufferedImage destination = hsb.createCompatibleDestImage(source, null);
    hsb.setHFactor(hValue);
    hsb.setSFactor(sValue);
    hsb.setBFactor(bValue);
    BufferedImage result = hsb.filter(bi, destination);

    return result;
}

回答by Mshnik

I tried every solution on this page, had no luck. The Xor one (accepted answer) didn't work for me - tinted a weird yellow color instead of the color I was giving as an argument no matter what the argument. I finally found an approach that works for me, though it is a bit messy. Figured I'd add it in case anyone else is having the same issues I am with the other solutions. Cheers!

我尝试了此页面上的所有解决方案,但没有运气。Xor 一个(接受的答案)对我不起作用 - 用奇怪的黄色代替我作为论点给出的颜色,无论论点是什么。我终于找到了一种对我有用的方法,虽然它有点乱。想我会添加它,以防其他人遇到与其他解决方案相同的问题。干杯!

/** Tints the given image with the given color.
 * @param loadImg - the image to paint and tint
 * @param color - the color to tint. Alpha value of input color isn't used.
 * @return A tinted version of loadImg */
public static BufferedImage tint(BufferedImage loadImg, Color color) {
    BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
            BufferedImage.TRANSLUCENT);
    final float tintOpacity = 0.45f;
    Graphics2D g2d = img.createGraphics(); 

    //Draw the base image
    g2d.drawImage(loadImg, null, 0, 0);
    //Set the color to a transparent version of the input color
    g2d.setColor(new Color(color.getRed() / 255f, color.getGreen() / 255f, 
        color.getBlue() / 255f, tintOpacity));

    //Iterate over every pixel, if it isn't transparent paint over it
    Raster data = loadImg.getData();
    for(int x = data.getMinX(); x < data.getWidth(); x++){
        for(int y = data.getMinY(); y < data.getHeight(); y++){
            int[] pixel = data.getPixel(x, y, new int[4]);
            if(pixel[3] > 0){ //If pixel isn't full alpha. Could also be pixel[3]==255
                g2d.fillRect(x, y, 1, 1);
            }
        }
    }
    g2d.dispose();
    return img;
}

回答by APerson

This isn't exactly tinting, its more like applying another layer on it but it works for me:

这不是完全着色,它更像是在其上应用另一层,但它对我有用:

public static BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue, int alpha /*Also the intesity*/) {
    Graphics g = loadImg.getGraphics();
    g.setColor(new Color(red, green, blue, alpha));
    g.fillRect(0, 0, loadImg.getWidth(), loadImg.getHeight());
    g.dispose();
    return loadImg;
}

回答by 2xsaiko

Because all methods I found didn't work for me for whatever reason, here is an easy way to approach this (no extra libs needed):

因为我发现的所有方法无论出于何种原因都不适合我,这里有一个简单的方法来解决这个问题(不需要额外的库):

/**
 * Colors an image with specified color.
 * @param r Red value. Between 0 and 1
 * @param g Green value. Between 0 and 1
 * @param b Blue value. Between 0 and 1
 * @param src The image to color
 * @return The colored image
 */
protected BufferedImage color(float r, float g, float b, BufferedImage src) {

    // Copy image ( who made that so complicated :< )
    BufferedImage newImage = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TRANSLUCENT);
    Graphics2D graphics = newImage.createGraphics();
    graphics.drawImage(src, 0, 0, null);
    graphics.dispose();

    // Color image
    for (int i = 0; i < newImage.getWidth(); i++) {
        for (int j = 0; j < newImage.getHeight(); j++) {
            int ax = newImage.getColorModel().getAlpha(newImage.getRaster().getDataElements(i, j, null));
            int rx = newImage.getColorModel().getRed(newImage.getRaster().getDataElements(i, j, null));
            int gx = newImage.getColorModel().getGreen(newImage.getRaster().getDataElements(i, j, null));
            int bx = newImage.getColorModel().getBlue(newImage.getRaster().getDataElements(i, j, null));
            rx *= r;
            gx *= g;
            bx *= b;
            newImage.setRGB(i, j, (ax << 24) | (rx << 16) | (gx << 8) | (bx << 0));
        }
    }
    return newImage;
}

A black image will alwaysstay black, but a white image will be the color you specify. This method goes through every pixel and multiply the red green and blue values of the image with parameters. This is the exact behavior of the OpenGL glColor3f()method. R, G and B params must be 0.0F to 1.0F.

黑色图像将始终保持黑色,但白色图像将是您指定的颜色。该方法遍历每个像素并将图像的红绿蓝值与参数相乘。这是 OpenGL glColor3f()方法的确切行为。R、G 和 B 参数必须在 0.0F 到 1.0F 之间。

This method has no problem with alpha values.

这种方法对 alpha 值没有问题。