Helvetica

时间:2015-11-10 18:48:36

标签: java pdfbox

我正在使用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();

我得到了这个例外:

  

无法在字体Helvetica中编码U + 2019。 Type 1字体仅支持8位   代码点

我在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)

2 个答案:

答案 0 :(得分:5)

查看PDFBox代码,它看起来真的像个bug。如果您查看PDType1Font.encode()方法,如果代码点为>则自动抛出0xFF的。但是,如果逻辑在这种情况下继续进行,则GlyphList将转换" \ u2019"字符到" quoteright",这将是字体中的有效字符。

答案 1 :(得分:5)

正如@jtahlborn在他的回答中解释的那样,PDType1Font.encode()在当前的2.0.0候选版本中被打破了。

与1.x.x PDPageContentStream方法drawString相比,2.0.0候选方法showText可识别编码。

因此,作为一种解决方法,您可以使用具有子集嵌入的复合字体,例如,在标准的MS Windows安装上:

InputStream fontStream = new FileInputStream("c:/Windows/Fonts/ARIALUNI.TTF");
PDType0Font font = PDType0Font.load(pdf, fontStream);

使用此字体,您的代码不会因"’"而失败,因为复合字体类没有在PDType1Font中观察到错误。