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

2024-03-08

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

http://www.coderanch.com/t/556009/open-source/PdfBox-Replace-String-double-pdf 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 字符?

EDIT:

Screenshot: enter image description here

EDIT 2:

我搜索了 PDFTextStripper 及其超类中的 pdfbox 源代码,发现了文本是如何提取的:

在 processStream 方法的开头,我们有

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

当剥离 processEncodedText 中的文本时,使用 PDFont 类的实例,如下所示:

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

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

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

新问题是,当我使用相同的两行代码实例化 PDFont 类时,我得到一个“null”字体类,因此我无法使用 .encode(...) 方法。 这些类的源代码在这里:http://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFStreamEngine.java http://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFStreamEngine.java and http://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFTextStripper.java http://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 位字符。为了确定为每个字节绘制什么字形,该字节被推入该字体的编码向量。编码向量将字节映射到字形名称,然后在字体中查找该字形名称并将其绘制在页面上。请注意,这个描述是半真半假的(稍后会详细介绍)。

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

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

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

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

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

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

因此,当我看到有人试图简单地替换 PDF 内容中的一大块文本时,我看到的只是一个痛苦的世界。对于大多数正常的 PDF 来说,这在 90% 的情况下都有效,但对于任何奇异的东西 - 祝你好运。 PDF 的文本渲染怪癖已经足够让人痛苦了,以至于有时更容易将其视为只写格式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java PDFBox - 读取和修改带有特殊字符(变音符号)的 pdf 的相关文章

随机推荐

  • 准备卸载,就像 Inno Setup 中的准备安装页面一样

    我需要检查多个 exe 文件是否正在运行 通过安装程序安装 然后提示用户关闭它们 如果它们正在运行 如果没有则取消卸载过程 有没有办法在安装中为卸载程序提供类似 准备 页面之类的内容 或者我该如何实施这样的检查 甚至一个消息框也将是完美的
  • Shapefile 到 TopoJSON 转换问题

    I m trying to convert a shapefile to GeoJSON and then to TopoJSON as described in Let s Make a Map http bost ocks org mi
  • 删除最后一次出现的字符

    A 今天在 talkstats com 上发现了这个问题 http www talkstats com showthread php 36897 regular expressions其中发布者想要使用正则表达式删除字符串的最后一个句点 而
  • 刷新jsp文件时线程锁定

    在重负载下 当 GZipping 和解压缩 JSP 文件时 我看到很多线程被锁定 线程转储如下所示 似乎来自大小为 14Kb 的 header jsp http 0 0 0 0 8080 304 daemon prio 3 tid 0x00
  • ASP.NET 页面上的 MS SQL 超时,但 SSMS 中没有

    当存储过程在我们的 ASP NET 页面之一上执行时 它在 SQL Server 上超时 但出现异常Timeout expired The timeout period elapsed prior to completion of the
  • 在 Python 中使用带有正则表达式的 OR 语句时防止列表中出现空元素

    我正在使用正则表达式从网站编译价格 PriceFinder re compile lt n s b d d 2 lt lt FF0000 gt b d d 2 lt Price re findall PriceFinder str soup
  • Cypher - 删除具有特定值的所有属性

    我正在寻找一种方法来删除数据库中任何节点的每个属性 使用 Cypher 具有特定值 Context我从关系表中获取了一个包含大量 NULL 值的 csv 批量文件 LOAD CSV将它们作为价值观 删除它们 用 csv 文件中的空 替换它们
  • 使用 ssh 检查远程主机上是否存在文件

    我想检查远程主机上是否存在某个文件 我试过这个 if ssh user localhost p 19999 e home user Dropbox path Research and Development Puffer and Traps
  • SQLSRV PHP for SQL Server 不是有效的 Win32 应用程序

    这是我的设置 Windows Server 2008 R2 64 位 阿帕奇 2 4 4 64 位 PHP 5 4 15 32位 64位仍处于实验阶段 线程安全 VC9编译器 Microsoft SQL Server 2012 本机客户端
  • 锚元素的 ping 属性跨浏览器如何?

    a 是 HTML5 锚元素中一个相对较新 相对未知的属性 它的跨浏览器兼容性如何 我查看了 MDN 等在线资源http caniuse com http caniuse com 但没有发现任何表明浏览器支持的信息 我想知道这是否是 2014
  • 在docker中安装.net框架4.7.2

    我是 Net 环境的新手 我正在尝试为我的公司实施 docker 他们之前使用的是 4 5 所以我在 dockerfile 中使用了以下语句 RUN Install WindowsFeature NET Framework 45 ASPNE
  • 如何设置Spark执行器内存?

    我已经设定Spark executor 内存 to 2048m 并且在 UI 环境 页面中 我可以看到该值已正确设置 但是在 Executors 页面中 我看到只有1个执行器 它的内存是265 4MB 非常奇怪的价值 为什么不是256MB
  • const char* 连接

    我需要连接两个 const 字符 如下所示 const char one Hello const char two World 我该怎么做呢 我通过了这些char 来自具有 C 接口的第三方库 所以我不能简单地使用std string反而
  • 显示所有 messageHeader 的值

    我想知道显示所有 MessageHeaders 服务器端的最佳方式是什么 实际上我知道的唯一方法如下 OperationContext Current IncomingMessageHeaders GetHeader
  • 将 Powershell 核心设置为 Windows/Linux 上的默认 GNU Make shell

    在 Windows 上的 makefile 中 使用以下 make 版本 PS C projects gt make version GNU Make 4 1 Built for i686 w64 mingw32 Copyright C 1
  • 一般:Angular2 中的异步验证

    从几个晚上开始 我就开始在 augular2 中进行表单验证 所有基本案例都很容易实现并且工作正常 但我坚持使用异步验证 我创建了一个非常小的例子http plnkr co edit Xo8xwJjhlHkXrunzS8ZE http pl
  • Z3 将数组的默认值设置为零

    我正在尝试求解数组表达式的模型 其中数组的默认值等于 0 例如 我正在尝试解决这个例子 但我总是得到未知的结果 declare const arr Array Int Int declare const arr2 Array Int Int
  • 如何获取函数签名对应的TypedDict?

    假设我有一个像这样的函数签名 def any foo bar Bar with baz Optional Baz None with datetime Optional datetime None effective Optional bo
  • 如何在asp.net中发送邮件

    你好 我编写了在asp net中发送邮件的代码 如下所示 MailMessage mailMessage new MailMessage mailMessage From email protected cdn cgi l email pr
  • Java PDFBox - 读取和修改带有特殊字符(变音符号)的 pdf

    我正在尝试使用此方法修改 pdf 第一个代码块 使用 PDFStreamParser 并迭代 PDFOperator 然后在需要时更新 COSString http www coderanch com t 556009 open sourc