Применение оттенка к изображению в java

Я пытаюсь создать несколько похожих визуальных стилей для моих программ, каждый с другой цветовой темой. Для этого я реализовал использование значков для представления различных состояний JCheckBoxs и JRadioButtons. Вместо того, чтобы делать один полный набор значков для каждого возможного цвета, есть ли способ, которым я могу просто взять один набор и изменить оттенок/насыщенность/яркость/Альфа изображения перед его отображением?

7 ответов


есть способ, но вам придется использовать некоторые преобразования 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 " для альфа-канала, будут соблюдены исходные значения Альфа-канала. Конечным результатом является композит, который вы ищете.

Edit:

вы можете загрузить начальный BufferedImage одним из двух способов. Проще всего использовать новый API ImageIO Java:http://download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html чтобы загрузить файл непосредственно в BufferedImage. Вызов будет выглядеть что-то вроде этого:--7-->

BufferedImage img = ImageIO.read(url); 

кроме того, вы можете создать метод для чтения изображения с помощью инструментария.

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 object вам нужно только внести пару изменений в методы getWidth() и getHeight (), чтобы заставить его работать.


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

чтобы рассчитать среднее значение для каждого цветового компонента и сохранить исходную Альфа:

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

Это лучше всего подходит для моего случая.


самый простой способ сделать это - использовать фильтры изображений от 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;
}

Я пробовал каждое решение на этой странице, не повезло. Xor one (принятый ответ) не работал для меня - тонировал странный желтый цвет вместо цвета, который я давал в качестве аргумента, независимо от того, какой аргумент. Я, наконец, нашел подход, который работает для меня, хотя это немного грязный. Решил добавить его, если у кого-то еще есть те же проблемы, что и у меня с другими решениями. Ура!

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

Это не совсем тонировка, это больше похоже на нанесение на него другого слоя, но это работает для меня:

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

потому что все методы, которые я нашел, не работает для меня по какой-то причине, вот простой способ (без дополнительных библиотек):

/**
 * 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,0 F до Ф. 1.0

этот метод не имеет проблем с Альфа-значениями.