诀窍是使用 Form XObjects 将多个页面强加在单个页面中。表单 XObjects 可以引用整个 PDF 页面,并维护独立的剪辑。 PyPDF2 不支持 Form XObjects,因此合并会统一所有输入页面的流,以便它们共享输出页面的剪辑/媒体框。我已经成功地使用了 pdflatex 和 pdfrw (python) - 测试程序在下面内联。由于表单 XObjects 源自类似的 postscript 2 级功能,正如KenS 所建议的那样,应该可以使用“页面剪辑”在 ghostscript 中实现相同的目标。事实上he shared a ghostscript 2x1 imposition script in another answer,但它看起来非常复杂。结合poppler的pdftops的字体光栅化问题(即使兼容级别> 1.4),我已经放弃了ghostscript的方法。
派生自How to stitch two PDF pages together as one big page? 的Latex 脚本。需要pdflatex:
\documentclass{article}
\usepackage{pdfpages}
\usepackage[paperwidth=8.5in, paperheight=11in]{geometry}
\usepackage[multidot]{grffile}
\pagestyle{plain}
\begin{document}
\setlength\voffset{+0.0in}
\setlength\hoffset{+0.0in}
\includepdf[ noautoscale=true
, frame=false
, pages={1}
]
{<file.pdf>}
\eject \paperwidth=17in \pdfpagewidth=17in \paperheight=11in \pdfpageheight=11in
\includepdf[ nup=2x1
, noautoscale=true
, frame=false
, pages={2-,}
]
{<file.pdf>}
\end{document}
pdfrw(python 脚本)派生自pdfrw:examples:booklet。需要 pdfrw >= 0.2:
#!/usr/bin/env python3
# Copyright:
# Yclept Nemo
# 2016
# License:
# GPLv3
import itertools
import argparse
import pdfrw
# from itertool recipes in the python documentation
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return itertools.zip_longest(*args, fillvalue=fillvalue)
def pagemerge(page, *pages):
merged = pdfrw.PageMerge() + page
for page in reversed(list(itertools.takewhile(lambda i: i is not None, reversed(pages)))):
merged = merged + page
merged[-1].x = merged[-2].x + merged[-2].w
return merged.render()
parser = argparse.ArgumentParser(description='Impose PDF files using Form XOBjects')
parser.add_argument\
( "source"
, help="PDF, source path"
, type=pdfrw.PdfReader
)
parser.add_argument\
( "-s", "--spacer"
, help="PDF, spacer path"
, type=lambda fp: next(iter(pdfrw.PdfReader(fp).pages), None)
)
parser.add_argument\
( "target"
, help="PDF, target path"
)
args = parser.parse_args()
pages = args.source.pages[:1]
for pair in grouper(args.source.pages[1:], 2):
assert pair[0] is not None
pages.append(pagemerge(pair[0], args.spacer, pair[1]))
# include metadata in target
target = pdfrw.PdfWriter()
target.addpages(pages)
target.trailer.Info = args.source.Info
target.write(args.target)
pdfrw 0.2 的一些特性:
- 请注意,操作
+=、append 和extend 没有为pdfrw.PageMerge 定义,即使它的行为类似于列表。此外,+ 的作用类似于 +=,因为它修改了左侧对象。