在java中对图像应用色调

发布于 2024-10-03 10:25:13 字数 176 浏览 0 评论 0原文

我试图为我的程序创建几种类似的视觉风格,每种风格都有不同的颜色主题。为此,我实现了使用图标来表示 JCheckBoxJRadioButton 的不同状态。我不需要为每种可能的颜色制作一整套图标,有什么方法可以在显示图像之前只使用一组并更改图像的色调/饱和度/亮度/alpha 吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

雄赳赳气昂昂 2024-10-10 10:25:13

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

首先,阅读本文以了解一些背景信息:http://www.javalobby.org/articles/ 接下来

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

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

,您需要创建一个新的 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;
}

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

编辑:

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

BufferedImage img = ImageIO.read(url); 

或者,您可以创建一个方法来使用 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;
}

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

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.

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

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

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

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

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.

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.html to load the file directly to a BufferedImage. The call would look something like this:

BufferedImage img = ImageIO.read(url); 

Alternatively, you can create a method to read the image using the 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 colorImage method to accept the Image object you only need to make a couple changes to the getWidth() and getHeight() methods to get it to work.

黯然#的苍凉 2024-10-10 10:25:13
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());
        }
    }
}
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());
        }
    }
}
深爱不及久伴 2024-10-10 10:25:13

计算每个颜色分量的平均值并保留原始 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);
        }
    }
}

这最适合我的情况。

To calculate average for each color component and keep original 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.

喜爱皱眉﹌ 2024-10-10 10:25:13

最简单的方法是使用 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;
}

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

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;
}
如歌彻婉言 2024-10-10 10:25:13

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

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

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;
}
那些过往 2024-10-10 10:25:13

我尝试了此页面上的所有解决方案,但没有运气。 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;
}

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!

/** 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;
}
你如我软肋 2024-10-10 10:25:13

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

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

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

此方法对于 alpha 值没有问题。

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 always stay 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.

This method has no problem with alpha values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文