J'ai deux BufferedImages j'ai chargé de pngs. Le premier contient une image, le second un masque alpha pour l'image.
Je veux créer une image combinée à partir des deux, en appliquant le masque alpha. Mon google-fu me fait défaut.
Je sais comment charger/enregistrer les images, il me faut juste le passage où je passe de deux BufferedImages à une BufferedImage avec le canal alpha droit.
Votre solution pourrait être améliorée en extrayant les données RVB de 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 Color à chaque itération de la boucle interne.
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 est-elle utile à quelqu'un de toute façon. Voici 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 d'un tableau au début, ne nécessitant qu'une boucle for. De plus, il déplace directement l'octet bleu en alpha (de la couleur du masque), au lieu de d'abord masquer l'octet rouge puis de le déplacer.
Comme les autres méthodes, cela suppose que les deux images ont les mêmes dimensions.
J'ai joué récemment un peu avec ce genre de choses, pour afficher une image sur l'autre, et à disparaître une image au gris.
Masquer également une image avec un masque transparent (version précédente de ce message!).
J'ai pris mon petit programme de test et l'ai légèrement modifié pour obtenir le résultat souhaité.
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 n'affiche que les images dans un petit panneau Swing.
Notez que l'image de masque est des niveaux de gris, noir devenant une transparence totale, blanc opaque devenant pleine.
Bien que vous ayez résolu votre problème, je pensais pouvoir vous donner mon point de vue. Il utilise un peu plus de méthode Java-ish, en utilisant des classes standard pour traiter/images de filtre.
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'il est plus rapide (pourrait être intéressant de mesurer les performances respectives), 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 façon de le faire fast, mais cela 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 l'alpha dans l'image d'origine.
J'ai écrit ce code dans Koltin, le point clé ici est que si vous avez l'alpha sur votre image d'origine, 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 Java (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);
}