在命令行上导出PDF页面标签

12
我希望能导出一些PDF文档中存储的页面标签以便于解析。我知道可以使用qpdf将PDF转换后再深入挖掘,但这似乎有点过度。是否没有命令行工具可以简单地打印每个页面的页面标签(或与其他元数据一起)?我知道PDFSpy会导出标签,但300美元不是我的选择,最好的解决方案应该是免费的。
2个回答

16

简短回答:
我不知道有任何(免费)工具可以“简单打印”每个页面的页面标签。

此外,使用像qpdf或具有等效功能的工具,您将无法避免扩展压缩对象和对象流。

长回答:
没有这样的工具,因为这些是关于页面标签的唯一可靠的信息:

  1. 每个PDF文档必须包含一个根对象。
  2. 该根对象必须/Type /Catalog
  3. 文档的尾部将显示在哪里找到该对象,使用键/Root后跟间接对象号引用。
  4. 如果 PDF文档使用非标准页面标签,则文档根对象必须有一个名为/PageLabels的条目。

在这里停止相对容易。因为/PageLabels键引用的对象可能包含在压缩的对象流中。这意味着您必须扩展该对象流。

如果您真的成功地获得了ASCII格式的页面标签描述,您会发现它不是易于解析的平面列表(如dictionary):它是一棵数字树。

我不会详细介绍这些复杂性,因为需要一个非常长的文章来描述所有可能的变化。您最好直接在官方ISO PDF-1.7规范中阅读。

但是,我将为您提供一个ASCII PDF代码示例:

213 0 obj
  << /Type /Catalog
     /PageLabels 
        << 
           /Nums 
                 [ 
                   0 <<           % start labeling from page no. 1
                       /S /r      % label with lowercase roman numbers
                     >> 
                   7 <<           % start new labeling from page no. 8
                       /S /D      % label with standard decimal numbers
                     >> 
                   11 <<          % start labeling page no. 12
                       /S /D      % label with decimal numbers...
                       /P (ABCD-) %   ...but using label prefix 'ABCD-'...
                       /St 3      %   ...followed by '3' as the start decimal.
                     >>
                  ]
        >>
     %%...........................
     %%...more root object keys...
     %%........................... 
  >>
endobj

以上示例将以如下方式标记页面编号1, 2, 3, ... (last):

i
ii
iii
iv
v
vi
1
2
3
4
ABCD-3
ABCD-4
ABCD-5
ABCD-6
...and so on until last page...

正如您所看到的,PDF方法标记页面(将页面编号映射到页面名称)是完全不直观的。只有通过研究PDF规范才能理解它。


感谢您对这种情况的出色总结。我之前已经了解到大部分内容。我意识到,要么是我自己编写一个小型解析器,要么是其他人之前已经编写过(我希望是后者)。我很乐意根据根对象中的信息自行计算它们,但不幸的是,在简单的jscript实现中并不总是容易找到根对象(我想使用它)。QPDF可以轻松让我访问页面对象,但无法要求它直接返回尾随或根对象,因此无法知道在哪里查找目录。 - grovel
1
好的,经过进一步的挖掘,我实际上找到了一个相当简单的解决方案:PDFtk(我之前看过,但这个功能文档记录不清楚)。 - grovel
11
运行命令pdftk.exe document.pdf dump_data output report.txt会生成一个文本文件,其中列出了元数据(如书签)以及页面标签。它看起来会像这样:
PageLabelNewIndex: 1 PageLabelStart: 1 PageLabelPrefix: C PageLabelNumStyle: DecimalArabicNumberals PageLabelNewIndex: 3 PageLabelStart: 1 PageLabelNumStyle: LowercaseRomanNumerals PageLabelNewIndex: 15 PageLabelStart: 1 PageLabelNumStyle: DecimalArabicNumerals
即C1、C2、i、ii、...、xiii、1、2、...
易于解析,正是我需要的。
@Kurt,无论如何还是谢谢你,非常感激!
- grovel
1
@grovel:哦,是的,好久不见的pdftk!现在我记起来了。几年前,我自己甚至也用过pdftk来做这件事情。但当时它并不能可靠地工作于PageLabel信息,也许这就是我忘记它的原因吧。你能重新为我发现这个功能真是太棒了。我也会测试一下的。 - Kurt Pfeifle
1
@ Sasha,你可能想看一下我下面的新答案。像你一样,我发现 pdftk 并不总是能胜任工作。 - mheim
显示剩余2条评论

3
我编写了一个基于Poppler的小型命令行实用程序,可以执行此任务:https://github.com/HeimMatthias/pdfpagelabels 免责声明: 我是原帖作者,但使用不同的帐户创建了原始帖子。多年来,我一直在我的实现中成功地使用通过pdftk(在上面的评论中列出)的解决方案。然而,去年我们重新从头开始实现系统,我们有很多情况下pdf-tk输出无法被我们的实现解析。
新的命令行工具遵循只做一件事情,但做到最好的哲学,并简单地打印所有或选定页面的页面标签pdf文件。如果有人发现它有用,并在这里看到它,那就更好了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接