使用 Ghostscript 分割 PDF
Posted
技术标签:
【中文标题】使用 Ghostscript 分割 PDF【英文标题】:Splitting a PDF with Ghostscript 【发布时间】:2012-04-30 23:57:07 【问题描述】:我尝试使用 Ghostscript 拆分多页 PDF,我在更多网站甚至ghostscript.com 上找到了相同的解决方案,即:
gs -sDEVICE=pdfwrite -dSAFER -o outname.%d.pdf input.pdf
但这似乎对我不起作用,因为它会生成一个文件,其中 所有页面,名称为 outname.1.pdf.
当我添加开始页面和结束页面时,它工作正常,但我 希望它在不知道这些参数的情况下工作。
在 gs-devel 存档中,我找到了一个解决方案:
http://ghostscript.com/pipermail/gs-devel/2009-April/008310.html--
但我想在没有pdf_info
的情况下这样做。
当我使用不同的设备时,例如pswrite
,但相同
参数,它可以正常工作,生成尽可能多的 ps 文件,就像我的
input.pdf 包含。
使用pdfwrite
时这正常吗?我是不是做错了什么?
【问题讨论】:
【参考方案1】:我发现 Weimer 先生编写的这个脚本非常有用:
#!/bin/sh
#
# pdfsplit [input.pdf] [first_page] [last_page] [output.pdf]
#
# Example: pdfsplit big_file.pdf 10 20 pages_ten_to_twenty.pdf
#
# written by: Westley Weimer, Wed Mar 19 17:58:09 EDT 2008
#
# The trick: ghostscript (gs) will do PDF splitting for you, it's just not
# obvious and the required defines are not listed in the manual page.
if [ $# -lt 4 ]
then
echo "Usage: pdfsplit input.pdf first_page last_page output.pdf"
exit 1
fi
gs -dNOPAUSE -dQUIET -dBATCH -sOutputFile="$4" -dFirstPage=$2 -dLastPage=$3 -sDEVICE=pdfwrite "$1"
来源:http://www.cs.virginia.edu/~weimer/pdfsplit/pdfsplit
将其保存为pdfsplit.sh
,看看奇迹发生了。
PDFSAM 也可以完成这项工作。适用于 Windows 和 Mac。
【讨论】:
太棒了。我没有 pdftk 和 psselect 会失去一些 pdf 质量,但不是这个。 感谢您提供指向 -dFirstPage=... 和 -dLastPage=... 参数的指针!【参考方案2】:您看到的是“正常”行为:Ghostscript 的pdfwrite
输出设备的当前版本不支持此功能。 Use.htm 中也记录了这一点(诚然,有些模糊):
“请注意,并非所有设备都支持每个文件一页的功能......”
我似乎记得一位 Ghostscript 开发人员在 IRC 上提到,他们可能在未来的某个版本中将此功能添加到 pdfwrite,但这似乎需要一些主要的代码重写,这就是为什么他们还没做...
更新: 正如 Gordon 的评论已经暗示的那样,截至 version 9.06(2012 年 7 月 31 日发布),Ghostscript 现在支持问题中引用的命令行也适用于 pdfwrite
。 (Gordon 一定是在 9.05 中发现了对此的非官方支持,或者他从尚未标记为 9.06 的预发布源编译了自己的可执行文件。
【讨论】:
是的,我读过这一行,但我的短语“正常行为”想要表示“pdfwrite 是可能不支持此功能的人之一吗?”你记住这个 IRC 对我来说没问题,谢谢。 对于在搜索中找到此答案的人:从 9.05 开始,使用 OP 的命令,每个文件一页对我有效。 @Gordon:支持-o out_%d.pdf
语法(将多页 PDF 拆分为每页的单个文件)在 9.06 中成为正式版本。我已经在其他答案中暗示了这一点(例如 Split multi page PDF file into single pages)。我忘了更新这个答案。感谢您的提示。【参考方案3】:
#!/bin/bash
#where $1 is the input filename
ournum=`gs -q -dNODISPLAY -c "("$1") (r) file runpdfbegin pdfpagecount = quit" 2>/dev/null`
echo "Processing $ournum pages"
counter=1
while [ $counter -le $ournum ] ; do
newname=`echo $1 | sed -e s/\.pdf//g`
reallynewname=$newname-$counter.pdf
counterplus=$((counter+1))
# make the individual pdf page
yes | gs -dBATCH -sOutputFile="$reallynewname" -dFirstPage=$counter -dLastPage=$counter -sDEVICE=pdfwrite "$1" >& /dev/null
counter=$counterplus
done
【讨论】:
【参考方案4】:假设您安装了 Ghostscript,以下是 Windows 命令提示符的脚本(也可用于拖放):
@echo off
chcp 65001
setlocal enabledelayedexpansion
rem Customize or remove this line if you already have Ghostscript folders in your system PATH
set path=C:\Program Files\gs\gs9.22\lib;C:\Program Files\gs\gs9.22\bin;%path%
:start
echo Splitting "%~n1%~x1" into standalone single pages...
cd %~d1%~p1
rem getting number of pages of PDF with GhostScript
for /f "usebackq delims=" %%a in (`gswin64c -q -dNODISPLAY -c "(%~n1%~x1) (r) file runpdfbegin pdfpagecount = quit"`) do set "numpages=%%a"
for /L %%n in (1,1,%numpages%) do (
echo Extracting page %%n of %numpages%...
set "x=00%%n"
set "x=!x:~-3!"
gswin64c.exe -dNumRenderingThreads=2 -dBATCH -dNOPAUSE -dQUIET -dFirstPage=%%n -dLastPage=%%n -sDEVICE=pdfwrite -sOutputFile="%~d1%~p1%~n1-!x!.pdf" "%1"
)
shift
if NOT x%1==x goto start
pause
将此脚本命名为split PDF.bat
之类的名称并将其放在您的桌面上。将一个(甚至更多)多页 PDF 拖放到其上,它将为 PDF 的每一页创建一个独立的 PDF 文件,并在名称后附加后缀 -001
、-002
等以区分页面。
如果您的系统 PATH 环境变量中已有 Ghostscript 文件夹,您可能需要自定义(使用相关的 Ghostscript 版本)或删除 set path=...
行。
它适用于带有 Ghostscript 9.22 的 Windows 10。请参阅 cmets 以使其与 Ghostscript 9.50+ 一起使用。
享受吧。
【讨论】:
+1 用于获取 GS 的页数,干得好!如果有人想在 linux/macOS 上获取页数,请使用gs -q -dNODISPLAY -c "(../escaped\ file \name.pdf) (r) file runpdfbegin pdfpagecount = quit"
非常有帮助。可以与 GS 9.22 一起使用,但在某种程度上与(至少)9.50 和 9.52 不兼容。有人知道如何解决这个问题吗?
@user18258 我不知道如何解决这个问题,但无论如何我发现使用另一个命令行工具在 Windows 上分割 PDF 文件更方便,sedja
控制台。这是一个拖放批次:codepile.net/pile/6lWv3wzY
@mmj 感谢基于sedja
的代码!我将 GhostScript 用于许多“shell:sendto”任务,并且仍然对 9.52 兼容的解决方案感兴趣 - 尽管我知道您不会提供它。我在上面的基于 GS 的代码中发现了一个小错误(我仍在使用 GS 版本 9.27!):我认为 gswin64c.exe ... "%1"
应该是 gswin64c.exe ... %1
,否则当路径包含空格时会出现问题。
@tstone-1 似乎对于 Ghostscript 9.50+,您必须添加 -dNOSAFER
选项(连同 -dNODISPLAY
)。见:***.com/q/40156190【参考方案5】:
这是一个简单的 python 脚本:
#!/usr/bin/python3
import os
number_of_pages = 68
input_pdf = "abstracts_rev09.pdf"
for i in range(1, number_of_pages +1):
os.system("gs -q -dBATCH -dNOPAUSE -sOutputFile=pagepage:04d.pdf"
" -dFirstPage=page -dLastPage=page"
" -sDEVICE=pdfwrite input_pdf"
.format(page=i, input_pdf=input_pdf))
【讨论】:
【参考方案6】:更新的答案仅依赖于 pdftk.exe
,而不调用 Ghostscript
用户@mmj 提供的答案过去对我来说很好用,但不知何故在 GS 版本 9.20 和 9.50 之间的某个地方停止了工作。我也知道@Adobe 提供的解决方案。但是,我喜欢通过选择一个或多个文件并右键单击 → 发送到,从 Windows (10) 资源管理器中完成重复性任务。这是一个 Python 脚本(与 3.8 兼容),它使用 pdftk.exe
(用 2.02 测试)来计算总页数并将全部提取到单个文件中。它应该接受多个 PDF 作为输入。确保 PATH 中有 Python 和 pdftk.exe
。
将此命名为extract-pdf-pages-py.cmd
并将其命名为shell:sendto
:
python %APPDATA%\Microsoft\Windows\SendTo\extract-pdf-pages-py.py %*
把下面的extract-pdf-pages-py.py
放到同一个文件夹里:
#!/usr/bin/python3
# put as extract-pdf-pages-py.py to shell:sendto
import os
import subprocess
import re
import sys
import mimetypes
def is_tool(name):
from shutil import which
return which(name) is not None
if not is_tool('pdftk'):
input('pdftk.exe not within PATH. Aborting...')
raise SystemExit("pdftk.exe not within PATH.")
sys.argv.pop(0)
for j in range(len(sys.argv)):
input_pdf = sys.argv[j]
if 'application/pdf' not in mimetypes.guess_type(input_pdf):
input(f"File input_pdf is not a PDF. Skipping...")
continue
savefile = input_pdf.rstrip('.pdf')
numpages = subprocess.Popen(f"pdftk \"input_pdf\" dump_data", shell=True, stdout=subprocess.PIPE)
output1 = str(numpages.communicate()[0])
output2 = re.search("NumberOfPages: ([0-9]*)", output1)
number_of_pages = int(output2.group(1))
for i in range(1, number_of_pages + 1):
os.system(f"pdftk \"input_pdf\" cat i output \"savefile\"i:04d.pdf")
我使用了来自this answer(@Adobe 编写的脚本)和that one (is_tool
) 的代码。
【讨论】:
【参考方案7】:gs 只接受升序页面。 为了从源代码中改组(即第 7、第 8、第 5)页,我为 ~/.bashrc 创建了函数:
function expdf
local str=""
local arr=($(echo $1 | tr "," "\n"))
# splitting
for i in "$arr[@]";do
gs -dBATCH -sDEVICE=pdfwrite -sPageList=$i -dNOPAUSE -sOutputFile=$i.tmp $2
# reordering for combining
str="$str $i.tmp"
done
# combining to combine.pdf
gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=combine.pdf -dBATCH $str
# removing temporary files
for i in "$arr[@]";do rm $i.tmp;done
使用示例:expdf 7-8,5 source.pdf
【讨论】:
以上是关于使用 Ghostscript 分割 PDF的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Ghostscript 和 Ghostscript .NET 通过嵌入 IIC 配置文件生成正确的 PDF/A
Ghostscript 找不到 Ghostscript 库 (libgs)