Domanda

Ho due immagini con buffer che ho caricato da pngs. Il primo contiene un'immagine, il secondo una maschera alfa per l'immagine.

Voglio creare un'immagine combinata dai due, applicando la maschera alfa. Il mio google-fu mi manca.

So come caricare / salvare le immagini, ho solo bisogno del bit in cui vado da due immagini con buffer a un'immagine con buffer con il canale alfa giusto.

È stato utile?

Soluzione

La tua soluzione potrebbe essere migliorata recuperando i dati RGB più di un pixel alla volta (vedi http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html ) e non creando tre colori oggetti su ogni iterazione del ciclo interno.

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

Altri suggerimenti

Sono troppo tardi con questa risposta, ma forse è comunque utile per qualcuno. Questa è una versione più semplice ed efficiente del metodo di 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);
}

All'inizio legge tutti i pixel in un array, richiedendo quindi un solo for-loop. Inoltre, sposta direttamente il byte blu sull'alfa (del colore della maschera), anziché prima mascherare il byte rosso e poi spostarlo.

Come gli altri metodi, presuppone che entrambe le immagini abbiano le stesse dimensioni.

Di recente ho giocato un po 'con queste cose, per visualizzare un'immagine su un'altra e per far sfumare un'immagine in grigio.
Anche mascherare un'immagine con una maschera con trasparenza (la mia versione precedente di questo messaggio!).

Ho preso il mio piccolo programma di test e l'ho modificato un po 'per ottenere il risultato desiderato.

Ecco i bit rilevanti:

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

Il resto mostra le immagini in un piccolo pannello Swing.
Si noti che l'immagine della maschera presenta livelli di grigio, il nero diventa completamente trasparente, il bianco diventa completamente opaco.

Anche se hai risolto il tuo problema, ho pensato di condividere la mia opinione. Utilizza un metodo leggermente più Java, usando le classi standard per elaborare / filtrare le immagini.
In realtà, il mio metodo utilizza un po 'più di memoria (creando un'immagine aggiuntiva) e non sono sicuro che sia più veloce (misurare le rispettive prestazioni potrebbe essere interessante), ma è leggermente più astratto.
Almeno, hai scelta! : -)

Per coloro che utilizzano l'alfa nell'immagine originale.

Ho scritto questo codice in Koltin, il punto chiave qui è che se hai l'alfa sulla tua immagine originale devi moltiplicare questi canali.

Versione 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)
    }

Versione Java (appena tradotta da 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);
    }

In realtà, l'ho capito. Questo probabilmente non è un modo veloce di farlo, ma funziona:

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());
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top