web-dev-qa-db-ja.com

javaの画像に色合いを適用する

私は自分のプログラムに、それぞれ異なる色のテーマを持ついくつかの同様の視覚スタイルを作成しようとしています。これを行うために、JCheckBoxsとJRadioButtonsのさまざまな状態を表すアイコンの使用を実装しました。可能なすべての色に対して1つのフルセットのアイコンを作成する代わりに、1つのセットを取得して、画像を表示する前に画像の色相/彩度/明度/アルファを変更する方法はありますか?

23
Supuhstar

方法はありますが、いくつかのBufferedImage変換を利用する必要があります。それらを作成したら、後で簡単に再利用できるように、キャッシュするか保存してください。基本的に、アルファレイヤーのみを使用してピクセルをオフにする(スムーズなアンチエイリアシングも提供する)黒い画像(ソースカラー#000000)から始めます。たとえば、ソースイメージでは、すべてのピクセルが黒ですが、アルファチャネルはピクセルごとに異なります。

まず、いくつかの背景情報についてこの記事を読んでください: http://www.javalobby.org/articles/ultimate-image/

その入門書を使い終わったら、画像をBufferedImageにロードする必要があります。

BufferedImage loadImg = ImageUtil.loadImage("C:/Images/myimg.png");

次に、新しいBufferedImageを作成して、次のように変換する必要があります。

public BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue) {
    BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
        BufferedImage.TRANSLUCENT);
    Graphics2D graphics = img.createGraphics(); 
    Color newColor = new Color(red, green, blue, 0 /* alpha needs to be zero */);
    graphics.setXORMode(newColor);
    graphics.drawImage(loadImg, null, 0, 0);
    graphics.dispose();
    return img;
}

基本的に、setXORModeはXORソースイメージの色で提供する色です。ソースイメージが黒の場合、指定した色は指定したとおりに書き込まれます。アルファチャンネルに「0」を使用した色では、元のアルファチャンネルの値が尊重されます。最終結果は、探しているコンポジットです。

編集:

最初のBufferedImageは、2つの方法のいずれかでロードできます。最も簡単なのは、Javaの新しいImageIO APIを使用することです。 http://download.Oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html ファイルをBufferedImageに直接ロードする。呼び出しは次のようになります。

BufferedImage img = ImageIO.read(url); 

または、ToolKitを使用して画像を読み取るメソッドを作成することもできます。

public BufferedImage loadImage(String url) {
    ImageIcon icon = new ImageIcon(url);
    Image image = icon.getImage();

    // Create empty BufferedImage, sized to Image
    BufferedImage buffImage = 
      new BufferedImage(
        image.getWidth(null), 
        image.getHeight(null), 
        BufferedImage.TYPE_INT_ARGB);

    // Draw Image into BufferedImage
    Graphics g = buffImage.getGraphics();
    g.drawImage(image, 0, 0, null);
    return buffImage;
}

もちろん、注意を払う場合は、画像をバッファリングされた画像に読み込むために、色を付ける場合とまったく同じことを行う必要があります。つまり、colorImageメソッドのシグネチャを変更してImageオブジェクトを受け入れる場合は、getWidth()メソッドとgetHeight()メソッドをいくつか変更するだけで機能します。 。

13
Berin Loritsch

各色成分の平均を計算し、元のアルファを維持するには:

public static void tint(BufferedImage image, Color color) {
    for (int x = 0; x < image.getWidth(); x++) {
        for (int y = 0; y < image.getHeight(); y++) {
            Color pixelColor = new Color(image.getRGB(x, y), true);
            int r = (pixelColor.getRed() + color.getRed()) / 2;
            int g = (pixelColor.getGreen() + color.getGreen()) / 2;
            int b = (pixelColor.getBlue() + color.getBlue()) / 2;
            int a = pixelColor.getAlpha();
            int rgba = (a << 24) | (r << 16) | (g << 8) | b;
            image.setRGB(x, y, rgba);
        }
    }
}

これは私の場合に最適です。

4
Oleg Mikhailov
public static void tint(BufferedImage img) {

    for (int x = 0; x < img.getWidth(); x++) {
        for (int y = 0; y < img.getHeight(); y++) {

            Color color = new Color(img.getRGB(x, y));

            // do something with the color :) (change the hue, saturation and/or brightness)
            // float[] hsb = new float[3];
            // Color.RGBtoHSB(color.getRed(), old.getGreen(), old.getBlue(), hsb);

            // or just call brighter to just tint it
            Color brighter = color.brighter();

            img.setRGB(x, y, brighter.getRGB());
        }
    }
}
4
dacwe

