Java PDFBox - 阅读和修改带有特殊字符(变音符号)的 pdf

标签 java pdf utf-8 diacritics pdfbox

我正在尝试使用此方法修改 pdf(第一个代码块 - 使用 PDFStreamParser 并遍历 PDFOperator,然后在需要时更新 COSString):

http://www.coderanch.com/t/556009/open-source/PdfBox-Replace-String-double-pdf

我遇到了一些 UTF-8 字符(变音符号)的问题:当我打印要更新的文本时,它显示为“Societ? ?ii Na?ionale”(其中“?”是一个代码,例如0002 或 0004)。

有趣的是:

  1. 当我编写更新后的 pdf 文件时,字符显示正确(即使我无法检测并替换它们)
  2. 如果我尝试使用 PDFTextStripper 的 getText(...) 剥离文本,文本将被完美提取。
  3. 我尝试了 2 个 pdfbox 版本:1.5.0(其行为如上所述)和 1.8.1(最终的书面 pdf 文件无法正确显示特殊字符,文档中出现“空”字符串)<

我可以对用于更新 pdf 的类做什么(或至少尝试...)以便正确显示所有 UTF-8 字符?

编辑:

屏幕截图:enter image description here

编辑 2:

我在 PDFTextStripper 及其父类(super class)中搜索了 pdfbox 源代码,发现了文本是如何提取的:

在 processStream 方法的开头我们有

graphicsState = new PDGraphicsState(aPage.findCropBox());

当剥离 processEncodedText 中的文本时,PDFont 类的一个实例是这样使用的:

final PDFont font = graphicsState.getTextState().getFont();

文本是从 byte[] 中提取的:

String c = font.encode( string, i, codeLength );

新问题是,当我用相同的两行代码实例化一个 PDFont 类时,我得到一个“空”字体类,因此我不能使用 .encode(...) 方法。 这些类的源代码在这里: http://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFStreamEngine.javahttp://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFTextStripper.java

我正在挖掘更多......

最佳答案

您不能只替换字符串中的文本。我不会轻描淡写地说这个。很多年前在Acrobat上工作过,初版做的是文本搜索工具,所以对文本编码的问题有比较深刻的理解。主要问题是 PDF 中的每个字符串都以某种方式编码。这是因为 PDF 是在 Unicode 普遍可用之前制作的,并且在 PostScript 中有历史。 PosctScript 喜欢非常灵活的字体编码方法,并鼓励重新编码。

所以让我们退后一步,了解整个情况。

在默认情况下,PDF 中的字符串中的字符将被编码为一系列 8 位字符。为了确定为每个字节绘制的字形,字节被推送通过该字体的编码 vector 。编码 vector 将字节映射到字形名称,然后在字体中查找并绘制在页面上。请注意,此描述是半真半假的(稍后会详细介绍)。

大多数生成 PDF 的应用程序都很好,只使用标准编码,例如 StandardEncodingWinAnsiEncoding,其中大部分都非常合理。其他人将使用标准编码以及编码增量,这是标准编码与编码内容之间的差异。

一些应用程序试图在它们生成的 PDF 中更加节俭,因此它们查看它们使用的字形并决定嵌入字体的一个子集。如果他们只使用大写和小写的罗马字母和数字,他们会在没有这些元素的情况下重建字体,并且可能会选择重新索引它们,并提供一个编码 vector ,这样字节 0x00 进入字形“a”,0x01 进入字形 'b' 等等。

现在回到一半的真相。有一类字体是由字符 ID(或 CID)编码的,TrueType 和 OpenType 字体属于这一类。在这种情况下,您可以访问 Unicode,但同样有一个编码步骤,您将字符串(现在是 UTF16BE)映射到 CID,后者用于从字体中获取字形。并且没有特别好的理由,Adobe 使用 PostScript 函数来进行映射。同样,这是大约 3/4 的事实,因为对于中文、日文和韩文字体的旧管理也有不同的编码。

因此,在您愉快地将字符放入 PDF 字体的字符串之前,您必须问几个问题:

  1. 我的字形在字体中吗?
  2. 我的字形在编码中吗?
  3. 我的字形编码是什么?

其中任何一个都可能与您的预期不同。因此,例如,如果你想输入 Ä(a diresis),你必须查看字体是否有它的字形(可能不存在,因为字体是一个子集)。然后字体可能有一个有趣的编码,可能不包括字形。最后,用于 Ä 的实际字节值可能不是标准的。

因此,当我看到有人试图简单地替换 PDF 内容中的一大块文本时,我所看到的只是一个痛苦的世界。对于大多数理智的 PDF,这将在 90% 的时间内起作用,但对于任何异国情调的东西 - 祝你好运。 PDF 的文本呈现怪癖非常令人痛苦,有时更容易将其视为只写格式。

关于Java PDFBox - 阅读和修改带有特殊字符(变音符号)的 pdf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15964704/

相关文章:

Python3 - 无法读取 docx、odt 文件 - UnicodeDecodeError : 'utf-8' codec can't decode byte 0xea in position 10: invalid continuation byte

javascript - PhantomJS 将字符变成坏数据

excel - 显示文本链接以从 Excel 打开特定的 PDF 页面

python - Django/Python : How to convert pptx/docx formats to PDF using python?

java - Giraph 的工作永无止境

java - ArrayList 上的递归二分查找

java - 如何在 JSP 中打开 PDF 文件

php - TCPDF 不显示来自 mysql 的 č、ć、ž、š、đ 仅空白页

java - 在维护表关系/约束的同时自动生成测试数据

java - 如何在 Eclipse 中增加 Java 应用程序的堆内存