Helvetica 中的 PDFBox“特殊”字符
PDFBox “special” characters in Helvetica
我正在使用 PDFBox 2.0.0-SNAPSHOT 在 Java 中构建 PDF。它适用于非常基本的字符(例如 [a-zA-Z9-0]
),但我遇到了稍微更高级的字符的编码错误,例如 ’
(quoteright
)。这是我的代码:
PDDocument pdf = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
pdf.addPage(page);
PDPageContentStream contents = new PDPageContentStream(pdf, page);
PDFont font = PDType1Font.HELVETICA;
contents.beginText();
contents.setFont(font, 12);
// ...
String text = "’";
contents.showText(text);
contents.endText();
contents.close();
我得到这个异常:
Can't encode U+2019 in font Helvetica. Type 1 fonts only support 8-bit
code points
我在PDF specification的D.1部分查了非嵌入字体支持的字符,应该支持这个字符。
的确,如果我使用this trick,我可以插入正确的字符:
// ...
// String text = "’";
// contents.showText(text);
byte[] commands = "(x) Tj ".getBytes();
commands[1] = (byte)145; // = 221 octal = quoteright in WinAnsi
contents.appendRawCommands(commands);
// ...
但这并不是一个切实可行的解决方案。除了手动搜索字符串中可能存在的每个字符带来的不便之外,appendRawCommands
方法现已弃用。
那么,这是怎么回事? the answer from above 暗示 showText
不应该存在旧 drawString
方法的问题,但显然有些东西不起作用。
编辑: 根据评论中的要求,这里是异常的完整堆栈跟踪:
Exception in thread "main" java.lang.IllegalArgumentException: Can't encode U+2019 in font Helvetica. Type 1 fonts only support 8-bit code points
at org.apache.pdfbox.pdmodel.font.PDType1Font.encode(PDType1Font.java:343)
at org.apache.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:285)
at org.apache.pdfbox.pdmodel.font.PDFont.getStringWidth(PDFont.java:314)
at com.fatfractal.test.PDFBoxTest.textWidth(PDFBoxTest.java:148)
at com.fatfractal.test.PDFBoxTest.showFlowingTextAt(PDFBoxTest.java:128)
at com.fatfractal.test.PDFBoxTest.build(PDFBoxTest.java:73)
at com.fatfractal.test.PDFBoxTest.main(PDFBoxTest.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
看PDFBox的代码,确实是个bug。如果您查看 PDType1Font.encode()
方法,如果代码点 > 0xFF,它会自动抛出。但是,如果逻辑在这种情况下继续进行,则 GlyphList 会将“\u2019”字符转换为 "quoteright",这将是字体中的有效字符。
正如@jtahlborn 在他的回答中解释的那样,PDType1Font.encode()
在当前的 2.0.0 候选版本中被破坏了。
与 1.x.x PDPageContentStream
方法 drawString
相比,2.0.0 候选发布方法 showText
是编码感知的。
作为 work-around,因此,您可以使用带有子集嵌入的复合字体,例如在标准 MS Windows 安装上:
InputStream fontStream = new FileInputStream("c:/Windows/Fonts/ARIALUNI.TTF");
PDType0Font font = PDType0Font.load(pdf, fontStream);
使用此字体您的代码不会因 "’"
而失败,因为复合字体 类 没有在此处 PDType1Font
中观察到的错误。
我正在使用 PDFBox 2.0.0-SNAPSHOT 在 Java 中构建 PDF。它适用于非常基本的字符(例如 [a-zA-Z9-0]
),但我遇到了稍微更高级的字符的编码错误,例如 ’
(quoteright
)。这是我的代码:
PDDocument pdf = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
pdf.addPage(page);
PDPageContentStream contents = new PDPageContentStream(pdf, page);
PDFont font = PDType1Font.HELVETICA;
contents.beginText();
contents.setFont(font, 12);
// ...
String text = "’";
contents.showText(text);
contents.endText();
contents.close();
我得到这个异常:
Can't encode U+2019 in font Helvetica. Type 1 fonts only support 8-bit code points
我在PDF specification的D.1部分查了非嵌入字体支持的字符,应该支持这个字符。
的确,如果我使用this trick,我可以插入正确的字符:
// ...
// String text = "’";
// contents.showText(text);
byte[] commands = "(x) Tj ".getBytes();
commands[1] = (byte)145; // = 221 octal = quoteright in WinAnsi
contents.appendRawCommands(commands);
// ...
但这并不是一个切实可行的解决方案。除了手动搜索字符串中可能存在的每个字符带来的不便之外,appendRawCommands
方法现已弃用。
那么,这是怎么回事? the answer from above 暗示 showText
不应该存在旧 drawString
方法的问题,但显然有些东西不起作用。
编辑: 根据评论中的要求,这里是异常的完整堆栈跟踪:
Exception in thread "main" java.lang.IllegalArgumentException: Can't encode U+2019 in font Helvetica. Type 1 fonts only support 8-bit code points
at org.apache.pdfbox.pdmodel.font.PDType1Font.encode(PDType1Font.java:343)
at org.apache.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:285)
at org.apache.pdfbox.pdmodel.font.PDFont.getStringWidth(PDFont.java:314)
at com.fatfractal.test.PDFBoxTest.textWidth(PDFBoxTest.java:148)
at com.fatfractal.test.PDFBoxTest.showFlowingTextAt(PDFBoxTest.java:128)
at com.fatfractal.test.PDFBoxTest.build(PDFBoxTest.java:73)
at com.fatfractal.test.PDFBoxTest.main(PDFBoxTest.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
看PDFBox的代码,确实是个bug。如果您查看 PDType1Font.encode()
方法,如果代码点 > 0xFF,它会自动抛出。但是,如果逻辑在这种情况下继续进行,则 GlyphList 会将“\u2019”字符转换为 "quoteright",这将是字体中的有效字符。
正如@jtahlborn 在他的回答中解释的那样,PDType1Font.encode()
在当前的 2.0.0 候选版本中被破坏了。
与 1.x.x PDPageContentStream
方法 drawString
相比,2.0.0 候选发布方法 showText
是编码感知的。
作为 work-around,因此,您可以使用带有子集嵌入的复合字体,例如在标准 MS Windows 安装上:
InputStream fontStream = new FileInputStream("c:/Windows/Fonts/ARIALUNI.TTF");
PDType0Font font = PDType0Font.load(pdf, fontStream);
使用此字体您的代码不会因 "’"
而失败,因为复合字体 类 没有在此处 PDType1Font
中观察到的错误。