Python PyFPDF库使用Multicell方法时自动分页异常问题
FPDF双列翻译对照表分页错位问题修复
问题描述
开发基于Python FPDF模块的语言翻译对照表生成程序,通过调用pdf.multicell()方法实现双列布局,左列放置非英语词汇、右列放置对应英文译文。配置pdf.set_auto_page_break()方法后,预期内容达到页面边界时自动新建页面,但实际运行出现异常:自动分页总是在新页面写入一行内容后才触发,导致翻译条目对应关系错位,页面存在大量空白。
问题复现代码
data = [['le bus', 'the bus'], ['le train', 'the train'], ['la gare', 'the train station']] # 其余翻译条目按格式补充 def write_to_pdf(data): pdf = FPDF() pdf.set_auto_page_break(True, 2) pdf.add_page() pdf.add_font('DejaVu', '', 'filepath/font', uni=True) pdf.set_font('DejaVu', '', 14) pdf.cell(200, 10, txt = title,ln = 1, align = 'C') pdf.cell(200, 10, txt = subtitle,ln = 2, align = 'C') pdf.set_font('DejaVu', '', 10) for section in data: try: top = pdf.y offset = pdf.x + 100 pdf.multi_cell(100,10,section[0],0,'L') pdf.y = top pdf.x = offset pdf.multi_cell(100,10,section[1],0,'R') except: pass pdf.output("Output.pdf")
故障根因
- 双列布局实现逻辑存在缺陷:写入左列内容前记录当前Y轴坐标,左列写完后强制将Y轴重置回记录值再写右列,该操作直接绕过了FPDF内置的自动分页校验逻辑。当左列内容触发自动分页时,FPDF已经完成新页跳转,但代码立刻将Y轴改回分页前的旧坐标,导致分页位置判断完全失准。
- 自动分页预留边距设置过小:
set_auto_page_break第二个参数仅设为2,没有给双列内容的高度计算预留容错空间,极易触发边界判断异常。 - 裸
except语句直接吞掉了所有坐标越界、分页触发类的运行时异常,导致错位问题无法被及时感知和定位。
修复方案
修复核心逻辑为提前预判分页位置,避免写入过程中被动触发自动分页,具体调整点如下:
- 写入每一组翻译条目前,先通过
split_only=True参数预计算左右两列内容折行后的行数,得到当前条目渲染需要的总高度 - 校验当前页剩余可渲染高度是否足够容纳当前条目,高度不足时主动调用
add_page()新建页面,避免multi_cell写入过程中被动触发分页 - 移除强制重置Y轴坐标的逻辑,左右列内容都从预校验后的同一起始Y坐标开始写入,写完后将Y轴统一移动到当前条目下方,作为下一条目的渲染起点
- 调整自动分页预留边距到合理值(15mm),删除吞异常的裸
except语句
修复后完整代码
from fpdf import FPDF # 翻译数据集,格式为[原语言词汇, 对应英文译文] data = [['le bus', 'the bus'], ['le train', 'the train'], ['la gare', 'the train station']] title = "外语-英语翻译对照表" subtitle = "核心词汇汇总" def write_to_pdf(data): pdf = FPDF() # 配置自动分页,页脚预留15mm边距 pdf.set_auto_page_break(True, 15) pdf.add_page() pdf.add_font('DejaVu', '', 'filepath/font', uni=True) # 写入标题区 pdf.set_font('DejaVu', '', 14) pdf.cell(0, 10, txt=title, ln=1, align='C') pdf.cell(0, 10, txt=subtitle, ln=2, align='C') pdf.set_font('DejaVu', '', 10) col_width = 90 # 单列内容宽度 line_height = 10 # 单行文字高度 col_gap = 10 # 左右两列中间的间距 for left_text, right_text in data: start_x = pdf.l_margin # 左列起始X坐标为页面左边距 start_y = pdf.get_y() right_col_x = start_x + col_width + col_gap # 右列起始X坐标 # 预计算左右列折行数,得到当前条目总高度 left_line_count = len(pdf.multi_cell(col_width, line_height, left_text, border=0, align='L', split_only=True)) right_line_count = len(pdf.multi_cell(col_width, line_height, right_text, border=0, align='R', split_only=True)) entry_height = max(left_line_count, right_line_count) * line_height # 剩余高度不足时主动分页 if start_y + entry_height > pdf.page_break_trigger: pdf.add_page() start_y = pdf.get_y() # 写入左列内容 pdf.set_xy(start_x, start_y) pdf.multi_cell(col_width, line_height, left_text, border=0, align='L') # 写入右列内容 pdf.set_xy(right_col_x, start_y) pdf.multi_cell(col_width, line_height, right_text, border=0, align='R') # 将光标移动到当前条目下方,准备写入下一条 pdf.set_y(start_y + entry_height) pdf.output("Output.pdf")
内容的提问来源于stack exchange,提问作者Max Davies
相关产品推荐
相关产品推荐

