如何打印pdf的目录?

如何打印pdf的目录?

我有一个 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
}

以下是如何使用该脚本:

  1. 下载https://gitlab.com/derobert/random-toys/raw/master/pdf/pdftoc-to-latex?inline=false并另存为pdftoc-to-latex.pl
  2. chmod +x /path/to/pdftoc-to-latex.pl通过在终端中运行使其可执行
  3. 安装乳胶::编码perl 包。在 Debian Stretch 上,您可以通过sudo apt install liblatex-encode-perl.在其他发行版上,您可能需要做其他事情。
  4. 像这样运行脚本:/path/to/pdftoc-to-latex.pl /path/to/pdf/file.pdf > /path/to/where/you/want/tex/file.tex
  5. 使用您最喜欢的 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

相关内容