Reputation: 1574
I have a PNG image like this:
I want to change image to something like this:
How can I do this in JavaFX?
Upvotes: 6
Views: 22668
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
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
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.
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.
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