Java PDFBox“;特别”;Helvetica中的人物

Java PDFBox“;特别”;Helvetica中的人物,java,pdfbox,Java,Pdfbox,我正在使用PDFBOX2.0.0-SNAPSHOT以Java构建PDF。它对于非常基本的字符(例如[a-zA-Z9-0])工作正常,但对于稍微高级的字符,例如'(quoterright)我会遇到编码错误。这是我的密码: PDDocument pdf = new PDDocument(); PDPage page = new PDPage(PDRectangle.A4); pdf.addPage(page); PDPageContentStream contents = new PDPageCo

我正在使用PDFBOX2.0.0-SNAPSHOT以Java构建PDF。它对于非常基本的字符(例如
[a-zA-Z9-0]
)工作正常,但对于稍微高级的字符,例如
'
quoterright
)我会遇到编码错误。这是我的密码:

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();
我得到一个例外:

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)
无法在字体Helvetica中编码U+2019。类型1字体仅支持8位 代码点

我在的第D.1节中查找了非嵌入式字体的支持字符,应该支持此字符

事实上,如果我使用,我可以插入正确的字符:

// ...

// String text = "’";
// contents.showText(text);
byte[] commands = "(x) Tj ".getBytes();
commands[1] = (byte)145;    // = 221 octal = quoteright in WinAnsi
contents.appendRawCommands(commands);

// ...
但这并不是一个切实可行的解决方案。除了手动搜索字符串中可能包含的每个字符带来的不便外,
appendRawCommands
方法现在已被弃用

那么,这是怎么回事?从这一点可以看出,
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”字符转换为“quoterRight”,这将是字体中的有效字符。

正如@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
中观察到的错误。

可能重复:这不是重复,我所说的字符是根据规范使用的基本字体。您引用的是Adobe vs pdfbox,您希望从正确的源代码引用什么,例如。。。你知道Adobe不生产PDFBox吗?Apache维护pdfbox为什么要引用adobe可以做什么和pdfbox可以做什么(当两者完全不同时)?这是PDF标准ISO-32000-1所基于的格式()。我知道PDFBox不是由Adobe制作的,我不明白你为什么要采用这种语气。问题是你正在尝试为quote right编写unicode字符,它与windows 1252字符集使用的字符不同。实际上,您需要编写字符“\u0092”。您可以包括fontbox库,该库将具有FontFileFinder,用于以较少依赖于系统的方式获取字体文件。@matt肯定是生成代码的好主意。或者,如果您不想依赖部署计算机上的字体,请随身携带您自己的字体,例如作为资源。我刚刚查看了
FontFileFinder
;对于Windows计算机,它使用
RunTime.exec()
。根据PDFBox的使用环境,可以通过
SecurityManager
限制
RunTime.exec()
的使用。因此,如果您计划部署到一个安全的环境中,您肯定应该带上自己的字体。