引子/Introduce
最近女朋友要打印门票,但是门票样式是这种的,一页一张PDF(同个文件下),会比较浪费纸张。由于只需要打印A4(A4尺寸下尽可能多得打印门票),考虑到保留宽度不变的情况下把几个pdf接在一起印比较合适,不浪费纸张,于是在网上研究怎么把PDF合并在一起打印,无果。基本上都是使用自带的布局 不过都很浪费空间,于是决定写一篇博客介绍如何使用python完成操作。
Recently, my girlfriend faced a printing dilemma that many might find relatable. She needed to print out tickets, each formatted as a separate PDF page within a single file. The original sizes of these tickets weren’t A4, and printing them one by one would lead to unnecessary waste of paper. The quest was to fit as many of these tickets onto A4 paper as possible without altering their width, ensuring an eco-friendly approach to printing. Surprisingly, a deep dive into the internet didn’t yield a straightforward solution. Most available options stuck to standard layouts, which weren’t space-efficient. This led me to craft a Python solution that precisely meets these needs. This blog post aims to share how Python can be used to merge PDF pages for optimal A4 printing, a handy guide for those looking to conserve paper while maintaining document integrity.
解决方案/Solutions
由于门票有正反面,特意在函数里添加了repeat_first_page
的参数,如无特殊需求,默认False
即可。代码很简单,不介绍了。
Due to the tickets having both a front and back side, we intentionally included the repeat_first_page
parameter in the function. Unless there’s a special need, it can simply be left at its default setting of False
. The code is quite simple and requires no further explanation.
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from pdf2image import convert_from_path
def pdf_pages_to_images(pdf_path, dpi=800):
# 使用指定的DPI将PDF页面转换为图像
return convert_from_path(pdf_path, dpi=dpi)
def combine_images_into_pdf(images, output_pdf, images_per_page=3, repeat_first_page=False):
c = canvas.Canvas(output_pdf, pagesize=A4)
width, height = A4 # A4页面尺寸
if repeat_first_page and len(images) >= 1:
# 在每个新页面的开始重复第一页图像
repeated_images = [images[0]] * (images_per_page - 1) + images
else:
repeated_images = images
img_height = height / images_per_page
img_width = width
for i in range(0, len(repeated_images), images_per_page):
if i > 0:
c.showPage()
for j in range(min(images_per_page, len(repeated_images) - i)):
img = repeated_images[i + j]
img_path = f"/tmp/image_{i + j}.png"
img.save(img_path)
# 计算图像在页面上的位置
x = 0
y = height - img_height * (j + 1)
c.drawImage(img_path, x, y, width=img_width, height=img_height, preserveAspectRatio=True)
c.save()
input_pdf = "input.pdf"
output_pdf = "Front.pdf"
images = pdf_pages_to_images(input_pdf)
combine_images_into_pdf(images, output_pdf, images_per_page=4, repeat_first_page=False) # 正面
input_pdf = "input2.pdf"
output_pdf = "Back.pdf"
images = pdf_pages_to_images(input_pdf)
combine_images_into_pdf(images, output_pdf, images_per_page=4, repeat_first_page=True) # 反面
代码/Code
本段代码旨在解决打印门票时的纸张浪费问题,通过将门票的正反面高效地组合到A4纸张上。首先,我们使用pdf_pages_to_images
函数将PDF页面转换为图像,这一步骤通过指定高DPI值来确保图像质量。随后,combine_images_into_pdf
函数负责将转换得到的图像组合到一个或多个A4页面上,其中images_per_page
参数允许用户自定义每页显示的图像数量。特别地,repeat_first_page
参数用于控制是否在每个新页面上重复第一页图像,这一功能对于需要打印有正反面的门票尤其有用。通过这样的处理,不仅优化了纸张使用,还保留了门票的原始宽度,避免了不必要的调整和失真。
This code segment is designed to address the issue of paper wastage when printing tickets by efficiently combining the front and back sides of tickets onto A4 paper. Initially, the pdf_pages_to_images
function converts PDF pages into images, ensuring high image quality by specifying a high DPI value. Subsequently, the combine_images_into_pdf
function is responsible for combining the converted images onto one or more A4 pages, where the images_per_page
parameter allows users to customize the number of images displayed per page. Notably, the repeat_first_page
parameter controls whether to repeat the first page image on every new page, a feature particularly useful for printing tickets with both front and back sides. Through such processing, not only is paper usage optimized, but the original width of the tickets is also preserved, avoiding unnecessary adjustments and distortions.