代码之家  ›  专栏  ›  技术社区  ›  Ky -

在Java中对图像应用着色

  •  22
  • Ky -  · 技术社区  · 14 年前

    我正在尝试为我的程序创建几个类似的视觉样式,每个样式都有不同的颜色主题。为此,我已经实现了使用图标来表示 JCheckBox S和 JRadioButton S.除了为每种可能的颜色制作一套完整的图标,我有没有办法在显示图像之前只制作一套并更改图像的色调/饱和度/亮度/阿尔法?

    7 回复  |  直到 9 年前
        1
  •  13
  •   Berin Loritsch    14 年前

    有一种方法,但是您必须使用一些bufferedImage转换。一旦您创建了它们,就可以缓存它们或将它们保存下来,以便日后重用。从本质上讲,您希望从只使用alpha层关闭像素(也提供平滑的抗锯齿)的黑色图像(源颜色000000)开始。例如,在源图像中,每个像素都是黑色的,但是alpha通道在像素之间是不同的。

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

    一旦你完成了这个初级读物,你就需要将你的图像加载到一个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更新的IMAIO API: http://download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html 将文件直接加载到BufferedImage。电话看起来是这样的:

    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()方法进行几次更改即可使其正常工作。

        2
  •  4
  •   dacwe    14 年前
    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());
            }
        }
    }
    
        3
  •  3
  •   Oleg Mikhailov    9 年前

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

    这最适合我的情况。

        4
  •  2
  •   RocketRuwan    11 年前

    最简单的方法是使用 Image Filters by JH Labs . 您只需拨打

    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;
    }
    
        5
  •  1
  •   Mshnik    10 年前

    我试过这一页上的每一个解决方案,都没有运气。XORONE(公认的答案)对我不起作用——不管争论的内容如何,它的颜色都是一种奇怪的黄色,而不是我作为争论对象给出的颜色。我终于找到了一个适合我的方法,尽管有点混乱。我想我会添加它,以防其他人也有同样的问题,我与其他解决方案。干杯!

    /** 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;
    }
    
        6
  •  0
  •   APerson    12 年前

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

    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;
    }
    
        7
  •  0
  •   2xsaiko    10 年前

    因为我发现的所有方法都不适用于我,无论出于什么原因,这里有一个简单的方法来处理这个问题(不需要额外的libs):

    /**
     * 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的确切行为 GLCOLL3f() 方法。r、g和b参数必须为0.0f到1.0f。

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