-
Bug
-
Resolution: Duplicate
-
P3
-
11, 13, 14
ADDITIONAL SYSTEM INFORMATION :
openjdk version "14-ea" 2020-03-17
OpenJDK Runtime Environment (build 14-ea+25-1178)
OpenJDK 64-Bit Server VM (build 14-ea+25-1178, mixed mode, sharing)
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
When using a font that has been rotated and scaled using deriveFont(AffineTransform), text will draw differently depending on whether you use drawString(AttributedCharacterIterator, int, int) or drawString(String, int, int).
More specifically, when you use drawString(String, int, int), and the Graphics2D object uses a rotated + scaled font, and fractional metrics are enabled on the Graphics2D object, the glyph advances for the string appear to be calculated incorrectly.
The issue has been observed in OpenJDK 14-ea25, OpenJDK 13-b33, and OpenJDK 11.0.4.
The issue does not exist in Oracle JDK 1.8.0_152.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The characters in all four strings ("Hello World 1", "Hello World 2", "Hello World 3", "Hello World 4") are spaced correctly; spacing in all four samples should be equivalent across samples.
ACTUAL -
The characters in "Hello World 2" are not spaced correctly (the glyphs overlap).
---------- BEGIN SOURCE ----------
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
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.text.AttributedString;
import java.util.Collections;
import javax.imageio.ImageIO;
public class FontRotationTest {
public static void main(String... args) throws Exception {
BufferedImage img = new BufferedImage(700, 700, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
AffineTransform at = AffineTransform.getRotateInstance(Math.PI / 2);
at.scale(3.65, 2.44); // x and y scales must be different to reproduce
Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 24).deriveFont(at);
drawString(g2d, "Hello World 1", 100, 50, font, false, false); // <- OK
drawString(g2d, "Hello World 2", 200, 50, font, false, true); // <- problem here
drawString(g2d, "Hello World 3", 300, 50, font, true, false); // <- OK
drawString(g2d, "Hello World 4", 400, 50, font, true, true); // <- OK
g2d.dispose();
ImageIO.write(img, "png", new File("font-rotation.png"));
}
private static void drawString(Graphics2D g2d, String s, int x, int y, Font font, boolean attributed, boolean fm) {
Object onOrOff = (fm ? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, onOrOff);
if (attributed) {
AttributedString as = new AttributedString(s, Collections.singletonMap(TextAttribute.FONT, font));
g2d.drawString(as.getIterator(), x, y);
} else {
Font oldFont = g2d.getFont();
g2d.setFont(font);
g2d.drawString(s, x, y);
g2d.setFont(oldFont);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use the drawString(AttributedCharacterIterator, int, int) method instead of the drawString(String, int, int) method, or disable fractional metrics.
FREQUENCY : always
openjdk version "14-ea" 2020-03-17
OpenJDK Runtime Environment (build 14-ea+25-1178)
OpenJDK 64-Bit Server VM (build 14-ea+25-1178, mixed mode, sharing)
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
When using a font that has been rotated and scaled using deriveFont(AffineTransform), text will draw differently depending on whether you use drawString(AttributedCharacterIterator, int, int) or drawString(String, int, int).
More specifically, when you use drawString(String, int, int), and the Graphics2D object uses a rotated + scaled font, and fractional metrics are enabled on the Graphics2D object, the glyph advances for the string appear to be calculated incorrectly.
The issue has been observed in OpenJDK 14-ea25, OpenJDK 13-b33, and OpenJDK 11.0.4.
The issue does not exist in Oracle JDK 1.8.0_152.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The characters in all four strings ("Hello World 1", "Hello World 2", "Hello World 3", "Hello World 4") are spaced correctly; spacing in all four samples should be equivalent across samples.
ACTUAL -
The characters in "Hello World 2" are not spaced correctly (the glyphs overlap).
---------- BEGIN SOURCE ----------
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
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.text.AttributedString;
import java.util.Collections;
import javax.imageio.ImageIO;
public class FontRotationTest {
public static void main(String... args) throws Exception {
BufferedImage img = new BufferedImage(700, 700, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
AffineTransform at = AffineTransform.getRotateInstance(Math.PI / 2);
at.scale(3.65, 2.44); // x and y scales must be different to reproduce
Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 24).deriveFont(at);
drawString(g2d, "Hello World 1", 100, 50, font, false, false); // <- OK
drawString(g2d, "Hello World 2", 200, 50, font, false, true); // <- problem here
drawString(g2d, "Hello World 3", 300, 50, font, true, false); // <- OK
drawString(g2d, "Hello World 4", 400, 50, font, true, true); // <- OK
g2d.dispose();
ImageIO.write(img, "png", new File("font-rotation.png"));
}
private static void drawString(Graphics2D g2d, String s, int x, int y, Font font, boolean attributed, boolean fm) {
Object onOrOff = (fm ? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, onOrOff);
if (attributed) {
AttributedString as = new AttributedString(s, Collections.singletonMap(TextAttribute.FONT, font));
g2d.drawString(as.getIterator(), x, y);
} else {
Font oldFont = g2d.getFont();
g2d.setFont(font);
g2d.drawString(s, x, y);
g2d.setFont(oldFont);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use the drawString(AttributedCharacterIterator, int, int) method instead of the drawString(String, int, int) method, or disable fractional metrics.
FREQUENCY : always
- duplicates
-
JDK-8224109 Text spaced incorrectly by drawString under rotation with fractional metrics
- Resolved