我有一个 pdf 类书籍文件,其中有一个目录作为文件中的元数据,但它们没有列在文档的任何页面上。我想打印带有目录的文件,或者单独打印目录。我怎样才能做到这一点?
答案1
pdftk
可以转储“书签”,例如pdftk file.pdf dump_data_utf8
;您将得到一堆隐藏在其余元数据中的 Bookmark* 条目。grep
可以只给他们:
$ pdftk whatever.pdf dump_data_utf8 | grep ^Bookmark
BookmarkBegin
BookmarkTitle: Cover
BookmarkLevel: 1
BookmarkPageNumber: 1
BookmarkBegin
BookmarkTitle: Agenda
BookmarkLevel: 1
BookmarkPageNumber: 2
“级别”是缩进级别(因此级别 2 是从级别 1 缩进的)。您可以将其格式化为您想要打印的任何格式。
这是一个 Perl 脚本,用于以 LaTeX 格式打印它,然后可以将其输入到例如pdflatex
获取 PDF 文件(您甚至可以使用 pdftk 将其添加到原始 PDF 之前)。请注意,这也可以在https://gitlab.com/derobert/random-toys/blob/master/pdf/pdftoc-to-latex(如果你想改进它,这是发送拉取请求的好地方):
#!/usr/bin/perl
use 5.024;
use strict;
use warnings qw(all);
use IPC::Run3;
use LaTeX::Encode;
use Encode qw(decode);
my @levels
= qw(chapter section subsection subsubsection paragraph subparagraph);
my @counters;
my ($data_enc, $data);
run3 ['pdftk', $ARGV[0], 'dump_data_utf8'], undef, \$data_enc;
$data = decode('UTF-8', $data_enc, Encode::FB_CROAK);
my @latex_bm;
my $bm;
foreach (split(/\n/, $data)) {
/^Bookmark/ or next;
if (/^BookmarkBegin$/) {
add_latex_bm($bm) if $bm;
$bm = {};
} elsif (/^BookmarkLevel: (\d+)$/a) {
++$counters[$1 - 1];
$#counters = $1 - 1;
$bm->{number} = join(q{.}, @counters);
$bm->{level} = $1 - 1;
} elsif (/^BookmarkTitle: (.+)$/) {
$bm->{title} = latex_encode($1);
} elsif (/^BookmarkPageNumber: (\d+)$/a) {
$bm->{page} = $1;
} else {
die "Unknown Bookmark tag in $_\n";
}
}
add_latex_bm($bm) if $bm;
print <<LATEX;
\\documentclass{report}
\\begin{document}
${ \join('', @latex_bm) }
\\end{document}
LATEX
exit 0;
sub add_latex_bm {
my $bm = shift;
my $level = $levels[$bm->{level}];
my $number = $bm->{number};
my $title = $bm->{title};
my $page = $bm->{page};
push @latex_bm, <<LINE;
\\contentsline {$level}{\\numberline {$number}$title}{$page}%
LINE
}
以下是如何使用该脚本:
- 下载https://gitlab.com/derobert/random-toys/raw/master/pdf/pdftoc-to-latex?inline=false并另存为pdftoc-to-latex.pl
chmod +x /path/to/pdftoc-to-latex.pl
通过在终端中运行使其可执行- 安装乳胶::编码perl 包。在 Debian Stretch 上,您可以通过
sudo apt install liblatex-encode-perl
.在其他发行版上,您可能需要做其他事情。 - 像这样运行脚本:
/path/to/pdftoc-to-latex.pl /path/to/pdf/file.pdf > /path/to/where/you/want/tex/file.tex
- 使用您最喜欢的 LaTeX 编译器将生成的 tex 文件编译为 pdf(例如,
cd /path/to/where/you/want/tex; pdflatex file.tex
)
答案2
与上面的方法类似,但 bash 脚本又快又脏。仅取决于pdftk
封装。假设目录pdf/
、、tmp/
和toc/
。
#!/bin/bash
#usage: bash src/pdf-toc-txt.sh pdf/Del-2-200214.pdf "DEL 2"
fn="${1##*/}"
echo "processing: $fn"
rm -Rf tmp/*
#init toc file
echo "$2" > toc/$fn.txt
#pdf metadata
pdftk pdf/$fn dump_data_utf8 > tmp/$fn.txt
#build toc
cd tmp/
csplit -k $fn.txt '/^BookmarkBegin/' {*}
for i in xx*; do
s=$(grep 'BookmarkTitle' "$i");
l=$(grep 'BookmarkLevel' "$i");
p=$(grep 'BookmarkPageNumber' "$i");
sl=${#s};
let "dl = 100 - $sl";
#if output toc in html format
#echo "<h$l>$s" $(printf %"$dl"s | tr " " ".") $p"</h$l>";
#else use text format
echo "$s" $(printf %"$dl"s | tr " " ".") "$p";
done | sed 's/Bookmark\(.\)\{5,10\}: //g' >> ../toc/$fn.txt
#resume
cd ..
鉴于 pdf 包含书签元数据,文本输出如下所示:
DEL 2
...............................................
6 Introduktion (I) [10 sidor] ................ 4
6.1 Forskningsfrågor ......................... 5
6.1.1 Planering av forskningsfrågor ......... 7
6.1.2 Rapportering av forskningsfrågor ....... 7
6.2 Operationalisering ....................... 8
6.2.1 Rapportering av operationalisering ..... 11
6.3 Hypoteser ................................ 12
6.3.1 Rapportering av hypoteser .............. 13
7 Metod (M) [60 sidor] ....................... 15