【问题标题】:Set BufferedImage alpha mask in Java在 Java 中设置 BufferedImage alpha 掩码
【发布时间】:2010-09-18 07:42:21
【问题描述】:

我有两个从 png 加载的 BufferedImage。第一个包含图像,第二个包含图像的 alpha 蒙版。

我想通过应用 alpha 蒙版从两者中创建一个组合图像。我的 google-fu 让我失望了。

我知道如何加载/保存图像,我只需要从两个 BufferedImage 转到一个具有正确 Alpha 通道的 BufferedImage 的位。

【问题讨论】:

  • 我编辑了我的答案,以另一种方式给出正确的代码(按照你的要求做!)。

标签: java graphics alpha compositing


【解决方案1】:

这个答案我来得太晚了,但无论如何它可能对某人有用。这是 Michael Myers 方法的一个更简单、更高效的版本:

public void applyGrayscaleMaskToAlpha(BufferedImage image, BufferedImage mask)
{
    int width = image.getWidth();
    int height = image.getHeight();

    int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
    int[] maskPixels = mask.getRGB(0, 0, width, height, null, 0, width);

    for (int i = 0; i < imagePixels.length; i++)
    {
        int color = imagePixels[i] & 0x00ffffff; // Mask preexisting alpha
        int alpha = maskPixels[i] << 24; // Shift blue to alpha
        imagePixels[i] = color | alpha;
    }

    image.setRGB(0, 0, width, height, imagePixels, 0, width);
}

它在开始时将所有像素读入一个数组,因此只需要一个 for 循环。此外,它直接将蓝色字节转换为 alpha(掩码颜色),而不是先掩码红色字节然后再移位。

与其他方法一样,它假设两个图像具有相同的尺寸。

【讨论】:

    【解决方案2】:

    我最近玩了一下这个东西,将图像显示在另一个图像之上,并将图像淡化为灰色。
    还使用具有透明度的蒙版来蒙版图像(我之前版本的此消息!)。

    我使用了我的小测试程序并对其进行了一些调整以获得想要的结果。

    以下是相关位:

    TestMask() throws IOException
    {
        m_images = new BufferedImage[3];
        m_images[0] = ImageIO.read(new File("E:/Documents/images/map.png"));
        m_images[1] = ImageIO.read(new File("E:/Documents/images/mapMask3.png"));
        Image transpImg = TransformGrayToTransparency(m_images[1]);
        m_images[2] = ApplyTransparency(m_images[0], transpImg);
    }
    
    private Image TransformGrayToTransparency(BufferedImage image)
    {
        ImageFilter filter = new RGBImageFilter()
        {
            public final int filterRGB(int x, int y, int rgb)
            {
                return (rgb << 8) & 0xFF000000;
            }
        };
    
        ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
        return Toolkit.getDefaultToolkit().createImage(ip);
    }
    
    private BufferedImage ApplyTransparency(BufferedImage image, Image mask)
    {
        BufferedImage dest = new BufferedImage(
                image.getWidth(), image.getHeight(),
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = dest.createGraphics();
        g2.drawImage(image, 0, 0, null);
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.DST_IN, 1.0F);
        g2.setComposite(ac);
        g2.drawImage(mask, 0, 0, null);
        g2.dispose();
        return dest;
    }
    

    其余的只是在一个小的 Swing 面板中显示图像。
    请注意,蒙版图像是灰度级,黑色变为完全透明,白色变为完全不透明。

    虽然你已经解决了你的问题,但我可以分享我的看法。它使用了一种更类似于 Java 的方法,使用标准类来处理/过滤图像。
    实际上,我的方法使用了更多内存(制作额外的图像),我不确定它是否更快(测量各自的性能可能很有趣),但它稍微抽象一点。
    至少,你有选择! :-)

    【讨论】:

    • 哇,ApplyTransparency 方法让我很开心——在将一堆图像绘制到 Graphics2D 后,我需要对组件应用蒙版,而这正是我所需要的。谢谢!
    【解决方案3】:

    您的解决方案可以通过一次获取多个像素的 RGB 数据来改进(请参阅 http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html),并且不要在内循环的每次迭代中创建三个 Color 对象。

    final int width = image.getWidth();
    int[] imgData = new int[width];
    int[] maskData = new int[width];
    
    for (int y = 0; y < image.getHeight(); y++) {
        // fetch a line of data from each image
        image.getRGB(0, y, width, 1, imgData, 0, 1);
        mask.getRGB(0, y, width, 1, maskData, 0, 1);
        // apply the mask
        for (int x = 0; x < width; x++) {
            int color = imgData[x] & 0x00FFFFFF; // mask away any alpha present
            int maskColor = (maskData[x] & 0x00FF0000) << 8; // shift red into alpha bits
            color |= maskColor;
            imgData[x] = color;
        }
        // replace the data
        image.setRGB(0, y, width, 1, imgData, 0, 1);
    }
    

    【讨论】:

      【解决方案4】:

      对于那些在原始图像中使用 alpha 的人。

      我在 Koltin 中编写了这段代码,这里的关键点是,如果您的原始图像上有 alpha,则需要将这些通道相乘。

      科尔廷版本:

          val width = this.width
          val imgData = IntArray(width)
          val maskData = IntArray(width)
      
          for(y in 0..(this.height - 1)) {
      
            this.getRGB(0, y, width, 1, imgData, 0, 1)
            mask.getRGB(0, y, width, 1, maskData, 0, 1)
      
            for (x in 0..(this.width - 1)) {
      
              val maskAlpha = (maskData[x] and 0x000000FF)/ 255f
              val imageAlpha = ((imgData[x] shr 24) and 0x000000FF) / 255f
              val rgb = imgData[x] and 0x00FFFFFF
              val alpha = ((maskAlpha * imageAlpha) * 255).toInt() shl 24
              imgData[x] = rgb or alpha
            }
            this.setRGB(0, y, width, 1, imgData, 0, 1)
          }
      

      Java 版本(刚从 Kotlin 翻译过来的)

          int width = image.getWidth();
          int[] imgData = new int[width];
          int[] maskData = new int[width];
      
          for (int y = 0; y < image.getHeight(); y ++) {
      
              image.getRGB(0, y, width, 1, imgData, 0, 1);
              mask.getRGB(0, y, width, 1, maskData, 0, 1);
      
              for (int x = 0; x < image.getWidth(); x ++) {
      
                  //Normalize (0 - 1)
                  float maskAlpha = (maskData[x] & 0x000000FF)/ 255f;
                  float imageAlpha = ((imgData[x] >> 24) & 0x000000FF) / 255f;
      
                  //Image without alpha channel
                  int rgb = imgData[x] & 0x00FFFFFF;
      
                  //Multiplied alpha
                  int alpha = ((int) ((maskAlpha * imageAlpha) * 255)) << 24;
      
                  //Add alpha to image
                  imgData[x] = rgb | alpha;
              }
              image.setRGB(0, y, width, 1, imgData, 0, 1);
          }
      

      【讨论】:

        【解决方案5】:

        其实我已经想通了。这可能不是一种快速的方法,但它确实有效:

        for (int y = 0; y < image.getHeight(); y++) {
            for (int x = 0; x < image.getWidth(); x++) {
                Color c = new Color(image.getRGB(x, y));
                Color maskC = new Color(mask.getRGB(x, y));
                Color maskedColor = new Color(c.getRed(), c.getGreen(), c.getBlue(),
                    maskC.getRed());
                resultImg.setRGB(x, y, maskedColor.getRGB());
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多