You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FPDF单元格消失问题求助:大文本适配时单元格丢失

问题:大段文本导致PDF单元格消失(Quizlet闪卡转换工具)

我开发了一个将Quizlet闪卡转为可打印大闪卡的工具,因为Quizlet官方移除了这个功能。工具基础功能正常,但处理大段文本时会出现异常:单元格直接消失(并非字体大小变为0)。我尝试过两种适配105宽度单元格的方案——缩小字体、按3个单词分组换行,但都没解决问题。问题截图显示原本应存在内容的单元格区域为空,无任何文本或边框。

以下是我尝试的两段代码:

第一段尝试代码:

from fpdf import FPDF
import os, math, re, numpy

def group_words(s, n):
    words = s.split()
    for i in range(0, len(words), n):
        yield ' '.join(words[i:i+n])

def printcell(text):
    #105 is the width of 1 cell
    width = pdf.get_string_width(text)
    pdf.set_font("Japanese", size = fontsize)

    if(width >= 104):
        pdf.set_font("Japanese", size = fontsize-5)
        print("splitting")
        words = numpy.array(list(group_words(text,3)))
        print(words)
        words.join('\n')  
        print(words)
        pdf.cell(105, 74.25, words, 1, 1, 'C')
    else:
        pdf.cell(105, 74.25, text, 0, 1, 'C')

第二段尝试代码(早期版本,未做字体非0检查):

def printcell(text):
    while(pdf.get_string_width(text)>105):
        if (counter == fontsize):
            pass
        else:
            pdf.set_font("Japanese", size = fontsize-counter)
            counter+=1
    pdf.cell(105, 74.25, text, 0, 1, 'C')

问题分析与修复方案

第一段代码的核心问题

  1. numpy数组无法被PDF单元格识别:你把分组后的文本转成了numpy数组,但pdf.cell不支持数组类型参数,直接导致内容无法渲染,单元格看起来"消失"。
  2. join方法使用错误:words.join('\n')不会修改原数组,需要将结果赋值给新变量;且numpy数组的join用法不符合字符串拼接逻辑,应该用普通列表处理。
  3. pdf.cell不支持多行文本:即使生成了带换行的文本,cell也不会自动换行,文本会溢出单元格导致显示异常。

修复后的第一段代码:

from fpdf import FPDF
import os, math, re

def group_words(s, n):
    words = s.split()
    for i in range(0, len(words), n):
        yield ' '.join(words[i:i+n])

def printcell(text):
    # 105是单个单元格的宽度
    pdf.set_font("Japanese", size=fontsize)
    width = pdf.get_string_width(text)

    if width >= 104:
        pdf.set_font("Japanese", size=fontsize-5)
        print("splitting")
        # 用普通列表处理分组文本,无需numpy
        grouped_lines = list(group_words(text, 3))
        # 正确生成带换行的文本
        wrapped_text = '\n'.join(grouped_lines)
        print(wrapped_text)
        # 改用multi_cell支持多行文本渲染,第二个参数为每行高度
        pdf.multi_cell(105, 15, wrapped_text, 1, 'C')
    else:
        pdf.cell(105, 74.25, text, 0, 1, 'C')

第二段代码的核心问题

  1. counter未初始化:函数内使用了counter但未定义初始值,会直接抛出异常。
  2. 死循环风险:如果缩小到极小字体后文本宽度仍超过105,会进入无限循环。
  3. 无字体下限限制:未设置最小字体大小,可能缩到负数或过小导致文本无法显示。

修复后的第二段代码:

def printcell(text):
    # 初始化计数器与最小字体限制
    counter = 0
    min_font_size = 8
    current_font_size = fontsize
    pdf.set_font("Japanese", size=current_font_size)
    
    # 循环缩小字体,直到宽度符合要求或达到最小字体
    while pdf.get_string_width(text) > 105 and current_font_size > min_font_size:
        current_font_size -= 1
        pdf.set_font("Japanese", size=current_font_size)
        counter += 1
    # 兜底逻辑:最小字体仍超宽时,自动切换到换行处理
    if pdf.get_string_width(text) > 105:
        grouped_lines = list(group_words(text, 3))
        wrapped_text = '\n'.join(grouped_lines)
        pdf.multi_cell(105, 15, wrapped_text, 0, 'C')
    else:
        pdf.cell(105, 74.25, text, 0, 1, 'C')

通用注意事项

  • 确保全局变量fontsize已正确定义(例如fontsize = 16)。
  • 确认"Japanese"字体已正确加载,字体缺失也会导致文本不显示。
  • 使用multi_cell时,需根据字体大小调整每行高度参数,避免文本重叠。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 18:39:28