根据部分拆分 pdf 文档

根据部分拆分 pdf 文档

这可能是一个XY问题,更多关于上下文的信息在最后

有没有什么方法可以根据章节标题以编程方式拆分 pdf?那是

从此 pdf 中生成 2 个 pdf,其中一个包含直到“XY”部分的所有内容,第二个包含其余所有内容。

知道如何根据页码分割 PDF,但是还有更多“语义”可用的吗?

(简而言之,最初的问题是:NSF 希望在一个文档中包含参考文献列表,在另一个文档中包含描述,并且由于我使用 LaTeX / pandoc 来生成我的文档,因此将所有内容都包含在 1 个文档中然后再使用会更简单显然,链接并不重要。)

答案1

我喜欢用于pdftk此类工作。

如果我使用 Latex 创建一个基本文档,它可能如下所示:

\documentclass{report}
\usepackage{blindtext} % For lorem ipsum text
\usepackage{hyperref} % Turns chapters/sections into bookmarks

\begin{document}

\chapter{First Chapter}
\Blindtext[10]

\section{Subsection of chapter 1}
\Blindtext[3]

\chapter{Second Chapter}
\Blindtext[20]

\chapter{Third Chapter}
\Blindtext

\pdfbookmark{Example bookmark}{A}
\Blindtext

\end{document}

当我运行它时pdflatex,它会生成一个 13 页的 PDF,其中每个章节都有自动书签、第 1.1 节的深度书签、稍后的手动书签以及许多 lorem ipsum 段落。

现在我们有了一个 pdf 文件,我们可以用它pdftk来获得一些关于它的见解。数据很多,所以我将其缩减为有趣的部分。

$ pdftk sample.pdf dump_data
InfoBegin
...
NumberOfPages: 13
BookmarkBegin
BookmarkTitle: First Chapter
BookmarkLevel: 1
BookmarkPageNumber: 1
BookmarkBegin
BookmarkTitle: Subsection of chapter 1
BookmarkLevel: 2
BookmarkPageNumber: 3
BookmarkBegin
BookmarkTitle: Second Chapter
BookmarkLevel: 1
BookmarkPageNumber: 5
BookmarkBegin
BookmarkTitle: Third Chapter
BookmarkLevel: 1
BookmarkPageNumber: 11
BookmarkBegin
BookmarkTitle: Example bookmark
BookmarkLevel: 1
BookmarkPageNumber: 12
PageMediaBegin
...

当我们点击BookmarkBegin标签时,我们就知道我们有一个书签。当我们看到时,BookmarkTitle: X我们知道我们已经到达了部分XBookmarkPageNumber:每个书签都有一个关联的书签。您可以将其用于您的拆分。您还可以使用BookmarkLevel来过滤您想要拆分的级别(章节、部分、小节)。


假设您想在第 1 章和第 2 章之间进行拆分。从数据中我们可以看到,我们需要在第 4 页之前添加拆分:

BookmarkTitle: Second Chapter
BookmarkPageNumber: 5

现在我们有了页码,我们可以用来pdftk进行分割。这实际上涉及到cat在特定页面上使用:

pdftk sample.pdf cat 1-4 output sample-1.pdf
pdftk sample.pdf cat 5-end output sample-2.pdf

让我们采用更通用的方法,并将其编写为名为 .pdf 的 pdf 脚本sample.pdf。让我们在每个高级书签处拆分 PDF(过滤掉该部分)。

首先,让我们将书签标签转换为更易于解析的格式,我们可以在其中写入一些内容awk(我将其另存为parser.awk

#!/bin/awk -f
BEGIN {
    FS=": "
    OFS=";"
}
/^BookmarkBegin/ {
  if (this_level > 1) { # Only handle high-level sections
    next
  }
  if (this_page == "" || this_title == ""){
    next
  }
  if (last_page != "" && last_title != "") {
    print last_title, last_page, this_page-1
  }
  last_title=this_title
  last_page=this_page
  this_title=this_page=this_level=""
}
/^BookmarkTitle:/ {
    this_title=$2
}
/^BookmarkPageNumber:/ {
    this_page=$2
}
/^BookmarkLevel:/ {
    this_level=$2
}
END {
  print last_title, last_page, this_page-1
  print this_title, this_page, "end"
}

在这里,我假设标题不包含 a ;,因此我使用它作为输出分隔符。该脚本输出:

  1. 每个部分的名称
  2. 该部分的首页
  3. 本节的最后一页。
$ pdftk sample.pdf dump_data | awk -f parser.awk
First Chapter;1;4
Second Chapter;5;10
Third Chapter;11;11
Example bookmark;12;end

现在让我们迭代每一行并pdftk在 bash 中调用它:

#!/bin/bash                                                                     
                                                                                
sequence=1                                                                      
                                                                                
pdftk sample.pdf dump_data | awk -f parser.awk | \                              
while IFS=";" \                                                                 
read -r title start end                                                         
do                                                                              
  pdftk sample.pdf cat "$start"-"$end" output sample-$sequence-"$title".pdf      
  sequence=$((sequence+1))                                                      
done                                                                                     

这给你留下了以下内容:

$ ls *.pdf
'sample-1-First Chapter.pdf'
'sample-2-Second Chapter.pdf'
'sample-3-Third Chapter.pdf'
'sample-4-Example bookmark.pdf'
sample.pdf

这样做的一个限制是,当同一页面上有多个书签或书签很少时,它会有点混乱。

答案2

去年我使用了 python 库py_pdf_parser并实现了类似的目标。pdfplumber最重要的是,我使用 MathPix API(付费但费用最低)来完成到乳胶的最终转换。

您可以在此处查看我的脚本,看看它是否有帮助:https://github.com/sekerez/linear_algebra_done_right/blob/main/problems/extract_problems_from_pdf_book.py该脚本提取了书中的所有问题,并根据练习编号和问题编号将它们整齐地组织在数据结构中。令人惊奇的是,仅使用几行代码就可以做到这一点。

您必须根据您的用例调整脚本。由于每个 PDF 都非常不同,因此机器处理 PDF 非常困难。因此,您需要根据 PDF 格式手工制作自己的脚本。

答案3

斯图尔特的回答给了我几乎所有的工具,但我对他们的解决方案做了两个重要的编辑:

  1. 使用相干pdf保留目录(pdftk只需将其删除),
  2. 使命令将文件分成两部分,而不是将文件分成与章节一样多的文件。

重新使用parser.awkStewarts 共享的内容,假设调用了源代码source.pdf,并且我们要用来分割文档的章节称为“附录”,这给出了:

pdftk source.pdf dump_data | \
awk -f parser.awk  | \
grep Appendix | \
{ 
    IFS=";" ; \
    read -r title start end; \
    ./cpdf source.pdf  1-"`expr $start - 1`" -o A.pdf; \
    ./cpdf source.pdf "$start"-"$end" -o B.pdf;
}

  1. 转储文件的元数据,
  2. 提取相关位 ( title ; page start ; page ends),
  3. 抓住附录的相关部分,
  4. 将分隔符设置read;
  5. 将标题存储在title变量中,将起始页存储在 中start,将结束页存储在 中end
  6. start - 1将从 1 到(对应于附录开始之前的页面)的所有页面输出到名为 的文件中A.pdf
  7. 将文档的其余部分输出到名为B.pdf.

相关内容