【问题标题】:Encoding of PDF text stringPDF文本字符串的编码
【发布时间】:2015-06-10 15:07:37
【问题描述】:

我正在开发 PDF 解析器(文本提取)。

当页面需要 Flate 解码(来自 zlib 压缩)时,我的代码能够解压缩内容流,然后输出(流对象)如下所示:

BT
56.8 721.3 Td 
/F2 12 Tf
[<01>2<0203>2<04>-10<0503>2<04>-2<0506070809>2<0A>1<0B>]TJ
ET

我对字符串数组(TJ 的操作数)感兴趣。

这个数组中似乎包含多个十六进制编码的字符串,但对应的十六进制值没有意义。相反,它出现了一个类似 010203... 的序列,类似于 lz77 压缩。

  • PDF 是否有多个压缩级别?
  • 如何从上面的字符串数组中获取纯文本?

【问题讨论】:

    标签: pdf


    【解决方案1】:

    在开始这样一个雄心勃勃的项目之前,您应该让自己熟悉完整 official PDF-1.7 specification。请注意:这是一个 756 页的文档,它引用了大约 90 个其他文档,它声明它们也是 PDF 的“规范”

    您将了解到,为了将 PDF 源代码反转为文本内容,您必须反向应用字体使用的 编码。可以使用 5 种规范定义的标准编码:

    1. StandardEncoding
    2. MacRomanEncoding
    3. WinAnsiEncoding
    4. PDFDocEncoding
    5. MacExpertEncoding

    除此之外,还可以有 CustomEncoding(当嵌入字体是子集时发挥作用,并且不包含字体定义的所有字形,但仅包含那些文件要求的字形)。如果在 PDF 中定义了 /ToUnicode 表,则只能反转 CustomEncode-d 文本。只有这样,您才能将编码字符反向映射到字符名称。

    您还将了解到,不仅有 一个,还有 四个 运算符可用于显示文本字符串:

    1. Tj“显示文字”
    2. TJ“显示文本,允许单独的字形定位”
    3. '“移动到下一行并显示文本”
    4. " : “设置单词和字符间距,移动到下一行,并显示文本”

    此外,有三种不同的方式来表示文本字符串。这里给出了字符串 "string" 的示例:

    1. (string):这在括号内使用标准可打印 ASCII 字符(仅适用于拉丁/ASCII 文本部分)。
    2. (\163\164\162\151\156\147) :这使用 八进制 字符代码(也在括号内),如“附录 D(规范)字符集和编码”中列出的规范文件。
    3. &lt;737472696E67&gt; :这使用尖括号内的十六进制编码字符代码。

    文本提取器的问题如下:

    1. 使用可打印的 ASCII 字符(上面的1.)和八进制字符代码(上面的2. ) 可以混合。以下所有内容也是字符串 "string" 的“合法”表示(列表不完整!):

       (\163tring)Tj
       (\163\164\162\151\156g) Tj
       (st\162i\156g)  Tj
       ...
      
    2. 使用十六进制编码的字符代码(上面的3.)也不是直截了当的,因为以下所有表示都是等价的:

      <73 74 72 69 6E 67> TJ
      
      <73 7472 696E67> TJ
      
      <7 374 7 269 6E 67>TJ
      
      <73   74    72696E 67> TJ
      
      <73
        74 7
        2 69 6E 67>
      TJ
      

    有关 PDF 规范允许(或 Adob​​e 查看器允许)的更多怪异,另请参见示例:

    我自己最近创建了一系列手工编码的 PDF 文件,这些文件展示了丢失、不正确、被操纵或正确的 /ToUnicode 表如何影响任何 PDF 到文本反转的结果:


    最后看一下OP提供的PDF源代码的小sn-p:

    BT
    56.8 721.3 Td 
    /F2 12 Tf
    [<01>2<0203>2<04>-10<0503>2<04>-2<0506070809>2<0A>1<0B>]TJ
    ET
    
    • BTET 表示文本显示部分的开始和结束

    • 56.8 721.3 Td将当前点定位到坐标“水平方向56.8点,垂直方向721.3点”

    • 12 Tf 将字体大小设置为 12 磅。

    • /F1 将要使用的字体设置为 PDF 文档中其他地方定义的字体。该字体还在某处设置了字体编码(可能还有/ToUnicode 表)。当在文本字符串中看到特定的字符代码时,字体编码将确定应绘制哪种字形。

    • [&lt;01&gt;2&lt;0203&gt;2&lt;04&gt;-10&lt;0503&gt;2&lt;04&gt;-2&lt;0506070809&gt;2&lt;0A&gt;1&lt;0B&gt;]TJ

    这最后一部分可以分为以下几部分:

    • &lt;01&gt;2&lt;01&gt; 是第一个字符代码。 2 是使用文本显示运算符TJ 时允许的“单独字形定位”的参数。
    • &lt;0203&gt;2&lt;0203&gt; 是另外两个字符代码。 2 又是TJ“个别字形定位”的参数。
    • &lt;04&gt;-10&lt;04&gt; 是第四个字符代码。 -10 再次用于 “个别字形定位”TJ
    • &lt;0503&gt;2&lt;05&gt;是第五个字符代码,&lt;03&gt;是第三个字符代码(之前用过)。 2 用于“个别字形定位”...

    个别字形定位个别字形定位的工作原理如下:

    • 正数将下一个字形移到(减小字形间距到下一个字形)。
    • 负数将下一个字形移到右侧(为下一个字形添加更多空间)。
    • 数字本身代表当前单位的千分之一。

    字符代码的含义:要了解第一个、第二个、第三个……最后一个字符代码的含义,您必须在 PDF 的 /ToUnicode 表中查找这些代码。如果它没有嵌入这样的表,那就倒霉了!

    检查文本是否易于提取:要检查您的 PDF 是否适合文本提取,您可以使用命令行工具 pdffonts。这是一个示例输出:

    $ pdffonts sample.pdf
      name                      type          encoding     emb sub uni object ID
      ------------------------- ------------- ------------ --- --- --- ---------
      IADKRB+Arial-BoldMT       CID TrueType  Identity-H   yes yes yes     10  0
      SSKFGJ+ArialMT            CID TrueType  Custom       yes yes no      11  0
    

    在上述示例中,子集字体 SSKFGJ+ArialMT 使用自定义编码,但 PDF 中没有此字体的 /ToUnicode,如标题为 uni 的列所示。因此,提取使用此字体显示的文本并不容易(提取需要手动逆向工程——但您也可以只“阅读”PDF 页面)。

    【讨论】:

    • 我有一个 /ToUnicode 表,我得到的内容是像这样的尖括号文本 - 如何解码文本?
    • &lt;00360048...&gt; 部分是十六进制编码的文本字符串。您可以手动对其进行解码(通过参考 ASCII 表),或者像这样运行 Ghostscript 命令行:IFS=" "; gs -dNODISPLAY -q -c "&lt;3648&gt;" == quit 进行解码...
    • 你能帮我解码这个吗:
    • @KaranAhuja: 十六进制解码这给出了一个 ASCII 字符串 (&amp;/*\022*2'5\(-\003+,1-$:$',\003\(6&amp;52:)。现在需要/ToUnicode 表将其转换为(可能)可读的文本......
    • 解码十六进制编码文本字符串的更简单方法是使用 xxd -r -p 而不是 Ghostscript。例如:echo '0026002f002a0012002a0032002700350028002d0003002b002c0031002d0024003a00240027002c000300280036002600350032003a' | xxd -r -p
    【解决方案2】:

    阿布舍克,

    这不是一个简单的问题,不幸的是它表明您还没有阅读 PDF 规范。你应该这样做。

    您可以在此处下载 Acrobat SDK: http://www.adobe.com/devnet/acrobat/sdk/eula.html

    其中一部分是 PDF 规范,它是一份非常重要的文档,解释了 PDF 的来龙去脉(包括您问题的答案)。

    简而言之 - 而不是作为阅读文档的替代品 - 您正在查看的是 /F2 12 Tf 命令设置的字体编码中的字符值,该命令设置随后编写文本时使用的特定字体。

    【讨论】:

    • 啊,我正在查看 PDF 规范的相关部分,但我从未想过它可以由字体定义:) 感谢您指出正确的方向,我会阅读更多内容。
    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    相关资源
    最近更新 更多