在java中对图像应用色调

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

有一种方法,但你必须使用一些BufferedImage转换。 创建它们后,将它们缓存或保存,以便以后轻松重复使用。 基本上,您希望从黑色图像(源颜色#000000)开始,该图像仅使用alpha图层来关闭像素(还提供平滑的抗锯齿)。 例如,在源图像中,每个像素都是黑色,但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将使用源图像中的颜色对您提供的颜色进行异或。 如果源图像是黑色的,那么您指定的任何颜色都将在您指定时写入。 对于Alpha通道使用“0”的新颜色,将遵循原始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()方法进行一些更改即可使其工作。

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

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

这最适合我的情况。

最简单的方法是使用JH Labs的图像filter 。 你可以通过调用简单地调整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; } 

我试过这个页面上的每个解决方案,没有运气。 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; } 

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

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

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

 /** * 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值没有问题。