【问题标题】:PDFBox “special” characters in HelveticaHelvetica中的PDFBox“特殊”字符
【发布时间】:2015-11-10 18:48:36
【问题描述】:

我正在使用 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 方法存在的问题,但显然有些东西不起作用。

编辑:根据 cmets 的要求,这里是异常的完整堆栈跟踪:

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)

【问题讨论】:

  • 这不是重复的,我所说的字符是根据规范在基本字体中的。
  • 您引用的是 Adob​​e 与 pdfbox,您希望从正确的来源引用什么,例如 pdfbox.apache.org/2.0... 您知道 Adob​​e 不制作 PDFBox? Apache 维护 pdfbox 为什么要引用 adobe 可以做什么 VS pdfbox 可以做什么(当两者完全不同时)?
  • 这是 PDF 标准 ISO-32000-1 所基于的格式 (iso.org/iso/home/news_index/news_archive/news.htm?refid=Ref1141)。我知道 PDFBox 不是 Adob​​e 制作的,我不明白你为什么要采取这样的语气。
  • 问题是你正试图为引用权编写 unicode 字符,这与 windows 1252 字符集使用的字符不同。你基本上想写字符“\u0092”。

标签: java pdfbox


【解决方案1】:

查看 PDFBox 代码,它确实看起来像一个错误。如果您查看PDType1Font.encode() 方法,如果代码点> 0xFF,它会自动抛出。但是,如果在这种情况下继续执行逻辑,则 GlyphList 会将“\u2019”字符转换为“quoterright”,这将是字体中的有效字符。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 您可以包含 fontbox 库,该库将有一个 FontFileFinder,用于以较少系统依赖的方式获取字体文件。
    • @matt 绝对是生产代码的好主意。或者带上你自己的字体,例如作为资源,如果您不想依赖部署计算机上找到的字体。
    • 我刚刚看了FontFileFinder;对于 Windows 计算机,它使用RunTime.exec()。根据使用 PDFBox 的环境,RunTime.exec() 的使用可能会受到SecurityManager 的限制。因此,如果您打算部署到安全的环境中,您绝对应该携带自己的字体。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 2013-04-04
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 2012-09-08
    • 2011-07-28
    相关资源
    最近更新 更多