裁剪 PDF 内容
Crop PDF Content
我有一个 pdf 文件想要拼版。它有 8.5x11" 页面、媒体框和裁剪框。我希望 pdf 有 17x11" 页面,通过合并相邻页面。不幸的是,大多数页面的内容要么完全在裁剪框之外,要么跨越裁剪框。因为每个页面只能有一个流和裁剪框,所以在拼版时,重叠的内容会变得可见。这很糟糕。
我不想栅格化我的 pdf,因为那样会提前修复 DPI。所以我不会考虑将页面导出为图像,附加图像(imagemagick),然后将这些配对图像嵌入到新的 pdf 中。
我在 postscript 中也遇到了问题 - 在 pdf->ps->pdf 转换过程中透明度、字体光栅化和其他视觉故障问题。
答案应该是可编写脚本的。
到目前为止我已经尝试过:
- podofo 拼版脚本 (lua)
- PyPDF2 (python)
- ghostscript
- 乳胶
问题“Ghostscript removes content outside the crop box?”表明 ghostscript 的 pdfwrite 模块在生成输出 pdf 文件时,将根据裁剪框光栅化和裁剪内容。所以我只需要通过 ghostscript 的 pdfwrite 模块来传输我的 pdf。不幸的是,这不起作用。
当我尝试通过 evince 将 pdf 打印到另一个 pdf 时,我正要放弃。它工作得很好——裁剪框内的文本和矢量元素没有被栅格化,裁剪框外的元素被删除(我还没有测试跨界元素)。质量高分辨率(页面大小)且外观相同。事实上,除了元数据之外,一切似乎都一样。
所以:
- 这个问题是可以的
- 答案已经存在
如何访问它?
我认为 cup 的 pdftopdf
二进制文件可能会提供此功能。我在调用外部二进制文件时没有任何问题....但不知道如何使用 pdftopdf
.
编辑: Link to test pdf。它包含光栅、矢量和文本项 - 一些被部分透明的项目部分遮挡 - 跨越并邻接相邻页面。再一次,通过 cups 打印此 PDF 似乎会裁剪裁剪框外的所有内容。然而,在 inkscape 中打开过滤后的 pdf 显示页外项目被单独屏蔽,没有被裁剪 - 除了文本,它被修剪。
Ghostscript 和 pdfwrite 设备通常不会栅格化输入 PDF 文件的内容(需要注意的是涉及透明输入和输出 < PDF 1.4 的情况)。
完全裁剪掉的对象不会保留到输出中。
所以简短的回答是,使用 Ghostscript 和 pdfwrite 设备这应该是完全可行的,其优点是可以在单个操作中拼版页面。我确实有一个关于类似情况下的裁剪(反向拼版)的公开错误报告,但还没有时间解决它。
请注意,Ghostscript 通常使用 MediaBox 作为剪辑区域,如果要使用 CropBox,则需要在命令行中添加 -dUseCropBox
。
诀窍是使用 Form XObjects 在一个页面中强加多个页面。 Form XObjects 可以引用整个 PDF 页,并保持独立的剪辑。 PyPDF2 不支持 Form XObjects,因此合并统一了所有输入页面的流,以便它们共享输出页面的 clip/media 框。我已经成功地使用了 pdflatex 和 pdfrw (python) - 测试程序在下面内联。由于 Form XObjects 派生自类似的 postscript level 2 功能,如 it should be possible to achieve the same goal in ghostscript using "page clips". In fact , but it appears horrendously complicated. Combined with the font rasterization issues of poppler's pdftops 所建议(即使兼容级别 > 1.4),我已经放弃了 ghostscript 方法。
源自 的 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 定义,即使它的行为类似于列表。此外 +
的作用类似于 +=
,因为它修改了左侧对象。
我有一个 pdf 文件想要拼版。它有 8.5x11" 页面、媒体框和裁剪框。我希望 pdf 有 17x11" 页面,通过合并相邻页面。不幸的是,大多数页面的内容要么完全在裁剪框之外,要么跨越裁剪框。因为每个页面只能有一个流和裁剪框,所以在拼版时,重叠的内容会变得可见。这很糟糕。
我不想栅格化我的 pdf,因为那样会提前修复 DPI。所以我不会考虑将页面导出为图像,附加图像(imagemagick),然后将这些配对图像嵌入到新的 pdf 中。
我在 postscript 中也遇到了问题 - 在 pdf->ps->pdf 转换过程中透明度、字体光栅化和其他视觉故障问题。
答案应该是可编写脚本的。
到目前为止我已经尝试过:
- podofo 拼版脚本 (lua)
- PyPDF2 (python)
- ghostscript
- 乳胶
问题“Ghostscript removes content outside the crop box?”表明 ghostscript 的 pdfwrite 模块在生成输出 pdf 文件时,将根据裁剪框光栅化和裁剪内容。所以我只需要通过 ghostscript 的 pdfwrite 模块来传输我的 pdf。不幸的是,这不起作用。
当我尝试通过 evince 将 pdf 打印到另一个 pdf 时,我正要放弃。它工作得很好——裁剪框内的文本和矢量元素没有被栅格化,裁剪框外的元素被删除(我还没有测试跨界元素)。质量高分辨率(页面大小)且外观相同。事实上,除了元数据之外,一切似乎都一样。
所以:
- 这个问题是可以的
- 答案已经存在
如何访问它?
我认为 cup 的 pdftopdf
二进制文件可能会提供此功能。我在调用外部二进制文件时没有任何问题....但不知道如何使用 pdftopdf
.
编辑: Link to test pdf。它包含光栅、矢量和文本项 - 一些被部分透明的项目部分遮挡 - 跨越并邻接相邻页面。再一次,通过 cups 打印此 PDF 似乎会裁剪裁剪框外的所有内容。然而,在 inkscape 中打开过滤后的 pdf 显示页外项目被单独屏蔽,没有被裁剪 - 除了文本,它被修剪。
Ghostscript 和 pdfwrite 设备通常不会栅格化输入 PDF 文件的内容(需要注意的是涉及透明输入和输出 < PDF 1.4 的情况)。
完全裁剪掉的对象不会保留到输出中。
所以简短的回答是,使用 Ghostscript 和 pdfwrite 设备这应该是完全可行的,其优点是可以在单个操作中拼版页面。我确实有一个关于类似情况下的裁剪(反向拼版)的公开错误报告,但还没有时间解决它。
请注意,Ghostscript 通常使用 MediaBox 作为剪辑区域,如果要使用 CropBox,则需要在命令行中添加 -dUseCropBox
。
诀窍是使用 Form XObjects 在一个页面中强加多个页面。 Form XObjects 可以引用整个 PDF 页,并保持独立的剪辑。 PyPDF2 不支持 Form XObjects,因此合并统一了所有输入页面的流,以便它们共享输出页面的 clip/media 框。我已经成功地使用了 pdflatex 和 pdfrw (python) - 测试程序在下面内联。由于 Form XObjects 派生自类似的 postscript level 2 功能,如
源自
\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 定义,即使它的行为类似于列表。此外+
的作用类似于+=
,因为它修改了左侧对象。