我有两个从png文件中载入的BufferedImage。第一个包含图像,第二个包含图像的alpha掩码。
我想通过应用alpha掩码来创建一个合并后的图像。但是我的谷歌搜索失败了。
我知道如何加载/保存图像,我只需要知道如何将两个BufferedImage转换为一个具有正确alpha通道的BufferedImage。
我有两个从png文件中载入的BufferedImage。第一个包含图像,第二个包含图像的alpha掩码。
我想通过应用alpha掩码来创建一个合并后的图像。但是我的谷歌搜索失败了。
我知道如何加载/保存图像,我只需要知道如何将两个BufferedImage转换为一个具有正确alpha通道的BufferedImage。
我回答晚了,但也许对某些人有用。这是 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(掩码颜色的)位置,而不是先屏蔽红色字节再将其移动。
和其他方法一样,它假设两个图像具有相同的尺寸。
最近我在尝试使用这种方法,将一张图片展示在另一张图片上,并将一张图片变为灰色。
同时,使用透明度遮罩来遮盖一张图片(这是我先前版本信息的描述!)。
我拿出我的小测试程序并进行了调整,以获得想要的结果。
以下是相关部分:
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风格的方法,使用标准类来处理/过滤图像。
实际上,我的方法使用了更多的内存(创建了额外的图像),而且我不确定它是否更快(比较各自的性能可能会很有趣),但它稍微更抽象一些。
至少,你有选择!:-)
你的解决方案可以通过一次获取多个像素的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);
}
对于那些使用原始图片中的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版本(由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);
}
其实,我已经想出来了。这可能不是一个快速的方法,但它能够正常工作:
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());
}
}