You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

基于Python的ReportLab实现4×5图片网格生成方案问询

用ReportLab Table实现4×5照片接触印样的最佳方案

嘿,我完全懂你想用ReportLab做照片接触印样的需求——手动用drawImage一个个加确实太繁琐了,用Table组件来规整布局绝对是更聪明的选择!我帮你梳理了一套可行的实现方案,直接上代码和关键说明:

核心思路

每个Table单元格需要包含图片(保持宽高比)下方的文件名,所以我们要给每个单元格生成一个包含图片元素和文本元素的列表,让Table自动垂直排列它们。同时要计算好单元格的尺寸,适配A4纸的4列×5行布局,还要处理图片的缩放逻辑避免变形。

完整实现代码

from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Image, Paragraph
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle
from PIL import Image as PILImage
import os

def rowGen(lst, n):
    """按n个元素一组生成行数据"""
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

def create_image_cell(image_path, cell_width, cell_height):
    """生成包含图片和文件名的单元格内容"""
    # 用PIL获取图片原始宽高,计算缩放比例
    with PILImage.open(image_path) as img:
        orig_w, orig_h = img.size
    
    # 预留20点高度给文件名,计算图片的最大可用高度
    max_img_height = cell_height - 20
    scale = max_img_height / orig_h
    img_width = orig_w * scale
    
    # 如果缩放后图片宽度超过单元格宽度,再按宽度缩放
    if img_width > cell_width:
        scale = cell_width / orig_w
        img_height = orig_h * scale
        img_width = cell_width
    else:
        img_height = max_img_height
    
    # 创建ReportLab图片对象
    rl_image = Image(image_path, width=img_width, height=img_height)
    
    # 创建居中显示的文件名文本(用Paragraph美化样式)
    filename_style = ParagraphStyle(
        name="FileNameStyle",
        alignment=1,  # 1表示居中
        fontSize=10,
        fontName="Helvetica"
    )
    filename_paragraph = Paragraph(os.path.basename(image_path), filename_style)
    
    # 返回图片+文本的列表,Table会自动垂直排列这两个元素
    return [rl_image, filename_paragraph]

def makePDF(document_title, data):
    """生成PDF文档"""
    # 初始化文档,设置边距
    pdf = SimpleDocTemplate(
        document_title,
        pagesize=A4,
        leftMargin=20,
        rightMargin=20,
        topMargin=20,
        bottomMargin=20
    )
    
    # 定义Table样式:居中对齐、垂直居中、设置内边距
    table_style = TableStyle([
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        # 可选:添加网格线方便调试,发布时可以注释掉
        # ('BOX', (0,0), (-1,-1), 1, (0,0,0)),
        # ('INNERGRID', (0,0), (-1,-1), 0.5, (128,128,128))
    ])
    
    # 定义列宽和行高:A4纸扣除边距后,4列每列约138点,5行每行约160点
    col_widths = [138] * 4
    row_heights = [160] * 5
    
    # 创建Table并应用样式
    table = Table(data, colWidths=col_widths, rowHeights=row_heights)
    table.setStyle(table_style)
    
    # 构建PDF
    pdf.build([table])

if __name__ == "__main__":
    # 图片目录路径
    img_dir = "Images/"
    # 获取目录下所有jpg图片的完整路径
    image_paths = [
        os.path.join(img_dir, filename)
        for filename in os.listdir(img_dir)
        if filename.lower().endswith(".jpg")
    ]
    
    # 生成每个图片对应的单元格内容,再按4个一组分成行
    cell_contents = [create_image_cell(path, 138, 160) for path in image_paths]
    table_data = list(rowGen(cell_contents, 4))
    
    # 处理最后一行不足4个的情况,补空单元格避免布局错乱
    if len(table_data[-1]) < 4:
        table_data[-1] += [[]] * (4 - len(table_data[-1]))
    
    # 生成PDF
    makePDF("Photo_Contact_Sheet.pdf", table_data)

关键细节说明

  1. 图片缩放逻辑:用PIL获取原始图片尺寸,先按单元格高度(扣除文件名高度)缩放,若宽度超过单元格则再按宽度缩放,确保图片始终保持原始宽高比且完全适配单元格。
  2. 单元格内容结构:每个单元格用[图片元素, 文本段落]的列表,Table会自动将这两个元素垂直居中排列,完美实现图片在上、文件名在下的效果。
  3. Table尺寸控制:手动设置colWidthsrowHeights,保证每个单元格大小统一,适配A4纸的4×5布局。
  4. 空单元格填充:如果图片总数不是4的倍数,给最后一行补空单元格,避免Table布局出现错乱。

内容的提问来源于stack exchange,提问作者Petchalxande

火山引擎 最新活动