Mettre le masque alpha de BufferedImage en Java
j'ai deux tampons que j'ai chargés depuis pngs. La première contient une image, la seconde un masque alpha pour l'image.
je veux créer une image combinée des deux, en appliquant le masque alpha. Mon google-fu me lâche.
je sais comment charger/enregistrer les images, j'ai juste besoin du bit où je passe de deux BufferedImages à un BufferedImage avec le canal alpha droit.
5 réponses
votre solution pourrait être améliorée en récupérant les données RVB plus d'un pixel à la fois(voir http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html ), et en ne créant pas trois objets de couleur à chaque itération de la boucle intérieure.
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);
}
je suis trop en retard avec cette réponse, mais peut-être qu'elle est utile pour quelqu'un de toute façon. C'est une version plus simple et plus efficace de la méthode de 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);
}
il lit tous les pixels dans un tableau au début, n'exigeant donc qu'une seule boucle. En outre, il déplace directement le byte bleu à l'alpha (de la couleur du masque), au lieu de masquer d'abord le byte rouge et puis le déplacer.
comme les autres méthodes, il suppose les deux images ont les mêmes dimensions.
j'ai récemment joué un peu avec ce truc, pour afficher une image sur une autre, et pour faire passer une image en gris.
Aussi masquer une image avec un masque avec transparence (ma version précédente de ce message!).
j'ai pris mon petit programme de test et modifié un peu pour obtenir le résultat voulu.
Voici les bits pertinents:
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;
}
le reste affiche juste les images dans un petit Swing panneau.
Notez que l'image du masque est de niveaux gris, noir devenant pleine transparence, Blanc devenant pleinement opaque.
bien que vous ayez résolu votre problème, je pensais pouvoir partager mon point de vue. Il utilise une méthode légèrement plus Java-ish, en utilisant des classes standard pour traiter / filtrer les images.
En fait, ma méthode utilise un peu plus de mémoire (faire une image supplémentaire) et je ne suis pas sûr qu'elle soit plus rapide (mesurer les performances respectives pourrait être intéressant), mais il est un peu plus abstrait.
Au moins, vous avez le choix! :- )
en fait, je l'ai compris. Ce n'est probablement pas une rapide façon de le faire, mais il fonctionne:
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());
}
}
pour ceux qui utilisent alpha dans l'image originale.
j'ai écrit ce code dans Koltin, le point clé ici est que si vous avez l'alpha sur votre image originale vous devez multiplier ces canaux.
Koltin Version:
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)
}
version de Java (juste traduit de 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);
}