Eeliya
Eeliya

Reputation: 1574

How to change color of image in JavaFX

I have a PNG image like this:

png image

I want to change image to something like this:

enter image description here

How can I do this in JavaFX?

Upvotes: 6

Views: 22668

Answers (3)

Michael Sims
Michael Sims

Reputation: 2523

I tried Wolfgang's reColor method above, but when I was trying to just recolor an image where I was trying to change all white pixels to another color, the result was always off and in many cases it wouldn't replace the colors at all, defaulting them to flat black for a variety of different colors that I tried.

So after figuring out what his code was doing, I came up with this method that actually does a one-for-one color pixel replacement and it works quite well.

import javafx.scene.paint.Color;
import javafx.scene.image.*;

private static Image reColor(Image inputImage, Color sourceColor, Color finalColor) {
    int            W           = (int) inputImage.getWidth();
    int            H           = (int) inputImage.getHeight();
    WritableImage  outputImage = new WritableImage(W, H);
    PixelReader    reader      = inputImage.getPixelReader();
    PixelWriter    writer      = outputImage.getPixelWriter();
    float          ocR         = (float) sourceColor.getRed();
    float          ocG         = (float) sourceColor.getGreen();
    float          ocB         = (float) sourceColor.getBlue();
    float          ncR         = (float) finalColor.getRed();
    float          ncG         = (float) finalColor.getGreen();
    float          ncB         = (float) finalColor.getBlue();
    java.awt.Color oldColor    = new java.awt.Color(ocR, ocG, ocB);
    java.awt.Color newColor    = new java.awt.Color(ncR, ncG, ncB);
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            int            argb       = reader.getArgb(x, y);
            java.awt.Color pixelColor = new java.awt.Color(argb, true);
            writer.setArgb(x, y,
                           pixelColor.equals(oldColor) ?
                           newColor.getRGB() :
                           pixelColor.getRGB());
        }
    }
    return outputImage;
}

Upvotes: 0

Wolfgang Fahl
Wolfgang Fahl

Reputation: 15769

The below code will replace one pixel color with another. If you run that multiple times over your original image replacing gray scale values with color values you should be set. To save memory you might want to adapt the code to reuse the writeable image for each loop.

/**
   * reColor the given InputImage to the given color
   * inspired by https://stackoverflow.com/a/12945629/1497139
   * @param inputImage
   * @param oldColor
   * @param newColor 
   * @return reColored Image
   * 
   */
  public static Image reColor(Image inputImage, Color oldColor, Color newColor) {
    int W = (int) inputImage.getWidth();
    int H = (int) inputImage.getHeight();
    WritableImage outputImage = new WritableImage(W, H);
    PixelReader reader = inputImage.getPixelReader();
    PixelWriter writer = outputImage.getPixelWriter();
    int ob=(int) oldColor.getBlue()*255;
    int or=(int) oldColor.getRed()*255;
    int og=(int) oldColor.getGreen()*255;
    int nb=(int) newColor.getBlue()*255;
    int nr=(int) newColor.getRed()*255;
    int ng=(int) newColor.getGreen()*255;
    for (int y = 0; y < H; y++) {
      for (int x = 0; x < W; x++) {
        int argb = reader.getArgb(x, y);
        int a = (argb >> 24) & 0xFF;
        int r = (argb >> 16) & 0xFF;
        int g = (argb >>  8) & 0xFF;
        int b =  argb        & 0xFF;
        if (g==og && r==or && b==ob) {
          r=nr;
          g=ng;
          b=nb;
        }

        argb = (a << 24) | (r << 16) | (g << 8) | b;
        writer.setArgb(x, y, argb);
      }
    }
    return outputImage;
  }

Upvotes: 4

jewelsea
jewelsea

Reputation: 159291

As you don't care if it is a vector shape or a bitmap, I'll just outline solutions using a bitmap here. If you actually wanted a vector shape, I believe you would need to work with vector input to get a good result.


Use a ColorAdjust effect with the brightness set to minimum (-1). Cache the result for SPEED.

speed

Here is a sample which creates a shadow outline of an image:

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.*;
import javafx.stage.Stage;

public class Shadow extends Application {
    @Override 
    public void start(Stage stage) throws Exception {
        ImageView imageView = new ImageView(
            new Image(
                "https://i.sstatic.net/jbT1H.png"
            )
        );

        ColorAdjust blackout = new ColorAdjust();
        blackout.setBrightness(-1.0);

        imageView.setEffect(blackout);
        imageView.setCache(true);
        imageView.setCacheHint(CacheHint.SPEED);

        stage.setScene(new Scene(new Group(imageView)));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch();
    }
}

Here is another sample which adjusts the color of an image, hover over smurfette to make her blush.

smurfette blushing smurfette

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Shadow extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Image image = new Image(
                "http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
        );

        ImageView imageView = new ImageView(image);
        imageView.setClip(new ImageView(image));

        ColorAdjust monochrome = new ColorAdjust();
        monochrome.setSaturation(-1.0);

        Blend blush = new Blend(
                BlendMode.MULTIPLY,
                monochrome,
                new ColorInput(
                        0,
                        0,
                        imageView.getImage().getWidth(),
                        imageView.getImage().getHeight(),
                        Color.RED
                )
        );

        imageView.effectProperty().bind(
                Bindings
                    .when(imageView.hoverProperty())
                        .then((Effect) blush)
                        .otherwise((Effect) null)
        );

        imageView.setCache(true);
        imageView.setCacheHint(CacheHint.SPEED);

        stage.setScene(new Scene(new Group(imageView), Color.AQUA));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch();
    }
}

Upvotes: 27

Related Questions