【问题标题】:Split a PDF by Bookmarks?按书签拆分 PDF?
【发布时间】:2011-02-05 19:23:32
【问题描述】:

我将处理通过“合并”多个 PDF 创建的单个 PDF。每个合并的 PDF 都有 PDF 部分开始显示的位置,并带有书签。

有没有什么方法可以通过书签和脚本自动拆分?

我们只有用于指示部件的书签,而不是页码,因此我们需要从书签中推断出页码。最好有一个 Linux 工具。

【问题讨论】:

    标签: linux pdf pdf-generation tagged-pdf


    【解决方案1】:

    您有像 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 不需要 Adob​​e Acrobat,并且生成的文档与 Adob​​e Acrobat Reader 版本 5 及更高版本兼容。

    编辑*

    如果您不想付费,还可以找到一个免费的开源程序Here。

    【讨论】:

    【解决方案2】:

    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
    

    【讨论】:

    • 很好 :) 我使用grep -A1 '^BookmarkLevel: 1' | grep '^BookmarkPageNumber: ' 仅获取顶级书签。不幸的是,所有较低级别的书签都会以这种方式丢失......
    • 我只想提一下,这个 bash 脚本在带有 pdftk 的 macOS Sierra 上仍然可以正常工作。做得很好!
    【解决方案3】:

    有一个用 Java 编写的名为 Sejda 的命令行工具,您可以在其中找到完全符合您要求的 splitbybookmarks 命令。它是 Java,所以它在 Linux 上运行,并且是一个命令行工具,您可以编写脚本来执行此操作。

    免责声明
    我是作者之一

    【讨论】:

    • 他们有 200 页的限制。
    • 不,没有任何限制。如果您遇到问题,请打开一个问题。
    • sejda-console 需要 Pro,即 2000 美元/年。当然不是我用例的选择。
    【解决方案4】:

    这是我用于该任务的一个小 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;
        }
    

    【讨论】:

      猜你喜欢
      • 2022-12-06
      • 1970-01-01
      • 1970-01-01
      • 2017-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多