JDK-8122351 : Transforms on Text
  • Type: Bug
  • Component: javafx
  • Sub-Component: graphics
  • Affected Version: 7u45
  • Priority: P4
  • Status: Resolved
  • Resolution: Duplicate
  • Submitted: 2013-11-25
  • Updated: 2015-06-17
  • Resolved: 2013-11-25
Related Reports
Duplicate :  
Duplicate :  
Description
Text 2D transforms are not smooth as expected
Comments
>yes, the text caching doest the job. This is good news, but which is the tradeoff ? >Each glyph will have its own texture or you create a big texture with the whole text ? I guess the first. The whole content in Text node (all glyphs) is internally render to a texture, this texture will be transformed and re-rendered as needed. The trade off is text quality. For example, LCD text will look off when you rotate it, another classic case is a scale transform going from very small to very big. The first time the text is render is when the cached initialized, as the (texture) of the text is stretched the results gets blurry. >Last point: I have the impression that white text quality is a little worse than the dropshadow yellow text. Is this right ? It should be same, internally both cases are using an intermediate texture for rendering. >p.s. a side question: is there any api that allows me to transform each glyph separately ? Yes, but not glyphs. You can put each character you want to transform in a Text node and add them all into a TextFlow. The TextFlow will layout the text logically, then you can set whatever animation you need to each Text node. You can also animate to TextFlow as whole.
28-11-2013

Hi Felipe, yes, the text caching doest the job. This is good news, but which is the tradeoff ? Each glyph will have its own texture or you create a big texture with the whole text ? I guess the first. Last point: I have the impression that white text quality is a little worse than the dropshadow yellow text. Is this right ? p.s. a side question: is there any api that allows me to transform each glyph separately ? Let's think about creating effects like this: http://win.classx.it/classx_gfx/castalia/tml_efx_anim0.gif (this is java2d) Many thanks! Mik
28-11-2013

Hi Michele, Yes, I know how bad it looks. Unfortunately this not something we will be able fix for JavaFX 8. If you have a rotation in your transforms we actually disable subpixel text which makes it even worse. In JavaFX 8 your best option to solve this type of problem is animate the text as bitmap. In your example, try: text.setCache(true); text.setCacheHint(CacheHint.SPEED); I'm using RT-6475 to track this type of problem (so there is no need to reopen this bug).
27-11-2013

Felipe (hi), did you run it ?
27-11-2013

Felipe, please run the code and investigate, reopening as appropriate.
26-11-2013

I tried with the new jre-8-ea-bin-b117-windows-x64-21_nov_2013 and we're still far from perfection. The glyphs are still rasterized at integer coords (no subpixel rendering). Maybe we need an api to tell the font rasterizer to render glyphs at float coords (FontRenderingHints or something like this). In order to get the best visual results we must put an effect on the text node (see yello text). But this is only a dirty trick as the effect is really time-consuming in most cases. Of course we prefer the real thing.. Here's the source code that shows the problem (which, IMHO is NOT RESOLVED). -------8<-------------------------------------------------------- /* * Created on 25/nov/2013 */ package JavaFX; import javafx.animation.ParallelTransition; import javafx.animation.RotateTransition; import javafx.animation.ScaleTransition; import javafx.animation.Timeline; import javafx.animation.TranslateTransition; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.effect.DropShadow; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.util.Duration; /** * @author Mik */ public class TextTransformIssue extends Application { /* * @see javafx.application.Application#start(javafx.stage.Stage) */ @Override public void start(Stage stage) throws Exception { Group root = new Group(); Scene scene = new Scene(root, 800, 800, Color.BLACK); Rectangle r = new Rectangle(0, 0, 800, 800); r.setFill(Color.BLUE); root.getChildren().add(r); TranslateTransition translate = new TranslateTransition(Duration.millis(100000)); translate.setToX(290); translate.setToY(290); RotateTransition rotate = new RotateTransition(Duration.millis(100000)); rotate.setToAngle(360); ScaleTransition scale = new ScaleTransition(Duration.millis(100000)); scale.setToX(.1); scale.setToY(.1); // ////////////////// final Text text = new Text(); text.setText("TEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM"); text.setFill(Color.ALICEBLUE); text.setFont(Font.font(null, FontWeight.BOLD, 40)); text.setX(25); text.setY(65); final Text text1 = new Text(); text1.setText("TEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM"); text1.setFill(Color.YELLOW); text1.setFont(Font.font(null, FontWeight.BOLD, 40)); text1.setX(25); text1.setY(465); // effect DropShadow ds = new DropShadow(); ds.setOffsetY(3.0); ds.setOffsetX(3.0); ds.setColor(Color.GRAY); text1.setEffect(ds); // attach root.getChildren().add(text); root.getChildren().add(text1); // our transition ParallelTransition transition = new ParallelTransition(root, rotate); transition.setCycleCount(Timeline.INDEFINITE); transition.setAutoReverse(true); transition.play(); stage.setTitle("JavaFX Text Transform issue"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
26-11-2013

RT-6475 is also a interesting bug to follow if you are interested on transforms on Text.
25-11-2013

I think this is a duplicate of RT-14187
25-11-2013

/* * Created on 25/nov/2013 */ package JavaFX; import javafx.animation.ParallelTransition; import javafx.animation.RotateTransition; import javafx.animation.ScaleTransition; import javafx.animation.Timeline; import javafx.animation.TranslateTransition; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.effect.DropShadow; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.util.Duration; /** * @author Mik */ public class TextTransformIssue extends Application { /* * @see javafx.application.Application#start(javafx.stage.Stage) */ @Override public void start(Stage stage) throws Exception { Group root = new Group(); Scene scene = new Scene(root, 800, 800, Color.BLACK); Rectangle r = new Rectangle(0, 0, 800, 800); r.setFill(Color.BLUE); root.getChildren().add(r); TranslateTransition translate = new TranslateTransition(Duration.millis(10000)); translate.setToX(290); translate.setToY(290); RotateTransition rotate = new RotateTransition(Duration.millis(10000)); rotate.setToAngle(360); ScaleTransition scale = new ScaleTransition(Duration.millis(10000)); scale.setToX(.1); scale.setToY(.1); // ////////////////// final Text text = new Text(); text.setText("TEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM\nTEXT WITH NON-SMOOTH TRANSFORM"); text.setFill(Color.ALICEBLUE); text.setFont(Font.font(null, FontWeight.BOLD, 40)); text.setX(25); text.setY(65); final Text text1 = new Text(); text1.setText("TEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM\nTEXT WITH SMOOTH TRANSFORM"); text1.setFill(Color.YELLOW); text1.setFont(Font.font(null, FontWeight.BOLD, 40)); text1.setX(25); text1.setY(365); // effect DropShadow ds = new DropShadow(); ds.setOffsetY(3.0); ds.setOffsetX(3.0); ds.setColor(Color.GRAY); text1.setEffect(ds); // attach root.getChildren().add(text); root.getChildren().add(text1); // our transition ParallelTransition transition = new ParallelTransition(root, translate, rotate, scale); transition.setCycleCount(Timeline.INDEFINITE); transition.setAutoReverse(true); transition.play(); stage.setTitle("JavaFX Text Transform issue"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
25-11-2013