I am working on a JavaFx application which use canvas to represent a diagram. The canvas is painting text using graphicsContext.fillText(). In the image below the canvas is on the right, on the left is a Label using the same font. My question is which renering parameter should I use to make the right text look the same as on the left ?
public class SampleRenderingIssue extends Application {
private final StackPane root = new StackPane();
private final Scene scene = new Scene(root, 300, 250);
private final BorderPane pane = new BorderPane();
private final Canvas canvas = new Canvas();
@Override
public void start(Stage stage) {
stage.setTitle("Sample Canvas");
VBox vbox = new VBox();
VBox.setVgrow(pane, Priority.ALWAYS);
vbox.getChildren().addAll( pane );
pane.getChildren().add(canvas);
root.getChildren().add(vbox);
stage.setScene(scene);
stage.sizeToScene();
setupCanvasPane();
stage.show();
Platform.runLater(()-> paint());
}
private void setupCanvasPane(){
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
pane.widthProperty().addListener((o,p,c)-> paint());
paint();
}
public void paint(){
GraphicsContext gr = canvas.getGraphicsContext2D();
gr.clearRect( 0,0, canvas.getWidth(), canvas.getHeight() );
gr.setFill( Color.web("#222222") );
gr.fillRect( 0,0,canvas.getWidth(), canvas.getHeight());
gr.setStroke( Color.WHITE );
gr.setFill( Color.WHITE );
gr.setLineWidth( 1d );
gr.strokeLine( 0,0, canvas.getWidth(), canvas.getHeight() );
gr.setFont( Font.font( "Candara"));
gr.fillText("This is a text", 100, 100 );
gr.setFont( Font.font( "Monospaced"));
gr.fillText("This is a text", 100, 120 );
}
public static void main(String[] args) {
launch(args);
}
}
The issue reproduces on a FullHd display where the Windows scale in Control Panel is set to 125% ( default value for a notebook ).
I also had poor text rendering quality in a Canvas
. I display dense text in a small font size and it looked quite ugly before.
This may or may not be the same problem you have been running up against, since my Windows scaling is at 100%, but I've discovered in my case it was caused by the Canvas
not using the same ClearType implementation as the rest of the UI widgets do. It seems to be set to GREY
mode instead of LCD
. It's a simple one line fix:
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFontSmoothingType(FontSmoothingType.LCD);
gc.setFont(Font.font("Consolas", 10));
gc.fillText("Example ABC 123", 10, 10);
Here is the result, in each case the top line is the rendered version, and the bottom line is a Label
in the scene. I've included a zoomed in version, where you can clearly see Canvas is not doing the LCD subpixel rendering correctly
In the right handle example they appear to be identical, and my visual quality is restored.