6

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?

Eeliya
  • 1,534
  • 5
  • 23
  • 37
  • Do you want a [vector shape](http://docs.oracle.com/javafx/2/api/javafx/scene/shape/Shape.html) or a [bitmapped image](http://docs.oracle.com/javafx/2/api/javafx/scene/image/Image.html)? – jewelsea Aug 08 '13 at 11:10
  • Well, anyone which is faster, because I want to use this feature for my game engine. I want to create a shape from image at the runtime. So it needs to be fast approach. – Eeliya Aug 08 '13 at 11:14

3 Answers3

27

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.stack.imgur.com/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();
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thanks for your code, but its not exactly what I want. I a shape then I am able to change the colour of the shape. I have updated my question. – Eeliya Aug 08 '13 at 11:39
  • 1
    Updated answer to include a color change. Please be more specific when asking questions, thanks :-) – jewelsea Aug 08 '13 at 12:41
  • Thanks for answer, my main question is how to create a shape from image. this is good workaround but my main question still remain without an answer. I try to solve my problem with this workaround. – Eeliya Aug 08 '13 at 14:15
5

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;
  }
Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186
0

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;
}
Michael Sims
  • 2,360
  • 1
  • 16
  • 29