これを行う最も簡単な方法は、 JH Labsによる画像フィルター を使用することです。次のように呼び出すことで、HSBを簡単に調整できます。

public BufferedImage setHSB(BufferedImage source, float hValue, float sValue, float bValue) {        
    com.jhlabs.image.HSBAdjustFilter hsb hsb = new HSBAdjustFilter();
    BufferedImage destination = hsb.createCompatibleDestImage(source, null);
    hsb.setHFactor(hValue);
    hsb.setSFactor(sValue);
    hsb.setBFactor(bValue);
    BufferedImage result = hsb.filter(bi, destination);

    return result;
}
3
RocketRuwan

これは正確に着色している​​わけではなく、別のレイヤーを適用するようなものですが、私にとってはうまくいきます。

public static BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue, int alpha /*Also the intesity*/) {
    Graphics g = loadImg.getGraphics();
    g.setColor(new Color(red, green, blue, alpha));
    g.fillRect(0, 0, loadImg.getWidth(), loadImg.getHeight());
    g.dispose();
    return loadImg;
}
1
APerson

私はこのページのすべての解決策を試しましたが、運がありませんでした。 Xorの1つ(受け入れられた答え)は私には機能しませんでした-引数が何であれ、引数として与えていた色の代わりに奇妙な黄色に着色しました。少し面倒ですが、ようやく自分に合ったアプローチを見つけました。他の誰かが私が他の解決策と同じ問題を抱えている場合に備えて、私はそれを追加すると考えました。乾杯!

/** Tints the given image with the given color.
 * @param loadImg - the image to Paint and tint
 * @param color - the color to tint. Alpha value of input color isn't used.
 * @return A tinted version of loadImg */
public static BufferedImage tint(BufferedImage loadImg, Color color) {
    BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
            BufferedImage.TRANSLUCENT);
    final float tintOpacity = 0.45f;
    Graphics2D g2d = img.createGraphics(); 

    //Draw the base image
    g2d.drawImage(loadImg, null, 0, 0);
    //Set the color to a transparent version of the input color
    g2d.setColor(new Color(color.getRed() / 255f, color.getGreen() / 255f, 
        color.getBlue() / 255f, tintOpacity));

    //Iterate over every pixel, if it isn't transparent Paint over it
    Raster data = loadImg.getData();
    for(int x = data.getMinX(); x < data.getWidth(); x++){
        for(int y = data.getMinY(); y < data.getHeight(); y++){
            int[] pixel = data.getPixel(x, y, new int[4]);
            if(pixel[3] > 0){ //If pixel isn't full alpha. Could also be pixel[3]==255
                g2d.fillRect(x, y, 1, 1);
            }
        }
    }
    g2d.dispose();
    return img;
}
1
Mshnik

私が見つけたすべてのメソッドが何らかの理由で機能しなかったので、これにアプローチする簡単な方法があります(追加のライブラリは必要ありません):

/**
 * Colors an image with specified color.
 * @param r Red value. Between 0 and 1
 * @param g Green value. Between 0 and 1
 * @param b Blue value. Between 0 and 1
 * @param src The image to color
 * @return The colored image
 */
protected BufferedImage color(float r, float g, float b, BufferedImage src) {

    // Copy image ( who made that so complicated :< )
    BufferedImage newImage = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TRANSLUCENT);
    Graphics2D graphics = newImage.createGraphics();
    graphics.drawImage(src, 0, 0, null);
    graphics.dispose();

    // Color image
    for (int i = 0; i < newImage.getWidth(); i++) {
        for (int j = 0; j < newImage.getHeight(); j++) {
            int ax = newImage.getColorModel().getAlpha(newImage.getRaster().getDataElements(i, j, null));
            int rx = newImage.getColorModel().getRed(newImage.getRaster().getDataElements(i, j, null));
            int gx = newImage.getColorModel().getGreen(newImage.getRaster().getDataElements(i, j, null));
            int bx = newImage.getColorModel().getBlue(newImage.getRaster().getDataElements(i, j, null));
            rx *= r;
            gx *= g;
            bx *= b;
            newImage.setRGB(i, j, (ax << 24) | (rx << 16) | (gx << 8) | (bx << 0));
        }
    }
    return newImage;
}

黒の画像は常に黒のままですが、白の画像は指定した色になります。この方法では、すべてのピクセルを調べ、画像の赤、緑、青の値にパラメーターを掛けます。これは、OpenGL glColor3f()メソッドの正確な動作です。 R、G、Bのパラメータは0.0Fから1.0Fでなければなりません。

この方法では、アルファ値に問題はありません。

0
2xsaiko