JDK-8102847 : Need a way to avoid jittery, pixelated text when scaling a Label or Text node in an animation
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-05-31
  • Updated: 2015-06-16
  • Resolved: 2013-09-27
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8Fixed
Related Reports
Blocks :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
When a Label is in a ScaleTransition the text jumps around and also seems to lose its antialising (or at least doesn't look overly smooth). 


public class TextAnimateApp extends Application {

    public static void main(String[] args) throws Exception {
        launch(args);
    }

    public void start(Stage stage) throws Exception {

        final StackPane rootPane = new StackPane();

        Label label = new Label("This is a label");
        label.setStyle("-fx-font-scale: 30");
        ScaleTransition scale = new ScaleTransition(Duration.seconds(5), label);
        scale.setCycleCount(Animation.INDEFINITE);
        scale.setAutoReverse(true);
        scale.setFromX(0);
        scale.setFromY(0);
        scale.setToX(5);
        scale.setToY(5);
        scale.play();
        rootPane.getChildren().add(label);

        Scene scene = new Scene(rootPane, 1200, 800);
        stage.setScene(scene);
        stage.show();
    }
}



Comments
closing as fixed as a reasonable work around has been provided.
27-09-2013

Yes, that works too.
27-09-2013

Here is another approach. The only thing with this one is that when the text gets small, it gets jaggy. I assume this must be an artifact of image scaling, but don't know for certain. public class TextAnimateApp extends Application { public static void main(String[] args) throws Exception { launch(args); } public void start(Stage stage) throws Exception { final StackPane rootPane = new StackPane(); Text label = new Text("This is a label"); label.setFont(Font.font(400)); label.setCache(true); label.setCacheHint(CacheHint.SPEED); ScaleTransition scale = new ScaleTransition(Duration.seconds(5), label); scale.setCycleCount(Animation.INDEFINITE); scale.setAutoReverse(true); scale.setFromX(0); scale.setFromY(0); scale.setToX(1); scale.setToY(1); scale.play(); rootPane.getChildren().add(label); Scene scene = new Scene(rootPane, 1200, 800); stage.setScene(scene); stage.show(); } }
27-09-2013

Yes, I think RT-6475 & RT-14187 capture the work items we need at this point. As for cache hint = SPEED, it works now, the text is rendered and scales without the jittery. That said, we cache it at identify so as the text scale 5x it will render as one would expect (blown up, blurry) Running the animation from 5 to 0 (instead of from 0 to 5) makes it look much better.
27-09-2013

BTW, did you verify that with the cache hint SPEED that this use case works as is now?
27-09-2013

As long as we've got the unfinished work documented in JIRA issues, that's fine with me.
27-09-2013

Richard, Can I close this jira ? RT-30863 is fixed, thus we have a way to avoid jittery, pixelated text when scaling. RT-6475 covers rendering hints RT-14187 covers subpixel text
27-09-2013

>BTW, I bet the SPEED cache hints I tried earlier would work now that I fixed the fact that SPEED wasn't being honored by CacheFilter. not really, the problem here is the CacheFilter caching the node at scale 0x. See RT-30863
20-09-2013

BTW, I bet the SPEED cache hints I tried earlier would work now that I fixed the fact that SPEED wasn't being honored by CacheFilter.
18-09-2013

Richard, Try scale.setFromX(5); scale.setFromY(5); scale.setToX(0); scale.setToY(0); Instead of scale.setFromX(0); scale.setFromY(0); scale.setToX(5); scale.setToY(5); Think of that as workaround for RT-30863, but it actually better, as the first time we render text it uses the max size. Fixing this bug we can use images (either fixing RT-30863 or documenting best practices how to animated text). The other options it to use paths, which is part of RT-6475. For JavaFX8, what should we do ?
18-09-2013

Filed RT-30863 to capture the failure of cache=true, cacheHint=SPEED to draw anything.
01-06-2013

setSmooth(false) is not implemented, see NGShape public void setAntialiased(boolean aa) { // TODO: for now everything will be antialiased (RT-26939) //if (aa != this.antialiased) { // this.antialiased = aa; // invalidateStrokeShape(); //} }
31-05-2013

Both smooth true/false are a little jittery. It isn't a framerate issue, just that as the text is animating in size the AA is "crawling". Smooth=false is still doing AA. Attaching two videos.
31-05-2013

Okay, we could try: a) text.setSmooth(false); -- let me know if that makes any difference for you b) improve on performance (currently the shape for text is being computed every frame, it could easily be cached).
31-05-2013

Definitely much better, although still somewhat jumpy -- maybe just the AA algorithm is a little too noticeable, I'm not certain. But loads better.
31-05-2013

Richard, for the sake of testing, try this: diff -r 18da8c32f363 javafx-sg-prism/src/com/sun/javafx/sg/prism/NGText.java --- a/javafx-sg-prism/src/com/sun/javafx/sg/prism/NGText.java Thu May 30 14:54:15 2013 -0700 +++ b/javafx-sg-prism/src/com/sun/javafx/sg/prism/NGText.java Fri May 31 08:45:51 2013 -0700 @@ -273,7 +273,8 @@ if (mode != Mode.STROKE) { g.setPaint(fillPaint); int op = TEXT; - op |= strike.drawAsShapes() || drawingEffect ? SHAPE_FILL : FILL; +// op |= strike.drawAsShapes() || drawingEffect ? SHAPE_FILL : FILL; + op |= SHAPE_FILL; renderText(g, strike, clipBds, selectionColor, op); // Splitting decoration from text rendering is important in order
31-05-2013

It will force Text to draw using shape. Maybe we need a drawAsShapes for Text ?
31-05-2013

Note that a Label, and a Text node in its default configuration *must* behave like this if you want crisp text. The glyphs are being aligned on pixel boundaries so that the text will appear as sharp as possible. This is particularly true of the way the windows font renderer works (Mac on the other hand will position glyphs where they theoretically belong and render somewhat blurrier text as a result. Which approach is better is a matter of debate on the web -- the truth is there is no right answer). However the Text node is supposed to support options for animated text, such that the Text will act more like a shape (outline) rather than Text. The downside is the text will not appear as crisp. This is to be expected (to my knowledge there is no solution to that tradeoff so long as pixels are involved, although with a high-enough resolution display you'll stop being able to see it with the unaided eye).
31-05-2013

This also did not work: Text text = new Text("This is a text node"); Platform.runLater( new Runnable() { @Override public void run() { text.setCache(true); text.setCacheHint(CacheHint.SPEED); ScaleTransition scale = new ScaleTransition(Duration.seconds(5), text); scale.setCycleCount(Animation.INDEFINITE); scale.setAutoReverse(true); scale.setFromX(0); scale.setFromY(0); scale.setToX(5); scale.setToY(5); scale.play(); } }); rootPane.getChildren().add(text);
31-05-2013

I expected this to work, but it doesn't draw anything: final StackPane rootPane = new StackPane(); Text text = new Text("This is a text node"); text.setCache(true); text.setCacheHint(CacheHint.SPEED); ScaleTransition scale = new ScaleTransition(Duration.seconds(5), text); scale.setCycleCount(Animation.INDEFINITE); scale.setAutoReverse(true); scale.setFromX(0); scale.setFromY(0); scale.setToX(5); scale.setToY(5); scale.play(); rootPane.getChildren().add(text); Scene scene = new Scene(rootPane, 1200, 800); stage.setScene(scene); stage.show(); It *should* have rendered the text node at its normal size, and then used this cached version for the subsequent animation. Instead it draws nothing.
31-05-2013