我正在使用UNIX系统,希望将成千上万个PDF文件合并成一个文件以便打印。事先我不知道它们有多少页。
我想要双面打印,使得两个文件不在同一页上。
因此,我需要将合并的文件对齐,确保每个文件都从奇数页开始,并在下一页为偶数页时添加空白页。
我正在使用UNIX系统,希望将成千上万个PDF文件合并成一个文件以便打印。事先我不知道它们有多少页。
我想要双面打印,使得两个文件不在同一页上。
因此,我需要将合并的文件对齐,确保每个文件都从奇数页开始,并在下一页为偶数页时添加空白页。
这是我使用的解决方案(基于@Dingo的基本原理,但对于PDF操作使用了更简单的方法):
创建一个只有一个空白页面的PDF文件
首先,在某个地方创建一个只有一个空白页面的PDF文件(在我的情况下,它位于 /path/to/blank.pdf
)。可以使用以下命令(来自此主题):
touch blank.ps && ps2pdf blank.ps blank.pdf
运行Bash脚本
接着,在包含所有PDF文件的目录中,我运行一个小脚本,将blank.pdf
文件添加到每个奇数页码的PDF文件末尾:
#!/bin/bash
for f in *.pdf; do
let npages=$(pdfinfo "$f"|grep 'Pages:'|awk '{print $2}')
let modulo="($npages %2)"
if [ $modulo -eq 1 ]; then
pdftk "$f" "/path/to/blank.pdf" output "aligned_$f"
# or
# pdfunite "$f" "/path/to/blank.pdf" "aligned_$f"
else
cp "$f" "aligned_$f"
fi
done
合并结果
现在,所有以 aligned_
前缀的文件都有偶数页码,我可以使用以下命令将它们合并:
pdftk aligned_*.pdf output result.pdf
# or
pdfunite aligned_*.pdf result.pdf
工具信息:
ps2pdf
在大多数Linux发行版中的ghostscript
包中pdfinfo
,pdfunite
来自Poppler PDF渲染库(通常软件包名称为poppler-utils
或poppler_utils
)pdftk
通常是它自己的包,即pdftk
软件包如果您从另一个角度看待这个问题,它可能会更容易解决。
为了实现这一点,在打印时,将第二个pdf文件的第一页不附加到第一个pdf文件的最后一页上,更普遍地讲,后续pdf文件的第一页不能与前一个pdf文件的最后一页在同一张纸的背面打印。
您需要选择性地向具有奇数页数的pdf文件添加仅一个空白页。
我编写了一个简单的脚本,名为abbblankifneeded,您可以将其放在一个文件中,然后复制到/usr/bin或/usr/local/bin中。
然后,在您存储pdf的文件夹中使用以下语法来调用:
for f in *.pdf; do addblankifneeded $f; done
该脚本会向具有奇数页数的pdf文件末尾添加一个空白页,跳过已经有偶数页数的pdf文件,然后将所有pdf文件合并成一个文件。
要求:pdftk,pdfinfo
注意:根据您的bash环境,您可能需要将脚本第一行的sh解释器替换为bash解释器
#!/bin/sh
#script to add automatically blank page at the end of a pdf documents, if count of their pages is a not a module of 2 and then to join all pdfs into one
#
# made by Dingo
#
# dokupuppylinux.co.cc
#
#http://pastebin.com/u/dingodog (my pastebin toolbox for pdf scripts)
#
filename=$1
altxlarg="`pdfinfo -box $filename| grep MediaBox | cut -d : -f2 | awk '{print $3 FS $4}'`"
echo "%PDF-1.4
%µí®û
3 0 obj
<<
/Length 0
>>
stream
endstream
endobj
4 0 obj
<<
/ProcSet [/PDF ]
/ExtGState <<
/GS1 1 0 R
>>
>>
endobj
5 0 obj
<<
/Type /Halftone
/HalftoneType 1
/HalftoneName (Default)
/Frequency 60
/Angle 45
/SpotFunction /Round
>>
endobj
1 0 obj
<<
/Type /ExtGState
/SA false
/OP false
/HT /Default
>>
endobj
2 0 obj
<<
/Type /Page
/Parent 7 0 R
/Resources 4 0 R
/Contents 3 0 R
>>
endobj
7 0 obj
<<
/Type /Pages
/Kids [2 0 R ]
/Count 1
/MediaBox [0 0 595 841]
>>
endobj
6 0 obj
<<
/Type /Catalog
/Pages 7 0 R
>>
endobj
8 0 obj
<<
/CreationDate (D:20110915222508)
/Producer (libgnomeprint Ver: 2.12.1)
>>
endobj
xref
0 9
0000000000 65535 f
0000000278 00000 n
0000000357 00000 n
0000000017 00000 n
0000000072 00000 n
0000000146 00000 n
0000000535 00000 n
0000000445 00000 n
0000000590 00000 n
trailer
<<
/Size 9
/Root 6 0 R
/Info 8 0 R
>>
startxref
688
%%EOF" | sed -e "s/595 841/$altxlarg/g">blank.pdf
pdftk blank.pdf output fixed.pdf
mv fixed.pdf blank.pdf
pages="`pdftk $filename dump_data | grep NumberOfPages | cut -d : -f2`"
if [ $(( $pages % 2 )) -eq 0 ]
then echo "$filename has already a multiple of 2 pages ($pages ). Script will be skipped for this file" >>report.txt
else
pdftk A=$filename B=blank.pdf cat A B output blankadded.pdf
mv blankadded.pdf $filename
pdffiles=`ls *.pdf | grep -v -e blank.pdf -e joinedtogether.pdf| xargs -n 1`; pdftk $pdffiles cat output joinedtogether.pdf
fi
exit 0
免责声明:以下提到的工具是本人编写。
这是一个免费且开源的命令行界面工具,用于执行 PDF 的合并或拆分等操作。 merge
命令有一个选项:
[--addBlanks]:如果合并后文档页数为奇数,则在每个文档之后添加一个空白页(可选)
既然您只需要打印 PDF,我假设您不关心文档的顺序。这是您可以使用的命令:
sejda-console merge -d /path/to/pdfs_to_merge -o /outputpath/merged_file.pdf --addBlanks
它可以从官方网站 sejda.org 下载。
这是一个由 Sejda 支持的 Web 应用程序,具有上述相同的功能,但通过 Web 界面实现。 您需要上传文件,因此,根据您的输入集的大小,可能不是适合您的正确解决方案。
如果选择 merge
命令并上传 PDF 文档,则必须选中复选框 Add blank page if odd page number
才能获得所需的行为。
这是最流行的解决方案的PowerShell版本,使用pdftk
。我为Windows编写了此代码,但您可以在其他平台上使用PowerShell Core。
# install pdftk server if on windows
# https://www.pdflabs.com/tools/pdftk-server/
$blank_pdf_path = ".\blank.pdf"
$input_folder = ".\input\"
$aligned_folder = ".\aligned\"
$final_output_path = ".\result.pdf"
foreach($file in (Get-ChildItem $input_folder -Filter *.pdf))
{
# easy but might break if pdfinfo output changes
# takes 7th line with the "Page: 2" and matches only numbers
(pdfinfo $file.FullName)[7] -match "(\d+)" | Out-Null
$npages = $Matches[1]
$modulo = $npages % 2
if($modulo -eq 1)
{
$output_path = Join-Path $aligned_folder $file.Name
pdftk $file.FullName $blank_pdf_path output $output_path
}
else
{
Copy-Item $file.FullName -Destination $aligned_folder
}
}
$aligned_pdfs = Join-Path $aligned_folder "*.pdf"
pdftk $aligned_pdfs output $final_output_path
Martin 有了一个良好的开端。我更新了 PyPdf2 并进行了一些微调,例如按文件名排序输出。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from argparse import ArgumentParser
from glob import glob
from PyPDF2 import PdfFileReader, PdfFileWriter
import os.path
def merge(pdfpath, blank_filename, output_filename):
with open(blank_filename, "rb") as f:
blank = PdfFileReader(f)
output = PdfFileWriter()
filelist = sorted(glob(os.path.join(pdfpath,'*.pdf')))
for pdffile in filelist:
if pdffile == output_filename:
continue
print("Parse '%s'" % pdffile)
document = PdfFileReader(open(pdffile, 'rb'))
for i in range(document.getNumPages()):
output.addPage(document.getPage(i))
if document.getNumPages() % 2 == 1:
output.addPage(blank.getPage(0))
print("Add blank page to '%s' (had %i pages)" % (pdffile, document.getNumPages()))
print("Start writing '%s'" % output_filename)
with open(output_filename, "wb") as output_stream:
output.write(output_stream)
if __name__ == "__main__":
parser = ArgumentParser()
# Add more options if you like
parser.add_argument("-o", "--output", dest="output_filename", default="merged.pdf",
help="write merged PDF to FILE", metavar="FILE")
parser.add_argument("-b", "--blank", dest="blank_filename", default="blank.pdf",
help="path to blank PDF file", metavar="FILE")
parser.add_argument("-p", "--path", dest="path", default=".",
help="path of source PDF files")
args = parser.parse_args()
merge(args.path, args.blank_filename, args.output_filename)
`
这个方法对我有效。在macOS上使用了pdfcpu。 可以按照以下方式安装:
brew install pdfcpu
并且稍作修改来自https://dev59.com/m2kw5IYBdhLWcg3wi7Fz#12761103的代码。
#!/bin/bash
mkdir aligned
for f in *.pdf; do
let npages=$(pdfcpu info "$f"|grep 'Page count:'|awk '{print $3}')
let modulo="($npages %2)"
if [ $modulo -eq 1 ]; then
pdfcpu page insert -pages l -mode after "$f" "aligned/$f"
else
cp "$f" "aligned/$f"
fi
done
pdfcpu merge merged-aligned.pdf aligned/*.pdf
rm -rf aligned
注意!它在当前目录中创建并删除“aligned”目录。因此,可以随意改进它以使其更安全使用。
Chris Lercher在https://dev59.com/m2kw5IYBdhLWcg3wi7Fz#12761103中的代码对我来说并不完全适用。我不知道这是因为我正在使用Cygwin/mintty,还是因为我必须使用qpdf
而不是pdftk
。以下是对我有效的代码:
#!/bin/bash
for f in *.pdf; do
npages=$(pdfinfo "$f"|grep 'Pages:'|sed 's/[^0-9]*//g')
modulo=$(($npages %2))
if [ $modulo -eq 1 ]; then
qpdf --empty --pages "$f" "path/to/blank.pdf" -- "aligned_$f"
else
cp "$f" "aligned_$f"
fi
done
qpdf
将它们合并(感谢https://dev59.com/AXE95IYBdhLWcg3wAo9U#51080927)。qpdf --verbose --empty --pages aligned_* -- all.pdf
下面是我使用的用于创建空白页面的https://unix.stackexchange.com/a/272878中的有用代码:
echo "" | ps2pdf -sPAPERSIZE=a4 - blank.pdf
pyPDF
包。/path/to/blank.pdf
(我已经在这里创建了空白pdf页面)。pdfmerge.py
在您的$PATH
的任何目录中。(我不是Windows用户。在Linux下,这很简单。如果您遇到错误或者它可以正常工作,请告诉我。)pdfmerge.py
可执行。在只包含要合并的PDF文件的目录中运行uniprint.py
。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from argparse import ArgumentParser
from glob import glob
from pyPdf import PdfFileReader, PdfFileWriter
def merge(path, blank_filename, output_filename):
blank = PdfFileReader(file(blank_filename, "rb"))
output = PdfFileWriter()
for pdffile in glob('*.pdf'):
if pdffile == output_filename:
continue
print("Parse '%s'" % pdffile)
document = PdfFileReader(open(pdffile, 'rb'))
for i in range(document.getNumPages()):
output.addPage(document.getPage(i))
if document.getNumPages() % 2 == 1:
output.addPage(blank.getPage(0))
print("Add blank page to '%s' (had %i pages)" % (pdffile, document.getNumPages()))
print("Start writing '%s'" % output_filename)
output_stream = file(output_filename, "wb")
output.write(output_stream)
output_stream.close()
if __name__ == "__main__":
parser = ArgumentParser()
# Add more options if you like
parser.add_argument("-o", "--output", dest="output_filename", default="merged.pdf",
help="write merged PDF to FILE", metavar="FILE")
parser.add_argument("-b", "--blank", dest="blank_filename", default="blank.pdf",
help="path to blank PDF file", metavar="FILE")
parser.add_argument("-p", "--path", dest="path", default=".",
help="path of source PDF files")
args = parser.parse_args()
merge(args.path, args.blank_filename, args.output_filename)
请在Windows和Mac上测试并留下评论。
如果不能正常工作/需要改进,请始终留下评论。
在Linux上它可以正常工作。将3个PDF合并为一个200页的PDF只需不到一秒钟。
pdfjam
。 - Martin Schrödera2ps
可以被说服做到这一点。 - luser droog