Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8224109

Text spaced incorrectly by drawString under rotation with fractional metrics

XMLWordPrintable

    • 2d
    • 11
    • b07
    • x86_64
    • windows_7

        ADDITIONAL SYSTEM INFORMATION :
        Windows 7 - JDK 11 & JDK 12

        A DESCRIPTION OF THE PROBLEM :
        When the current transform has different x and y scales, rendering text at different angles the glyph spacing is proportional to the angle. This is apparent in Java 11, but was not this way in Java 6, 7 & 8.

        REGRESSION : Last worked in version 8u202

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        The following will produce a png file with some text which shows the differences when run on Java 8 vs Java 11 or later.

        import java.awt.Color;
        import java.awt.Font;
        import java.awt.Graphics2D;
        import java.awt.Toolkit;
        import java.awt.RenderingHints;
        import java.awt.font.TextAttribute;
        import java.awt.geom.AffineTransform;
        import java.awt.image.BufferedImage;
        import java.io.File;
        import java.io.IOException;
        import java.text.AttributedString;
        import java.util.Map;

        import javax.imageio.ImageIO;
        public class TransformedText_JDK8 {

            private static BufferedImage awtImage;
            private static Graphics2D buffer_g2d;
            private static Font originalFont;
            
            private static void initaliseGraphics()
            {
             awtImage = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB);
                buffer_g2d = (Graphics2D) awtImage.getGraphics();
                
                buffer_g2d.setBackground(Color.WHITE);
                buffer_g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT);

                buffer_g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                buffer_g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                buffer_g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                buffer_g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

                buffer_g2d.setColor(Color.WHITE);
                buffer_g2d.fillRect(10, 10, 980, 980);
                
                buffer_g2d.setColor(Color.BLACK);
                
                originalFont = new Font("Segoe UI", Font.PLAIN, 30);
            }
            
            private static void renderHeader()
            {
                AffineTransform cachedAt = buffer_g2d.getTransform();
                AffineTransform localAt = (AffineTransform) cachedAt.clone();
                
                localAt.translate(100, 100);
                System.out.println(System.getProperty("java.version"));

                AttributedString header1 = new AttributedString("java.version, " + System.getProperty("java.version"));

                header1.addAttribute(TextAttribute.FONT, originalFont);
                header1.addAttribute(TextAttribute.KERNING, TextAttribute.KERNING_ON);
                buffer_g2d.setTransform(localAt);
                buffer_g2d.drawString(header1.getIterator(), 0, 0);
                
                buffer_g2d.setTransform(cachedAt);
            }
            
            private static void renderTransformedText()
            {
                AffineTransform cachedAt = buffer_g2d.getTransform();;
                AffineTransform localAt;
                
                AttributedString test1 = new AttributedString(" Test String");
                test1.addAttribute(TextAttribute.FONT, originalFont);
                test1.addAttribute(TextAttribute.KERNING, TextAttribute.KERNING_ON);
                
                for (int i = 0; i <= 12; i++) {
                    localAt = (AffineTransform) cachedAt.clone();
                    localAt.translate(500, 500);

                    localAt.rotate(Math.toRadians(i * 30));
                    localAt.scale(1.0, 2.0);
                    
                    buffer_g2d.setTransform(localAt);
                    buffer_g2d.drawString(test1.getIterator(), 0, 0);

                    buffer_g2d.setTransform(cachedAt);
                }
            }
            
            private static void savePng()
            {
                try {
                    ImageIO.write(awtImage, "png",new File("c:\\temp\\FontTest02.png"));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                }
            }
            
            public static void main(String[] a) {
                initaliseGraphics();
                renderHeader();
                renderTransformedText();
                savePng();
            }
        }


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Each of the 'Test String' renderings should have the same glyph spacing - when the example is run on Java 8 the rendering is correct.
        ACTUAL -
        When run on Java 11 or later the strings become progressively stretched as they are rotated from the horizontal.

        ---------- BEGIN SOURCE ----------
        // See the example code given in the Steps to Reproduce
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        None found

        FREQUENCY : always


              prr Philip Race
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: