将PDF与PDFTK合并为书签?

时间:2010-06-03 20:21:36

标签: linux pdf pdf-generation pdftk ghostscriptsharp

使用pdftk合并多个pdf正在运行良好。但是,为每个pdf合并制作书签的简单方法是什么?

我没有在pdftk文档上看到任何关于此的内容,所以我认为pdftk不可能。

我们合并的所有文件都是1页,所以想知道是否还有其他可以在之后添加书签的实用程序?

或者另一个基于linux的pdf实用程序,允许在为每个单独的pdf指定书签时进行合并。

12 个答案:

答案 0 :(得分:40)

您还可以将多个PDF与Ghostscript合并。这条路线的一大优势是解决方案易于编写脚本,并且不需要真正的编程工作:

gswin32c.exe ^
          -dBATCH -dNOPAUSE ^
          -sDEVICE=pdfwrite ^
          -sOutputFile=merged.pdf ^
          [...more Ghostscript options as needed...] ^
          input1.pdf input2.pdf input3.pdf [....]

使用Ghostscript,您将能够传递 pdfmark 语句,这些语句可以为生成的PDF中的每个其他源文件添加内容列表和书签。例如:

gswin32c.exe ^
          -dBATCH -dNOPAUSE ^
          -sDEVICE=pdfwrite ^
          -sOutputFile=merged.pdf ^
          [...more Ghostscript options as needed...] ^
          file-with-pdfmarks-to-generate-a-ToC.ps ^
          -f input1.pdf input2.pdf input3.pdf [....]

gswin32c.exe ^
          -dBATCH -dNOPAUSE ^
          -sDEVICE=pdfwrite ^
          -sOutputFile=merged.pdf ^
          [...more Ghostscript options as needed...] ^
          file-with-pdfmarks-to-generate-a-ToC.ps ^
          -f input1.pdf ^
             input2.pdf ^ 
             input3.pdf [....]

有关pdfmark主题的一些介绍,另请参阅Thomas Merz的PDFmark Primer


<强> 编辑:
我想给你一个file-with-pdfmarks-to-generate-a-ToC.ps的例子,但不知何故忘了。这是:

[/Page 1 /View [/XYZ null null null] /Title (File 1) /OUT pdfmark
[/Page 2 /View [/XYZ null null null] /Title (File 2) /OUT pdfmark
[/Page 3 /View [/XYZ null null null] /Title (File 3) /OUT pdfmark
[/Page 4 /View [/XYZ null null null] /Title (File 4) /OUT pdfmark 

这将为前4个文件==前4页创建一个ToC(因为您保证您的合成文件每个合并输出PDF为1页)。

  1. [/XYZ null null null]部分确保您的页面视口和缩放级别在您按照链接时不会从当前视口和缩放级别更改。 (如果你想要一个任意的例子,你可以说[/XYZ 222 111 2]来做这件事。)
  2. /Title (some string you want) thingie确定ToC中的文本。
  3. 而且,您甚至可以直接将这些参数添加到Ghostscript命令行中:

    gswin32c.exe ^
           -o merged.pdf ^
           [...more Ghostscript options as needed...] ^
           -c "[/Page 1 /View [/XYZ null null null] /Title (File 1) /OUT pdfmark" ^
           -c "[/Page 2 /View [/XYZ null null null] /Title (File 2) /OUT pdfmark" ^
           -c "[/Page 3 /View [/XYZ null null null] /Title (File 3) /OUT pdfmark" ^
           -c "[/Page 4 /View [/XYZ null null null] /Title (File 4) /OUT pdfmark" ^
           -f input1.pdf ^
              input2.pdf ^ 
              input3.pdf ^ 
              input4.pdf [....]
    



    'nother编辑:

    哦,顺便说一下:Ghostscript 确实 保存书签,当你用它将两个PDF文件合并为一个时 - pdftk.exe没有。让我们使用第一次编辑命令生成的那个(有效地连接同一个文件的2个副本):

     gswin32c ^
        -sDEVICE=pdfwrite ^
        -o doublemerged.pdf ^
         merged.pdf ^
         merged.pdf
    

    文件doublemerged.pdf现在将有2 * 4 = 8个书签。

    • 符合预期:书签1,2,3和4链接到第1,2,3和4页。
    • 问题是,书签5,6,7和8也链接在第1,2,3和4页。

    原因是,预先存在的书签确实通过绝对页码来解决其链接目标。要解决这个问题(并且书签在合并文件中工作),必须生成书签,这些书签确实指向了命名目标的链接目标(并确保它们在合并的文档中是唯一的。)

    (这种方法也适用于linux,只需使用gs代替gswin32c。)


    附录

    以上命令行使用 [...more Ghostscript options as needed...] 作为占位符以获取更多选项。

    如果您不使用其他选项,Ghostscript将为各种参数应用其内置默认值。但是,这可能会给您带来您不喜欢的结果。由于Ghostscript根据输入生成一个全新的PDF,这意味着可能会更改某些原始对象。这适用于色彩空间和图像压缩级别。

    如何应用使原始嵌入图像保持不变的参数可以在SuperUser: "Use Ghostscript, but tell it to not reprocess images"处看到。

答案 1 :(得分:10)

我知道还有其他方法可以做到这一点,但是使用pdftk,您可以使用pdftk函数dump_data来合并pdf并为其添加书签,以创建pdf中现有信息的.info文件。然后,您可以通过为每个书签添加以下四行

,将书签信息添加到.info文件中
BookmarkBegin
BookmarkTitle: name
BookmarkLevel: level
BookmarkPageNumber: page number

然后使用update_info调用将合并的pdf书签更新为您写入.info文件的书签。我已经写了一些简单的函数,如果有兴趣的话,可以在autohotkey中为我做这个。见http://www.autohotkey.com/board/topic/98985-scripts-to-merge-pdfs-and-add-bookmarks-with-pdftk/

答案 2 :(得分:5)

请在https://stackoverflow.com/a/17781138/547578查看此答案。我使用了一种名为Sejda的东西。有用。它完美地结合了书签。谢谢@blablatros。

答案 3 :(得分:4)

添加或编辑可以使用的JPdfBookmarks pdf书签。它是一个出色的多操作系统自由软件工具,我已经使用了一段时间,效果很好。它仅处理书签,因此您需要另一个工具来合并或重新排序页面。除了pdftk,我建议尝试 PDF拆分和合并(好的应用程序,但奇怪的用户界面,从我的经验中弄乱书签), PDF-Shuffler (似乎工作正常,但有时会在处理某些文件时冻结)或PdfMod(最好的可能是处理重新排列,合并和处理书签,尽管我还没弄清楚如何将pdfs添加到特定页面)

很抱歉没有提供一些链接,作为新手,系统只允许我添加2个超链接。

答案 4 :(得分:2)

@pipitas的好答案并没有解决完美的书签问题,并且在unix讨论https://unix.stackexchange.com/questions/17065/add-and-edit-bookmarks-to-pdf/31070中存在相关问题,我建议

如果你仍然坚持使用那些unix脚本,那么

  1. 提取从pdftk
  2. 转储的书签数据
  3. 编写一个额外的脚本,将转储的书签数据转换为pdfmarks格式,接受ghostscript命令gs
  4. 使用gs脚本将它们与pdfmarks合并在一起
  5. 该脚本已经存在,请参阅Merge PDF's with PDFTK with Bookmarks?

    中的pdf-merge.py

答案 5 :(得分:2)

以下可能有用。我想将位于一个目录中的所有pdfs(in_nn.pdf)合并为一个out.pdf,其输入pdfs(in_nn)的名称为ToC。 我写了一个python脚本,它读取名称并提取页码并生成一个名为pdfmarks的文件。然后使用gs轻松完成合并文件。确切的命令由脚本输出,必须单独执行(可能由于页面大小调整或操作系统的原因而进行一些修改)。

在这里。也许窗户需要一些修改? (抱歉评论不是英文)。只需在要合并的pdf所在的目录中执行python脚本。

#!/usr/bin/env python

import subprocess

# Dieses Skript dient dazu, eine Reihe von pdfs zu einem einzigen pdf zusammenzufassen und bookmarks fuer diese pdf-Datei zu erzeugen.
# Dafuer wird ein Datei pdfmark benoetigt, die mit diesem Skript erzeugt wird.
# Dazu einfach dieses Skript in dem Verzeichnis aufrufen, das genau alle zusammenzufassenden pdfs (*pdf, s.u.) enthaelt.
# Das zusammenfassende pdf wird dann mit diesem Befehl (in der bash) generiert:
# gs -dBATCH -dNOPAUSE -sPAPERSIZE=A4 -sDEVICE=pdfwrite -sOutputFile="all.pdf" $(ls *pdf ) pdfmarks
# Bereits Inhaltsverzeichnisse bleiben erhalten, die neuen kommen ans Ende des Inhaltsverzeichnisses.
#
# pdfmarks sieht dabei prinzipiell so aus:
#
# [/Title (Nr. 1) /Page 1 /OUT pdfmark
# [/Title (Nr. 2) /Page 5 /OUT pdfmark
# [/Title (Nr. 3) /Page 9 /OUT pdfmark
# usw.

p = subprocess.Popen('ls *pdf', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

pdfdateien = []
kombinationen = []

for line in p.stdout.readlines():
# p enthaelt alle pdf-Dateinamen
  pdfdateien.append(line)


for datei in pdfdateien:
  cmd = "pdfinfo %s" %datei 
  q=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  kombination = [datei]

for line in p.stdout.readlines():
# p enthaelt alle pdf-Dateinamen
  pdfdateien.append(line)


for datei in pdfdateien:
  cmd = "pdfinfo %s" %datei 
  q=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  kombination = [datei]


  for subline in q.stdout.readlines():
# q enthaelt die Zeilen von pdfinfo
    if "Pages" in subline:
      kombination.append(subline)

  kombinationen.append(kombination)


# Jetzt kombinationen in benoetigtes Format bringen:

kombinationen_bereinigt =  []
out_string1 = "[/Title ("
out_string2 = ") /Page "
out_string3 = " /OUT pdfmark\n"
seitenzahl = 1

for kombination in kombinationen:
  dateiname = kombination[0][0:len(kombination[0])-5]

#
# Hier noch dateiname evtl. verwursten
# z. B.
#  lesezeichen = dateiname[0:1]+" "+dateiname[6:8]+"/"+dateiname[1:5]
  lesezeichen = dateiname

  anz_seiten = kombination[1][16:len(kombination[1])-1]
  seitenzahl_str = str(seitenzahl)

  kombination_bereinigt = out_string1+lesezeichen+out_string2+seitenzahl_str+out_string3
  kombinationen_bereinigt.append(kombination_bereinigt)

  seitenzahl += int(anz_seiten)


# Ausgabe ins file
outfile = open("pdfmarks", "w")

for i in kombinationen_bereinigt:
  outfile.write(i)

outfile.close()

# Merge-Befehl absetzen

print "\nFor merging all pdfs execute this (or similar) command (in bash shell):"
print "gs -dBATCH -dNOPAUSE -sPAPERSIZE=A4 -sDEVICE=pdfwrite -sOutputFile=\"all.pdf\" $(ls *pdf ) pdfmarks\n"

答案 6 :(得分:1)

不幸的是,没有简单的方法可以做到这一点。您可以使用直接构建pdftk的库,并编写使用iText或iTextSharp的Java或.NET程序来合并您的单页面并创建书签。如果你想去iText路线,可以在网上或iText书中找到很多例子(由iText作者撰写)。

......或者,让我知道什么不起作用,我可以提供帮助。

答案 7 :(得分:0)

以下内容旨在通过pdfmerger(https://stackoverflow.com/a/30524828/3915004)对答案进行评论。

感谢您的脚本pdfmerger! 我知道这个问题标记为linux,但为了概括你的Mac OS X脚本,需要做两件事:

  • ghostscript gs
  • 命令pdfinfo(包含在poppler

首先获取brew(google it,通过curl / ruby​​-magic命令^^安装),然后简单地安装它们:

brew install ghostscript
brew install poppler

ADD-ON:阅读带有章节标题的文本文件:

扩展您的脚本。 我将此工作流程主要用于编辑网站下载章节下载的书籍。 可以轻松生成包含章节名称的文本文件。 以下对代码的附加组件另外读取了一个文本文件'chapters.txt',每个pdf包含一行以进行合并。 (注意,我没有对与pdfs数相对应的行数进行任何检查。)

只需通过替换以下行来扩展您的脚本:

p = subprocess.Popen('ls *pdf', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
c = subprocess.Popen('less chapters.txt', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

pdfdateien = []
kombinationen = []
chapternames = []

for line in c.stdout.readlines():
# c contains all chapter-titles
  chapternames.append(line)

for line in p.stdout.readlines():

for index, kombination in enumerate(kombinationen):
#  dateiname = kombination[0][0:len(kombination[0])-5]
#
# Hier noch dateiname evtl. verwursten
# z. B.
#  lesezeichen = dateiname[0:1]+" "+dateiname[6:8]+"/"+dateiname[1:5]
#  lesezeichen = dateiname
  lesezeichen=chapternames[index][:-1]

  anz_seiten = kombination[1][16:len(kombination[1])-1]

答案 8 :(得分:0)

PdfMod。它有一个图形界面,可以手动添加书签。此外,如果您编辑已附带书签的PDF,它会自动更新它们以指向正确的页面。

答案 9 :(得分:0)

Sejda PDF (已在one of the answers中建议)也可作为在线服务提供:https://www.sejda.com/merge-pdf

如果您不想安装任何其他软件并希望通过浏览器在线工作,这可能会派上用场。

合并步骤:

  1. 将所有PDF文件拖放到网页
  2. 默认保留所有现有书签,并且也可以在合并文档中使用。

  3. 或者,合并工具可以根据要合并的PDF文档构建目录

  4. Option selected to generated Table of contents for merged PDF documents based on filenames

    Merged PDF table of contents

    合并PDF文件的在线服务每小时最多可使用30个文件,文件最多可达50Mb / 200页。

    免责声明:我是一名在Sejda工作的开源开发人员。

答案 10 :(得分:0)

pdftk的最新版本(至少为v2.02)可以正确处理书签和链接:

pdftk file1.pdf file2.pdf cat output merged.pdf

答案 11 :(得分:0)

pystitcher

(使用 pip install pystitcher 安装)

pystitcher 可让您将 PDF 合并在一起,还可以通过在 Markdown 文件中定义最终 PDF 结构轻松编辑书签。

因此,如果您的文件名为 1-5.pdf,则您将创建一个 Markdown 文件 (input.md):

# Part 1
[Chapter 1](1.pdf)
[Chapter 2](2.pdf)
[Chapter 3](3.pdf)
# Part 2
[Chapter 4](4.pdf)
[Chapter 5](5.pdf)

并运行 pystitcher input.md output.pdf,它将生成一个新的 PDF,其中添加了所有正确的书签。您还可以通过 existing_bookmarks 配置选项决定对现有书签进行的操作。