【问题标题】:Applying a tint to an image in java在java中将色调应用于图像
【发布时间】:2010-11-22 17:11:51
【问题描述】:

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

【问题讨论】:

    标签: java image icons jcheckbox jradiobutton


    【解决方案1】:

    有一种方法,但您必须使用一些 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 会将您提供的颜色与源图像中的颜色进行异或。如果源图像是黑色的,那么您提供的任何颜色都将按照您指定的方式写入。对于 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() 方法进行一些更改即可使其正常工作。

    【讨论】:

    • 我可以将它用于Images 和ImageIcons 吗?
    • 同样ImageUtil.loadImage(String s)不存在
    • 唯一拥有它的标准 java 类是 com.sun.imageio.plugins.common.ImageUtil 并且没有 loadImage 方法
    • 好的,我做了更多的窥探,这就是我想出的: Image img = Toolkit.getDefaultToolkit().getImage(URL or file path);
    • 其他一切都应该差不多。
    【解决方案2】:

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

    这最适合我的情况。

    【讨论】:

      【解决方案3】:
      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());
              }
          }
      }
      

      【讨论】:

      • 我不想制作新的图像文件。我想在程序中给它上色
      • 如何从 Image 或 ImageIcon 中制作 BufferedImage?
      • 您创建一个相同大小和颜色分辨率的 BufferedImage。然后在 BufferedImage 上执行 getGraphics 并使用该图形上下文在其位置 0,0 处绘制 Image 或 ImageIcon。之后,您可以随意使用像素数据。
      【解决方案4】:

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

      【讨论】:

      • bi 代表什么?
      【解决方案5】:

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

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

      【讨论】:

      • 这不只是返回一个纯色的图像吗?
      • 不,如果你设置了 alpha,它会让它有点透视,所以不要将 alpha 设置为 255,而是将其设置为 100 之类的东西,它就可以正常工作了。
      • 如果我试图用 alpha 对图像进行着色,这将不起作用,因为这样会用这种半透明颜色填充透明区域
      • 这就是这个问题
      • 如果添加 alpha 合成,它会起作用。使用不同的选项检查 ((Graphics2D) g).setCompositr(...)。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

        • 这不起作用。而是产生 LSD 幻觉。
        • 嗯?可以发截图吗?我自己也用过这种方法……
        • 你的看起来像 this。我的(也不好)看起来像this。请注意,在您的解决方案中,红色的脸看起来不错,但它是一种简单的红色 (255, 0, 0)。其他颜色由于某种原因不起作用。原始(未着色)看起来像this
        • 我正在尝试为灰度图像添加颜色。
        • 你能发布你的 color() 方法调用吗?
        猜你喜欢
        • 1970-01-01
        • 2021-08-15
        • 2012-10-21
        • 2014-12-15
        • 2020-11-05
        • 1970-01-01
        • 2018-01-13
        • 2023-03-04
        • 2011-05-23
        相关资源
        最近更新 更多