BufferedImage-Alphamaske in Java festlegen

Lesezeit: 5 Minuten

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

BufferedImage Alphamaske in Java festlegen
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.

1641743446 753 BufferedImage Alphamaske in Java festlegen
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!

    – mvmn

    19. Dez. ’21 um 23:03

1641743446 616 BufferedImage Alphamaske in Java festlegen
Michael myers

Ihre Lösung könnte verbessert werden, indem Sie die RGB-Daten mehr als ein Pixel gleichzeitig abrufen (siehe http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html) und indem nicht bei jeder Iteration der inneren Schleife drei Color-Objekte erstellt werden.

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

.

222780cookie-checkBufferedImage-Alphamaske in Java festlegen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy