Type0 CMap 解析问题

Swa*_*oop 2 pdf fonts adobe scanning ios

我目前正在使用 PDFKitten 进行 iOS PDF 扫描。我正在尝试提取文本以在具有 Type0 字体的 PDF 中进行搜索。我无法从 PDF 中提取文本。ToUnicode中的某些条目丢失,有些条目被误解。CMap 的解析可能有问题吗?如果我没有完整的CMap,我应该如何导出它?我可以为这些缺失的ToUnicode条目获取外部条目吗?

谢谢

mkl*_*mkl 5

PDF规范在第 9.10.2 节将字符代码映射到 Unicode 值中提供了有关如何提取文本内容的提示:

\n\n
    \n
  • 如果字体字典包含ToUnicode CMap(请参阅 9.10.3“ToUnicode CMap”),请使用该 CMap 将字符代码转换为 Unicode。

  • \n
  • 如果字体是使用预定义编码MacRomanEncodingMacExpertEncodingWinAnsiEncoding之一的简单字体,或者其编码的Differences数组仅包含取自 Adob​​e 标准拉丁字符集的字符名称和符号中的命名字符集字体(见附件D):

    \n\n

    a) 根据表 D.1 和 font\xe2\x80\x99s Differences数组将字符代码映射到字符名称。

    \n\n

    b) 在Adob​​e Glyph List(参见参考书目)中查找字符名称以获取\n相应的 Unicode 值。

  • \n
  • 如果字体是使用表 118 中列出的预定义 CMap 之一的复合字体(Identity\xe2\x80\x93H 和 Identity\xe2\x80\x93V 除外)或其后代 CIDFont 使用 Adob​​e-GB1、Adobe-CNS1, Adobe-Japan1 或 Adob​​e-Korea1 字符集:

    \n\n

    a) 根据 font\xe2\x80\x99s CMap 将字符代码映射到字符标识符(CID)。

    \n\n

    b) 从CIDSystemInfo字典中获取 font\xe2\x80\x99s CMap(例如 Adob​​e 和 Japan1)所使用的字符集的注册表和排序。

    \n\n

    c) 通过连接注册表和步骤 (b) 中获得的排序来构造第二个 CMap 名称,格式为registry\xe2\x80\x93ordering\xe2\x80\x93UCS2(例如 Adob​​e\xe2\x80\x93Japan1\xe2\x80 \x93UCS2)。

    \n\n

    d) 获取具有步骤 (c) 中构造的名称的 CMap(可从 ASN 网站获得;参见参考书目)。

    \n\n

    e)根据步骤(d)中获得的CMap对步骤(a)中获得的CID进行映射,产生Unicode值。

  • \n
\n\n

此外,如第 9.10.1 节所示,

\n\n
    \n
  • 结构元素或标记内容序列的 ActualText 条目(参见 14.9.4,“替换\n文本”)可用于直接指定文本内容
  • \n
\n\n

根据规范,如果这些方法无法生成 Unicode 值,则无法确定字符代码代表什么。这并不完全正确。例如,嵌入式字体程序可能包含它们自己的 Unicode 映射;但此类附加信息来源超出了实际的 PDF 格式。

\n\n

编辑

\n\n

OP 通过邮件提供了有问题的文件 iPhoneConfigurationProfileRef-2013-GM.pdf 并指出

\n\n
\n

我对每个字形都遇到问题。

\n\n

问题是 PDF 中存在的范围不完整,并且与 adobe-identity-cmap 文件不同。

\n\n

如果我只使用 PDF 中嵌入的 CMap,则不会获得每个字符的映射,如果我使用 adobe,则所有映射都是错误的。

\n
\n\n

由于他没有获得任何字形的映射,让我们以标题页为例。

\n\n

内容流包含与文本提取相关的以下操作:

\n\n
BT \n50 0 0 50 60 669.225 Tm \n/G1 1 Tf \n<0025> Tj \nET \nBT \n50 0 0 50 87.6 669.225 Tm \n/G1 1 Tf \n<005100500048004b004900570054> Tj \nET \nBT \n50 0 0 50 238 669.225 Tm \n/G1 1 Tf \n<0043> Tj \nET \nBT \n50 0 0 50 261.45 669.225 Tm \n/G1 1 Tf \n<0056004b00510050> Tj \nET \nBT \n50 0 0 50 355.4 669.225 Tm \n/G1 1 Tf\n<0032> Tj \nET \nBT \n50 0 0 50 380.75 669.225 Tm \n/G1 1 Tf \n<0054> Tj \nET \nBT \n50 0 0 50 396.55 669.225 Tm \n/G1 1 Tf \n<00510048004b004e0047> Tj \nET \nBT 50 0 0 50 60 609.225 Tm \n/G1 1 Tf \n<0034> Tj \nET \nBT \n50 0 0 50 86.65 609.225 Tm \n/G1 1 Tf \n<00470048> Tj \nET \nBT\n50 0 0 50 125.05 609.225 Tm \n/G1 1 Tf \n<00470054> Tj \nET \nBT \n50 0 0 50 165.45 609.225 Tm \n/G1 1 Tf \n<004700500045> Tj \nET \nBT \n50 0 0 50 238.9 609.225 Tm \n/G1 1 Tf \n<0047> Tj \nET\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以我们只需要查看第 1 页上的字体G1。幸运的是,该字体有一个ToUnicode映射:

\n\n
/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n  /Registry (Adobe)\n  /Ordering (UCS)\n  /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000><FFFF>\nendcodespacerange\n1 beginbfchar\n<000f><002d 2010>\nendbfchar\n15 beginbfrange\n<0002><0002><0020>\n<0004><000c><0022>\n<000e><000e><002c>\n<0010><001d><002e>\n<001f><001f><003d>\n<0022><0032><0040>\n<0034><003d><0052>\n<003f><003f><005d>\n<0041><0041><005f>\n<0043><005c><0061>\n<005e><005e><007c>\n<008a><008a><00a9>\n<00a4><00a4><2014>\n<00a5><00a6><201c>\n<00a8><00a8><2019>\nendbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend \n
Run Code Online (Sandbox Code Playgroud)\n\n

尝试应用此映射会得到(基于显式beginbfrange...endbfrange条目):

\n\n
<0025> Tj                          % "C"       = <0043>                         due to <0022><0032><0040>\n<005100500048004b004900570054> Tj  % "onfigur" = <006f006e00660069006700750072> due to <0043><005c><0061>\n<0043> Tj                          % "a"       = <0061>                         due to <0043><005c><0061>\n<0056004b00510050> Tj              % "tion"    = <00740069006f006e>             due to <0043><005c><0061>\n<0032> Tj                          % "P"       = <0050>                         due to <0022><0032><0040>\n<0054> Tj                          % "r"       = <0072>                         due to <0043><005c><0061>\n<00510048004b004e0047> Tj          % "ofile"   = <006f00660069006c0065>         due to <0043><005c><0061>\n<0034> Tj                          % "R"       = <0052>                         due to <0034><003d><0052>\n<00470048> Tj                      % "ef"      = <00650066>                     due to <0043><005c><0061>\n<00470054> Tj                      % "er"      = <00650072>                     due to <0043><005c><0061>\n<004700500045> Tj                  % "enc"     = <0065006e0063>                 due to <0043><005c><0061>\n<0047> Tj                          % "e"       = <0065>                         due to <0043><005c><0061>\n
Run Code Online (Sandbox Code Playgroud)\n\n

这与页面的外观非常匹配:

\n\n

扉页截图

\n