在java中将色调应用于图像

在java中将色调应用于图像,java,image,icons,jcheckbox,jradiobutton,Java,Image,Icons,Jcheckbox,Jradiobutton,我正在尝试为我的程序创建几个类似的视觉样式,每个都有不同的颜色主题。为此,我实现了使用图标来表示JCheckBoxs和JRadioButtons的不同状态。除了为每种可能的颜色制作一套完整的图标外,还有什么方法可以让我在显示之前只制作一套并更改图像的色调/饱和度/亮度/alpha吗?有一种方法,但您必须使用一些BuffereImage转换。创建它们之后,请缓存它们或保存它们,以便以后可以轻松重用。基本上,您希望从一个仅使用alpha层关闭像素的黑色图像(源颜色#000000)开始(还提供平滑的抗

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

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

首先,阅读本文了解一些背景信息:

一旦完成该初级读物,您需要将图像加载到BuffereImage中:

BufferedImage loadImg = ImageUtil.loadImage("C:/Images/myimg.png");
接下来,您需要创建一个新的BuffereImage,以便将转换为:

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;
}
本质上,setXORMode将对您提供的颜色与源图像中的颜色进行异或。如果源图像是黑色的,那么您提供的任何颜色都将按照您指定的颜色写入。对于alpha通道使用“0”的新颜色,将遵守原始alpha通道值。最终的结果就是你要寻找的复合材料

编辑:

您可以通过以下两种方式之一加载初始BuffereImage。最简单的方法是使用Java较新的ImageIO API:将文件直接加载到BuffereImage。这个电话看起来像这样:

BufferedImage img = ImageIO.read(url); 
或者,您可以创建一个方法来使用工具箱读取图像

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;
}
当然,如果你注意的话,我们必须做同样的事情,将图像读入缓冲图像,就像我们对其着色一样。简而言之,如果您更改了
colorImage
方法的签名以接受
Image
对象,则只需对getWidth()和getHeight()方法进行几次更改即可使其正常工作。

公共静态无效色调(BuffereImage img){
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());
        }
    }
}
对于(int x=0;x
这不完全是着色,它更像是在其上应用另一层,但它对我有效:

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;
}

最简单的方法是使用。您只需通过调用

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;
}

我尝试了这一页上的每一个解决方案,但没有成功。Xor one(被接受的答案)对我不起作用——它用了一种奇怪的黄色,而不是我作为论点给出的颜色,不管论点是什么。我终于找到了一种适合我的方法,尽管它有点混乱。我想我会加上它,以防其他人也遇到与其他解决方案相同的问题。干杯

/** 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;
}
/**使用给定颜色着色给定图像。
*@param loadImg-要绘制和着色的图像
*@param color-要着色的颜色。未使用输入颜色的Alpha值。
*@返回loadImg的着色版本*/
公共静态缓冲区图像色调(缓冲区图像加载img,颜色){
BuffereImage img=新的BuffereImage(loadImg.getWidth(),loadImg.getHeight(),
缓冲图像(半透明);
最终不透明度=0.45f;
Graphics2D g2d=img.createGraphics();
//绘制基础图像
g2d.drawImage(loadImg,null,0,0);
//将颜色设置为输入颜色的透明版本
g2d.setColor(新颜色(Color.getRed()/255f,Color.getGreen()/255f,
color.getBlue()/255f,tintpacity));
//迭代每个像素,如果它不是透明的,则在其上绘制
光栅数据=loadImg.getData();
对于(int x=data.getMinX();x0){//如果像素不是完整的alpha。也可以是像素[3]==255
g2d.fillRect(x,y,1,1);
}
}
}
g2d.dispose();
返回img;
}

因为我发现的所有方法无论出于何种原因都不适用于我,所以这里有一个简单的方法来实现这一点(不需要额外的LIB):

/**
*使用指定的颜色为图像着色。
*@param r红色值。介于0和1之间
*@param g绿色值。介于0和1之间
*@param b蓝色值。介于0和1之间
*@param src将图像设置为彩色
*@返回彩色图像
*/
受保护的BuffereImage颜色(浮点r、浮点g、浮点b、BuffereImage src){
//复制图像(谁把它弄得如此复杂:<)
BuffereImage newImage=新的BuffereImage(src.getWidth(),src.getHeight(),BuffereImage.半透明);
Graphics2D graphics=newImage.createGraphics();
graphics.drawImage(src,0,0,null);
graphics.dispose();
//彩色图像
对于(int i=0;i/**
 * 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;
}
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);
        }
    }
}