我将处理单个PDF,每个PDF都是通过“合并”多个PDF来创建的。每个合并的PDF都有PDF部件开始显示的位置和书签。
有没有办法通过书签用脚本自动拆分?
我们只有书签来指示部分,而不是页码,因此我们需要从书签中推断出页码。 Linux工具最好。
答案 0 :(得分:13)
pdftk可用于分割PDF文件并提取书签的页码。
获取书签的页码
pdftk in.pdf dump_data
并使您的脚本从输出中读取页码。
然后使用
pdftk in.pdf cat A-B output out_A-B.pdf
将A到B的页面转换为out_A-B.pdf。
脚本可能是这样的:
#!/bin/bash
infile=$1 # input pdf
outputprefix=$2
[ -e "$infile" -a -n "$outputprefix" ] || exit 1 # Invalid args
pagenumbers=( $(pdftk "$infile" dump_data | \
grep '^BookmarkPageNumber: ' | cut -f2 -d' ' | uniq)
end )
for ((i=0; i < ${#pagenumbers[@]} - 1; ++i)); do
a=${pagenumbers[i]} # start page number
b=${pagenumbers[i+1]} # end page number
[ "$b" = "end" ] || b=$[b-1]
pdftk "$infile" cat $a-$b output "${outputprefix}"_$a-$b.pdf
done
答案 1 :(得分:4)
有一个用Java编写的命令行工具Sejda,您可以在其中找到完全按照您的要求执行的splitbybookmarks
命令。它是Java,所以它在Linux上运行,并且是一个命令行工具,你可以编写脚本来做到这一点。
声明
我是其中一位作者
答案 2 :(得分:3)
你有像pdf-split这样的程序可以为你做到这一点:
A-PDF Split是一个非常简单,闪电般快速的桌面实用程序,可让您将任何Acrobat pdf文件拆分为较小的pdf文件。它提供了完整的灵活性和用户控制,包括文件的拆分方式以及拆分输出文件的唯一命名方式。 A-PDF Split提供了大量文件分割方式的多种选择 - 按页面,书签和奇数/偶数页面。即使您可以提取或删除部分PDF文件。 A-PDF Split还提供高级定义的分割,可以保存并稍后导入以用于重复的文件分割任务。 A-PDF Split代表了文件分割的最佳灵活性,可满足各种需求。
A-PDF Split适用于受密码保护的pdf文件,可以将各种pdf安全功能应用于拆分输出文件。如果需要,您可以使用A-PDF Merger等实用程序将生成的拆分文件与其他pdf文件重新组合,以形成新的复合pdf文件。
A-PDF Split不需要Adobe Acrobat,并生成与Adobe Acrobat Reader第5版及更高版本兼容的文档。
编辑*
如果您不想付费,还找到了免费的开源程序Here。
答案 3 :(得分:0)
这是我用于该任务的一个Perl小程序。 Perl并不特殊。它只是pdftk的包装器,用于解释其dump_data
输出,以将其转换为要提取的页码:
#!perl
use v5.24;
use warnings;
use Data::Dumper;
use File::Path qw(make_path);
use File::Spec::Functions qw(catfile);
my $pdftk = '/usr/local/bin/pdftk';
my $file = $ARGV[0];
my $split_dir = $ENV{PDF_SPLIT_DIR} // 'pdf_splits';
die "Can't find $ARGV[0]\n" unless -e $file;
# Read the data that pdftk spits out.
open my $pdftk_fh, '-|', $pdftk, $file, 'dump_data';
my @chapters;
while( <$pdftk_fh> ) {
state $chapter = 0;
next unless /\ABookmark/;
if( /\ABookmarkBegin/ ) {
my( $title ) = <$pdftk_fh> =~ /\ABookmarkTitle:\s+(.+)/;
my( $level ) = <$pdftk_fh> =~ /\ABookmarkLevel:\s+(.+)/;
my( $page_number ) = <$pdftk_fh> =~ /\BookmarkPageNumber:\s+(.+)/;
# I only want to split on chapters, so I skip higher
# level numbers (higher means more nesting, 1 is lowest).
next unless $level == 1;
# If you have front matter (preface, etc) then this numbering
# will be off. Chapter 1 might be called Chapter 3.
push @chapters, {
title => $title,
start_page => $page_number,
chapter => $chapter++,
};
}
}
# The end page for one chapter is one before the start page for
# the next chapter. There might be some blank pages at the end
# of the split for PDFs where the next chapter needs to start on
# an odd page.
foreach my $i ( 0 .. $#chapters - 1 ) {
my $last_page = $chapters[$i+1]->{start_page} - 1;
$chapters[$i]->{last_page} = $last_page;
}
$chapters[$#chapters]->{last_page} = 'end';
make_path $split_dir;
foreach my $chapter ( @chapters ) {
my( $start, $end ) = $chapter->@{qw(start_page last_page)};
# slugify the title so use it as a filename
my $title = lc( $chapter->{title} =~ s/[^a-z]+/-/gri );
my $path = catfile( $split_dir, "$title.pdf" );
say "Outputting $path";
# Use pdftk to extract that part of the PDF
system $pdftk, $file, 'cat', "$start-$end", 'output', $path;
}