21

pngからロードしたBufferedImagesが2つあります。1つ目は画像を含み、2つ目は画像のアルファマスクです。

アルファマスクを適用して、2つから組み合わせた画像を作成したいと思います。私のgoogle-fuは私に失敗します。

画像をロード/保存する方法を知っています。2つのBufferedImagesから正しいアルファチャネルを持つ1つのBufferedImageに移動するビットが必要です。

4

5 に答える 5

22

私はこの答えに遅すぎますが、とにかく誰かに役立つかもしれません. これは、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);
}

最初にすべてのピクセルを配列に読み込むため、必要な for ループは 1 つだけです。また、最初に赤のバイトをマスクしてからシフトするのではなく、青のバイトを (マスク色の) アルファに直接シフトします。

他の方法と同様に、両方の画像の寸法が同じであると想定しています。

于 2011-11-08T23:24:14.703 に答える
13

私は最近、このようなもので少し遊んで、画像を別の画像の上に表示し、画像を灰色にフェードさせました。
また、透明度のあるマスクで画像をマスキングします(このメッセージの以前のバージョンです!)。

私は小さなテスト プログラムを使用して、必要な結果が得られるように少し調整しました。

関連するビットは次のとおりです。

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

残りは、小さな Swing パネルに画像を表示するだけです。
マスク イメージはグレー レベルであり、黒が完全に透明になり、白が完全に不透明になることに注意してください。

あなたはあなたの問題を解決しましたが、私はそれについて私の見解を共有することができます. 標準クラスを使用して画像を処理/フィルタリングする、もう少し Java っぽい方法を使用します。
実際、私の方法はもう少し多くのメモリを使用し (追加の画像を作成する)、高速かどうかはわかりません (それぞれのパフォーマンスを測定するのは興味深いかもしれません) が、少し抽象的です。
少なくとも、あなたには選択肢があります!:-)

于 2008-10-21T14:02:08.793 に答える
10

RGB データを一度に 1 ピクセル以上フェッチすることで ( http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.htmlを参照)、ソリューションを改善できます。内側のループの反復ごとに 3 つの Color オブジェクトを作成しない。

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);
}
于 2008-10-21T14:02:57.730 に答える
0

実際、私はそれを理解しました。これはおそらくそれを行うための速い方法ではありませんが、それは機能します:

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());
    }
}
于 2008-10-21T13:25:13.517 に答える