I have a pretty specific problem with javaFx's ColorAdjust effect, I'm trying to apply a grayscale filter on an image, I'm using a ColorAdjust effect and setting the saturation Here is a reproducible example of what I'm trying to do
public class App extends Application {
@Override
public void start(Stage ps) {
Pane root = new Pane();
root.setMinSize(300, 300);
root.setStyle("-fx-background-color: #40444b;");
ImageView view = new ImageView(new Image("https://res.cloudinary.com/mesa-clone/image/upload/v1642936429/1f914_tydc44.png"));
view.setTranslateX(5);
view.setTranslateY(5);
view.setEffect(new ColorAdjust(0, -1, 0, 0));
root.getChildren().add(view);
ps.setScene(new Scene(root));
ps.show();
}
}
now this piece of code does exactly what it's supposed to do, but I'm not satisfied with the result, I want a grayscale filter that behaves similarly to the web css grayscale filter, which produces much better results for my use case :
<html>
<body style="background-color: #40444b;">
<img src="https://res.cloudinary.com/mesa-clone/image/upload/v1642936429/1f914_tydc44.png" style="filter: grayscale(100);">
</body>
</html>
[ Left is javafx, Right is Web (firefox) ]
I know the difference isn't a lot but it's crucial for my use case and I would appreciate if anyone has better ideas to get similar results to the web version of the grayscale filter
manually converting the image to grayscale using a WritableImage and Color.grayscale() gives better results but it would complicate the process of switching between color and grayscale :
public class App extends Application {
@Override
public void start(Stage ps) {
Pane root = new Pane();
root.setMinSize(300, 300);
root.setStyle("-fx-background-color: #40444b;");
Image image = new Image("https://res.cloudinary.com/mesa-clone/image/upload/v1642936429/1f914_tydc44.png");
ImageView view = new ImageView(grayScale(image));
view.setTranslateX(5);
view.setTranslateY(5);
root.getChildren().add(view);
ps.setScene(new Scene(root));
ps.setTitle("javafx grayscale test");
ps.show();
}
private static Image grayScale(Image img) {
WritableImage res = new WritableImage((int) img.getWidth(), (int) img.getHeight());
PixelReader pr = img.getPixelReader();
PixelWriter pw = res.getPixelWriter();
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
pw.setColor(x, y, pr.getColor(x, y).grayscale());
}
}
return res;
}
}
you have the choice of saving the filtered image or generating it every time, depending on whether that trade-off (increased memory usage for increased performance) is worthwhile.