Ich habe zwei BufferedImages, die ich aus PNGs geladen habe. Der erste enthält ein Bild, der zweite eine Alphamaske für das Bild.
Ich möchte ein kombiniertes Bild aus den beiden erstellen, indem ich die Alphamaske anwende. Mein Google-Fu versagt bei mir.
Ich weiß, wie man die Bilder lädt/speichert, ich brauche nur das Bit, wo ich von zwei BufferedImages zu einem BufferedImage mit dem richtigen Alphakanal gehe.
Ich habe meine Antwort bearbeitet, um auf alternative Weise einen korrekten Code anzugeben (und das zu tun, was Sie angefordert haben!).
– Philho
21. Okt. 08 um 15:20 Uhr
Meyer
Ich bin mit dieser Antwort zu spät, aber vielleicht nützt sie trotzdem jemandem. Dies ist eine einfachere und effizientere Version der Methode von 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);
}
Es liest am Anfang alle Pixel in ein Array ein und benötigt somit nur eine for-Schleife. Außerdem wird das blaue Byte direkt zum Alpha (der Maskenfarbe) verschoben, anstatt zuerst das rote Byte zu maskieren und dann zu verschieben.
Wie bei den anderen Methoden wird davon ausgegangen, dass beide Bilder die gleichen Abmessungen haben.
PhiLho
Ich habe vor kurzem ein bisschen mit diesem Zeug gespielt, um ein Bild über einem anderen anzuzeigen und ein Bild in Grau zu überblenden.
Maskieren Sie auch ein Bild mit einer Maske mit Transparenz (meine vorherige Version dieser Nachricht!).
Ich nahm mein kleines Testprogramm und optimierte es ein wenig, um das gewünschte Ergebnis zu erzielen.
Hier die relevanten Bits:
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;
}
Der Rest zeigt nur die Bilder in einem kleinen Swing-Panel an.
Beachten Sie, dass das Maskenbild aus Graustufen besteht, wobei Schwarz vollständig transparent wird und Weiß vollständig undurchsichtig wird.
Obwohl Sie Ihr Problem gelöst haben, könnte ich meine Meinung dazu teilen. Es verwendet eine etwas mehr Java-artige Methode, bei der Standardklassen verwendet werden, um Bilder zu verarbeiten/zu filtern.
Tatsächlich verbraucht meine Methode etwas mehr Speicher (erzeugt ein zusätzliches Bild) und ich bin mir nicht sicher, ob sie schneller ist (die Messung der jeweiligen Leistung könnte interessant sein), aber sie ist etwas abstrakter.
Zumindest hast du die Wahl! 🙂
Wow, die ApplyTransparency-Methode hat mir gerade den Tag versüßt – ich musste einer Komponente eine Maske zuweisen, nachdem ich eine Reihe von Bildern in Graphics2D gezeichnet hatte, und das ist genau das, was ich brauchte. Danke!
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);
}
Für diejenigen, die Alpha im Originalbild verwenden.
Ich habe diesen Code in Koltin geschrieben. Der entscheidende Punkt hier ist, dass Sie diese Kanäle multiplizieren müssen, wenn Sie das Alpha auf Ihrem Originalbild haben.
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)
}
Java-Version (gerade aus Kotlin übersetzt)
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);
}
Eigentlich habe ich es herausgefunden. Dies ist wahrscheinlich kein schnell Vorgehensweise, aber es funktioniert:
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());
}
}
.
2227800cookie-checkBufferedImage-Alphamaske in Java festlegenyes
Ich habe meine Antwort bearbeitet, um auf alternative Weise einen korrekten Code anzugeben (und das zu tun, was Sie angefordert haben!).
– Philho
21. Okt. 08 um 15:20 Uhr