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

Python中使用FPDF2生成PDF:行内加粗、Unicode支持及自动分页

问题描述

使用FPDF2编写Python脚本生成PDF时,原本通过开启markdown=True的multi_cell()或write_html()实现行内加粗功能正常,但当文本包含Unicode字符““”时,出现以下错误:

fpdf.errors.FPDFUnicodeEncodingException: Character "“" at index 544 in text is outside the range of characters supported by the font used: "times". Please consider using a Unicode font.

于是下载了SourceSerifPro字体并通过add_font()添加,代码如下:

texto1 = f"""**{nombre}**, mayor de edad, vecino de **{ciudad_usuario}**, identificado con la **{id_tipo}**
 No. **{id_numero}** expedida en **{id_lugar_expedicion}**, actuando con mi propio nombre y ... """
fuente_tipo = "SourceSerifPro-Regular"
class PDF(FPDF):
    def __init__(self):
        FPDF.__init__(self, unit="mm", format="letter", orientation="P")
        self.add_font("SourceSerifPro-Regular", "", "SourceSerifPro-Regular.ttf")
    
    def header(self):
        self.set_xy(25, 10)
        self.set_font(fuente_tipo, '', 12)
        self.ln(15)
        self.cell(0, 10, fecha, 0)
        self.ln(15)
    
    def footer(self):
        self.set_xy(185, -15)
        self.set_font(family= fuente_tipo, size= 8)
        self.cell(0, 10, 'Página ' + str(self.page_no()) + ' de n', 0)

    def add_txt_text(self, route):
        with open(route, "r", encoding="utf-8") as f:
            texto = f.read()
        self.multi_cell(0, None, texto, markdown = True, new_x='LEFT', new_y= 'NEXT')

pdf = PDF()
pdf.set_margins(25, 30, 10)
pdf.add_page()
pdf.set_auto_page_break(auto=True, margin=20)
pdf.set_font(fuente_tipo, '', 12)
pdf.multi_cell(0, None,  texto1, markdown = True, new_x='LEFT', new_y= 'NEXT') # max_line_height=30,
# This text has a unicode caracter
pdf.add_txt_text('fundamento_juridico.txt')
pdf.output('ejemplo.pdf')

但添加字体后又出现新错误:

File "C:\Users\user\Documents\PDF_generator\index.py", line 101, in <module>
    pdf.multi_cell(0, None,  texto1, markdown = True, new_x='LEFT', new_y= 'NEXT') # max_line_height=30,
  File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\site-packages\fpdf\fpdf.py", line 216, in wrapper
    return fn(self, *args, **kwargs)
  File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\site-packages\fpdf\fpdf.py", line 3213, in multi_cell
    styled_text_fragments = self._preload_font_styles(normalized_string, markdown)
  File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\site-packages\fpdf\fpdf.py", line 3004, in _preload_font_styles     
    self.set_font(style="B")
  File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\site-packages\fpdf\fpdf.py", line 1873, in set_font
    raise FPDFException(
fpdf.errors.FPDFException: Undefined font: sourceserifpro-regularB - Use built-in fonts or FPDF.add_font() beforehand

当前困境:要么删除Unicode字符,要么无法使用行内加粗。需要实现同时支持行内加粗、Unicode字符、文本触底自动分页的PDF生成。

解决方案

问题核心是仅添加了常规字重的字体,而Markdown加粗需要对应字体的粗体版本,调整步骤如下:

  1. 下载粗体字体文件:获取SourceSerifPro的粗体版本(如SourceSerifPro-Bold.ttf),与常规字体放在同一目录。

  2. 同时添加常规与粗体字体:在PDF类的__init__方法中,分别添加两种字重的字体,注意粗体的style参数设为"B":

class PDF(FPDF):
    def __init__(self):
        FPDF.__init__(self, unit="mm", format="letter", orientation="P")
        # 添加常规字体
        self.add_font("SourceSerifPro", "", "SourceSerifPro-Regular.ttf")
        # 添加粗体字体
        self.add_font("SourceSerifPro", "B", "SourceSerifPro-Bold.ttf")
  1. 统一字体家族名称:将fuente_tipo改为字体家族名(去掉-Regular后缀),让FPDF能自动匹配不同字重:
fuente_tipo = "SourceSerifPro"
  1. 调整所有字体调用:确保所有set_font使用统一的家族名称,避免指定具体字重文件名。

修改后的完整代码:

texto1 = f"""**{nombre}**, mayor de edad, vecino de **{ciudad_usuario}**, identificado con la **{id_tipo}**
 No. **{id_numero}** expedida en **{id_lugar_expedicion}**, actuando con mi propio nombre y ... """
fuente_tipo = "SourceSerifPro"
class PDF(FPDF):
    def __init__(self):
        FPDF.__init__(self, unit="mm", format="letter", orientation="P")
        self.add_font(fuente_tipo, "", "SourceSerifPro-Regular.ttf")
        self.add_font(fuente_tipo, "B", "SourceSerifPro-Bold.ttf")
    
    def header(self):
        self.set_xy(25, 10)
        self.set_font(fuente_tipo, '', 12)
        self.ln(15)
        self.cell(0, 10, fecha, 0)
        self.ln(15)
    
    def footer(self):
        self.set_xy(185, -15)
        self.set_font(family= fuente_tipo, size= 8)
        self.cell(0, 10, 'Página ' + str(self.page_no()) + ' de n', 0)

    def add_txt_text(self, route):
        with open(route, "r", encoding="utf-8") as f:
            texto = f.read()
        self.multi_cell(0, None, texto, markdown = True, new_x='LEFT', new_y= 'NEXT')

pdf = PDF()
pdf.set_margins(25, 30, 10)
pdf.add_page()
pdf.set_auto_page_break(auto=True, margin=20)
pdf.set_font(fuente_tipo, '', 12)
pdf.multi_cell(0, None,  texto1, markdown = True, new_x='LEFT', new_y= 'NEXT')
pdf.add_txt_text('fundamento_juridico.txt')
pdf.output('ejemplo.pdf')

此修改后,既支持Unicode字符,又能正常解析Markdown行内加粗,同时set_auto_page_break已开启,文本触底会自动分页,满足所有需求。

内容的提问来源于stack exchange,提问作者José Daza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:35:21