Pergunta

Estou tentando criar vários estilos visuais semelhantes para meus programas, cada um com um tema de cores diferente. Para fazer isso, implementei o uso de ícones para representar os diferentes estados de JCheckBoxareia JRadioButtons. Em vez de criar um conjunto completo de ícones para todas as cores possíveis, existe alguma maneira de pegar um conjunto e alterar a matiz/saturação/luminosidade/alfa da imagem antes de exibi -la?

Foi útil?

Solução

Existe uma maneira, mas você terá que usar algumas transformações de bufferImage. Depois de criar, cache -os ou salvá -los para serem facilmente reutilizados mais tarde. Essencialmente, você deseja começar com uma imagem preta (cor de origem #000000) que usa apenas a camada alfa para desligar os pixels (fornecendo também anti-aliasing suaves). Por exemplo, na sua imagem de origem, cada pixel é preto, mas o canal alfa difere do pixel para o pixel.

Primeiro, leia este artigo para obter algumas informações básicas: http://www.javalobby.org/articles/ultimate-image/

Depois de terminar com essa cartilha, você precisa carregar sua imagem em um bufferImage:

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

Em seguida, você precisa criar um novo bufferImage para transformar a transformação em:

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

Essencialmente, o SetXormode xorá a cor que você fornece com a cor na imagem de origem. Se a imagem de origem for preta, qualquer cor que você fornecer será escrita à medida que você a especificar. Com a nova cor usando "0" para o canal alfa, os valores originais do canal alfa serão respeitados. O resultado final é o composto que você está procurando.

Editar:

Você pode carregar o bufferImage inicial de duas maneiras. O mais fácil é usar a API Imageio mais recente de Java: http://download.oracle.com/javase/6/docs/api/javax/imageio/imageio.html Para carregar o arquivo diretamente em um bufferImage. A chamada seria algo assim:

BufferedImage img = ImageIO.read(url); 

Como alternativa, você pode criar um método para ler a imagem usando o kit de ferramentas.

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

Obviamente, se você prestar atenção, precisamos fazer exatamente a mesma coisa para ler a imagem em uma imagem em buffer como fazemos para matizer. Em suma, se você mudou a assinatura do colorImage método para aceitar o Image Objeto Você só precisa fazer algumas alterações nos métodos getWidth () e GetHeight () para fazê -lo funcionar.

Outras dicas

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

A maneira mais fácil de fazer isso seria usando o Filtros de imagem por JH Labs. Você pode simplesmente ajustar o HSB ligando,

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

Para calcular a média para cada componente de cores e manter o Alpha original:

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

Isso funciona melhor para o meu caso.

Eu tentei todas as soluções nesta página, não tive sorte. O XOR One (resposta aceita) não funcionou para mim - matizou uma cor amarela estranha em vez da cor que eu estava dando como argumento, não importa o argumento. Finalmente encontrei uma abordagem que funciona para mim, embora seja um pouco confuso. Imaginei que eu adicionaria caso qualquer outra pessoa esteja tendo os mesmos problemas que estou com as outras soluções. Felicidades!

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

Isso não é exatamente um tonalidade, é mais como aplicar outra camada, mas funciona para mim:

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

Porque todos os métodos que encontrei não funcionaram para mim por qualquer motivo, aqui está uma maneira fácil de abordar isso (sem necessidade de libs extra):

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

Uma imagem preta vai sempre Fique preto, mas uma imagem branca será a cor que você especificar. Este método passa por todos os pixels e multiplique os valores verde e azul vermelho da imagem com parâmetros. Este é o comportamento exato do OpenGL glcolor3f () método. Os parâmetros R, G e B devem ser 0,0F a 1,0F.

Este método não tem problemas com os valores alfa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top