-
Bug
-
Resolution: Fixed
-
P3
-
None
-
b21
-
generic
-
windows
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8270525 | 11.0.13-oracle | Prasanta Sadhukhan | P3 | Resolved | Fixed | b03 |
JDK-8269479 | 11.0.13 | Alexandr Scherbatiy | P3 | Resolved | Fixed | b01 |
PDFBox 1.8 uses scaled glyphs to print a text [1] and PDFBox 2.0 draws a text by drawing its path [2].
Recent fix to PDFBox allows to pass a custom PDFRenderer to PDFPrintable [3] so it is possible to override PDFBox PageDrawer.showGlyph(...) method and use Graphics2D.drawString(...) method to draw a text.
Some tests showed that there is a pdf document which prints all but one font properly using Graphics2D.drawString(...) method on Windows. This pdf doc is properly printed by PDFBox 1.8 and 2.0.
The issue is not reproduced on Linux. The pdf document in question is properly printed by PDFBox 1.8, 2.0, and PDFBox with custom Graphics2D.drawString(...) method on Ubuntu 20.04.
Further investigations showed that the font which is not properly printed with Graphics2D.drawString(...) method has an empty font name.
To reproduce the issue I created a simple test font which contains only capital letters "ABCDEF" and saved it with empty font family name (see attached fonts SampleBow.ttf and SampleBowMissedFamilyName.ttf).
Run the code below with the provided font which has an empty font name:
> java PrintFontSample SampleBowMissedFamilyName.ttf
The sample prints the text with the provided font using 3 ways:
- Graphics2D.drawString(...)
- Graphics2D.drawGlyphVector(...)
- Graphics2D.drawGlyphVector(...) using transformed glyphs
The first and the second methods use GDI TextOut method to print a text and the third method draws a text as a Path in GDI.
The attached sample-doc-without-fix.pdf doc shows how the sample is printed using jdk 16. The first and the second lines are printed with thin lines and only the third line is printed by the provided font.
The reason is that an empty string is provided as a family font name to awt_PrintJob.jFontToWFontA(...) method [4] and the expected font is not selected in GDI.
The proposed solution could be to return false when an empty family font name is passed to awt_PrintJob.jFontToWFontA(...) method so the text printing falls back to using GDI print Path method.
[1] https://github.com/apache/pdfbox/blob/41ae21bd4c3f304373d3b05f63af5325df248019/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java#L352
[2] https://github.com/apache/pdfbox/blob/4f14dee47ff821e44d9e2ff11532959d95e94d5b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java#L512
[3] https://github.com/apache/pdfbox/commit/7d9f08516c6c9967351f426bbb9d4b6104257835#diff-fea229ecdbc8fbc77551966810d22ce23a3d993e2df3d70c281eefc44fdf65f6
[4] https://github.com/openjdk/jdk/blob/e16d568c1f5d7030b9e038e21fb3815ae5b1163a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp#L2264
--- PrintFontSample.java ---
import javax.print.PrintServiceLookup;
import javax.swing.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import java.io.File;
public class PrintFontSample {
private static final String TEXT = "ABCDEF";
private static final float FONT_SIZE = 43;
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.printf("Provide path to the font file:%n");
System.err.printf(" > PrintFontSample SampleBowMissedFamilyName.ttf%n");
System.exit(1);
}
File fontFile = new File(args[0]);
if (!fontFile.exists()) {
System.err.printf("Provided font file does not exist: %s%n", args[0]);
System.exit(1);
}
final Font font = Font
.createFont(Font.TRUETYPE_FONT, fontFile)
.deriveFont(FONT_SIZE);
SwingUtilities.invokeAndWait(() -> {
try {
Printable printable = new PrintSample(font);
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintService(PrintServiceLookup.lookupDefaultPrintService());
job.setPrintable(printable);
job.print();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
static class PrintSample implements Printable {
private final Font font;
public PrintSample(Font font) {
this.font = font;
}
@Override
public int print(Graphics graphics, PageFormat pageFormat, int index) {
if (index == 0) {
drawText((Graphics2D) graphics, font, TEXT, 100, 150);
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}
private static void drawText(Graphics2D g, Font font, String text, int x, int y) {
int dy = (int) FONT_SIZE + 5;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int fontSize = font.getSize();
// draw string
g.setFont(font);
g.drawString(text, x, y);
// draw GlyphVector
FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true);
GlyphVector glyphs = font.createGlyphVector(frc, text);
g.drawGlyphVector(glyphs, x, y + dy);
// draw scaled GlyphVector
glyphs = font.deriveFont(1.0f).createGlyphVector(frc, text);
AffineTransform scale = AffineTransform.getScaleInstance(fontSize, fontSize);
for (int i = 0; i < glyphs.getNumGlyphs(); i++) {
glyphs.setGlyphTransform(i, scale);
}
g.drawGlyphVector(glyphs, x, y + 2 * dy);
}
}
--- --- ---
Recent fix to PDFBox allows to pass a custom PDFRenderer to PDFPrintable [3] so it is possible to override PDFBox PageDrawer.showGlyph(...) method and use Graphics2D.drawString(...) method to draw a text.
Some tests showed that there is a pdf document which prints all but one font properly using Graphics2D.drawString(...) method on Windows. This pdf doc is properly printed by PDFBox 1.8 and 2.0.
The issue is not reproduced on Linux. The pdf document in question is properly printed by PDFBox 1.8, 2.0, and PDFBox with custom Graphics2D.drawString(...) method on Ubuntu 20.04.
Further investigations showed that the font which is not properly printed with Graphics2D.drawString(...) method has an empty font name.
To reproduce the issue I created a simple test font which contains only capital letters "ABCDEF" and saved it with empty font family name (see attached fonts SampleBow.ttf and SampleBowMissedFamilyName.ttf).
Run the code below with the provided font which has an empty font name:
> java PrintFontSample SampleBowMissedFamilyName.ttf
The sample prints the text with the provided font using 3 ways:
- Graphics2D.drawString(...)
- Graphics2D.drawGlyphVector(...)
- Graphics2D.drawGlyphVector(...) using transformed glyphs
The first and the second methods use GDI TextOut method to print a text and the third method draws a text as a Path in GDI.
The attached sample-doc-without-fix.pdf doc shows how the sample is printed using jdk 16. The first and the second lines are printed with thin lines and only the third line is printed by the provided font.
The reason is that an empty string is provided as a family font name to awt_PrintJob.jFontToWFontA(...) method [4] and the expected font is not selected in GDI.
The proposed solution could be to return false when an empty family font name is passed to awt_PrintJob.jFontToWFontA(...) method so the text printing falls back to using GDI print Path method.
[1] https://github.com/apache/pdfbox/blob/41ae21bd4c3f304373d3b05f63af5325df248019/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java#L352
[2] https://github.com/apache/pdfbox/blob/4f14dee47ff821e44d9e2ff11532959d95e94d5b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java#L512
[3] https://github.com/apache/pdfbox/commit/7d9f08516c6c9967351f426bbb9d4b6104257835#diff-fea229ecdbc8fbc77551966810d22ce23a3d993e2df3d70c281eefc44fdf65f6
[4] https://github.com/openjdk/jdk/blob/e16d568c1f5d7030b9e038e21fb3815ae5b1163a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp#L2264
--- PrintFontSample.java ---
import javax.print.PrintServiceLookup;
import javax.swing.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import java.io.File;
public class PrintFontSample {
private static final String TEXT = "ABCDEF";
private static final float FONT_SIZE = 43;
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.printf("Provide path to the font file:%n");
System.err.printf(" > PrintFontSample SampleBowMissedFamilyName.ttf%n");
System.exit(1);
}
File fontFile = new File(args[0]);
if (!fontFile.exists()) {
System.err.printf("Provided font file does not exist: %s%n", args[0]);
System.exit(1);
}
final Font font = Font
.createFont(Font.TRUETYPE_FONT, fontFile)
.deriveFont(FONT_SIZE);
SwingUtilities.invokeAndWait(() -> {
try {
Printable printable = new PrintSample(font);
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintService(PrintServiceLookup.lookupDefaultPrintService());
job.setPrintable(printable);
job.print();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
static class PrintSample implements Printable {
private final Font font;
public PrintSample(Font font) {
this.font = font;
}
@Override
public int print(Graphics graphics, PageFormat pageFormat, int index) {
if (index == 0) {
drawText((Graphics2D) graphics, font, TEXT, 100, 150);
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}
private static void drawText(Graphics2D g, Font font, String text, int x, int y) {
int dy = (int) FONT_SIZE + 5;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int fontSize = font.getSize();
// draw string
g.setFont(font);
g.drawString(text, x, y);
// draw GlyphVector
FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true);
GlyphVector glyphs = font.createGlyphVector(frc, text);
g.drawGlyphVector(glyphs, x, y + dy);
// draw scaled GlyphVector
glyphs = font.deriveFont(1.0f).createGlyphVector(frc, text);
AffineTransform scale = AffineTransform.getScaleInstance(fontSize, fontSize);
for (int i = 0; i < glyphs.getNumGlyphs(); i++) {
glyphs.setGlyphTransform(i, scale);
}
g.drawGlyphVector(glyphs, x, y + 2 * dy);
}
}
--- --- ---
- backported by
-
JDK-8269479 Font with missed font family name is not properly printed on Windows
-
- Resolved
-
-
JDK-8270525 Font with missed font family name is not properly printed on Windows
-
- Resolved
-
- links to
-
Commit openjdk/jdk11u-dev/5a7e7d3b
-
Commit openjdk/jdk/e9370a13
-
Review openjdk/jdk11u-dev/62
-
Review openjdk/jdk/3631
(1 links to)