如何在 PDF 文件中列出指定的目的地?
命名目的地是您所谓的锚点的正式名称。foo
当您点击 的链接时,主要浏览器会跳转到指定的目的地http://example.com/some.pdf#foo
。
我有可以看到锚点工作的文档,但我似乎找不到列出锚点的方法。 Evince、okular 和 xpdf 会在收到指示时跳转到它们,但似乎没有列出它们的界面。pdftk dump_data
列出书签,但这不是同一件事(这是内容条目表,它很可能与指定目的地位于同一位置,但不能用作锚点)。
我正在寻找一个命令行解决方案(例如,适用于在诸如 之类的完成函数之后使用evince -n
)。由于这很有意义,我想按照目的地在文档中出现的顺序列出目的地。奖励:显示目标页码和其他有助于确定目标位置的信息。
也可以看看查看有关软件推荐的 PDF 文档中的锚点对于 GUI 查看器。
答案1
波普勒的 pdf信息命令行实用程序将为您提供 PDF 中所有指定目标的页码、位置和名称。您至少需要 0.58 版本的 Poppler。
$ pdfinfo -dests input.pdf
Page Destination Name
1 [ XYZ null null null ] "F1"
1 [ XYZ 122 458 null ] "G1.1500945"
1 [ XYZ 79 107 null ] "G1.1500953"
1 [ XYZ 79 81 null ] "G1.1500954"
1 [ XYZ null null null ] "P.1"
2 [ XYZ null null null ] "L1"
2 [ XYZ null null null ] "P.2"
(...)
答案2
这pyPDF库可以列出锚点:
#!/usr/bin/env python
import sys
from pyPdf import PdfFileReader
def pdf_list_anchors(fh):
reader = PdfFileReader(fh)
destinations = reader.getNamedDestinations()
for name in destinations:
print name
pdf_list_anchors(open(sys.argv[1]))
对于完成用例来说这已经足够好了,但是锚点是以随机顺序列出的。只有 pyPdf 1.13 的稳定接口,我找不到按顺序列出锚点的方法。我还没有尝试过 pyPdf2 。
答案3
(也在这里回答:查看 PDF 文档中的锚点)
我有同样的问题,最终通过以下方式找到了一个很好的答案如何直观地检查 PDF 的结构以对其进行逆向工程?
答案是使用Python包pdfminer.six
。是均匀的文档中的示例之一!将此代码剪切并粘贴到终端中:
pip install pdfminer.six
cat >extract.py <<EOF
import sys
import pdfminer.pdfparser, pdfminer.pdfdocument
with open(sys.argv[1], "rb") as f:
parser = pdfminer.pdfparser.PDFParser(f)
document = pdfminer.pdfdocument.PDFDocument(parser)
for (level, title, dest, a, se) in document.get_outlines():
print(' ' * level, title, dest or a, se)
EOF
python extract.py myInputFile.pdf
在我的特定 PDF 上,输出如下所示:
$ python extract.py ~/Desktop/p2786r3.pdf | head
Abstract {'S': /'GoTo', 'D': b'section.1'} None
Revision History {'S': /'GoTo', 'D': b'section.2'} None
R3: October 2023 (midterm mailing)r3-october-2023-midterm-mailing {'S': /'GoTo', 'D': b'section*.2'} None
R2: June 2023 (Varna meeting)r2-june-2023-varna-meeting {'S': /'GoTo', 'D': b'section*.3'} None
R1: May 2023 (pre-Varna mailing)r1-may-2023-pre-varna-mailing {'S': /'GoTo', 'D': b'section*.4'} None
R0: Issaquah 2023r0-issaquah-2023 {'S': /'GoTo', 'D': b'section*.5'} None
Introduction {'S': /'GoTo', 'D': b'section.3'} None
Motivating Use Cases {'S': /'GoTo', 'D': b'section.4'} None
Efficient vector growth {'S': /'GoTo', 'D': b'subsection.4.1'} None
Moving types without empty states {'S': /'GoTo', 'D': b'subsection.4.2'} None
事实上,p2786r3.pdf#subsection.4.2
在我的浏览器中导航到该特定部分会打开 PDF。
答案4
pypdf 库中有一些更改。在这里您可以找到该版本原剧本和修改后的脚本使用 python3 和 pypdf:
#!/usr/bin/env python3
import sys
from pypdf import PdfReader
def pdf_get_anchors(fh):
reader = PdfReader(fh)
destinations = reader.named_destinations #completely unsorted order, does not include pagenums
L=list();
np = len(reader.pages)
for PageNum in range(1,np+1) :
ThisPage = reader.pages[PageNum-1]
PageTop = ThisPage['/MediaBox'][3]
for name in destinations:
ThisDest = destinations[name]
ThisDestPage = ThisDest.page.get_object()
if ThisDestPage == ThisPage: #have to do this to identify the pagenum
DownPage = (PageTop - ThisDest.top) / PageTop # calc fraction of page down
Position = PageNum + DownPage # a sortable number down the whole pdf
L.append((name, PageNum, Position)); # put everything in a sortable list
return L, len (destinations), np
def pdf_print_anchors ( L ) :
for dest in L :
name=dest[0]
PageNum=dest[1]
Position= round(dest[2]*100)/100
print ("%8.2f % %s" % Position % name) #ThisDest.title
HeaderLine="\n Page Name"
pdf_get_anchors(open(sys.argv[1],'rb'))
L, NumDests, NumPages =pdf_get_anchors(open(sys.argv[1],'rb'))
print (HeaderLine)
L.sort(key=lambda dest: dest[0]) #sort name order
pdf_print_anchors(L);
print (HeaderLine)
L.sort(key=lambda dest: dest[2]) #sort in order down the pdf
pdf_print_anchors(L);
print ("Number of NamedDestinations: ", NumDests, "NumPages: ", NumPages)