2008-10-21 73 views
19

我有两个从pngs加载的BufferedImages。第一个包含一个图像,第二个包含图像的alpha蒙版。在Java中设置BufferedImage alpha掩码

我想通过应用alpha蒙版来从这两者创建组合图像。我的google-fu失败了。

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

+0

我编辑我的回答给一个正确的代码(做你要求什么!)以另一种方式。 – PhiLho 2008-10-21 15:20:24

回答

9

您可以通过一次获取多于一个像素的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); 
} 
0

其实,我已经想通了。这可能不是做这件事的快速的方式,但它的工作原理:

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

我最近在玩了一下这个东西,显示了一个又一个的图像,以及褪色的图像为灰色。
也用一个透明的面具(我以前的版本的消息!)掩盖图像。

我把我的小测试程序,并调整了一下,得到想要的结果。

下面是相关位:

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-ish方法,使用标准类来处理/过滤图像。实际上,我的方法使用了更多的内存(制作一个额外的图像),我不确定它是否更快(测量各自的表现可能很有趣),但它稍微抽象一些。
至少,你有选择! :-)

21

我这个答案为时已晚,但也许是使用了别人的反正。这是迈克尔迈尔斯的方法的更简单和更有效的版本:

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(掩码颜色的),而不是首先屏蔽红色字节,然后移动它。

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

0

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

我在Koltin写了这段代码,这里的关键是如果你的原始图像上有alpha,你需要乘这些通道。

Koltin版本:

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版本(从科特林只是翻译)

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