在Python开发中,将字符串内容转换为PDF文件是常见需求,可用于生成电子票据、数据报表、存档文档等场景,实现方式有多种,其中使用reportlab库是最主流的方案之一。

常用方案对比
目前Python中生成PDF的库较多,不同库的适用场景有所区别,以下是常见方案的对比:
| 库名称 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| reportlab | 功能全面,支持自定义样式、插入图片、表格等,文档完善 | 学习成本稍高,复杂排版需要较多配置 | 需要自定义PDF样式、生成复杂内容的场景 |
| fpdf | 轻量易用,上手简单,代码量少 | 功能相对有限,复杂排版支持不足 | 简单文本内容生成PDF的场景 |
| weasyprint | 支持HTML和CSS渲染,适合已有HTML内容的转换 | 依赖较多,安装相对复杂 | 已有HTML格式内容需要转PDF的场景 |
使用reportlab实现字符串转PDF
环境安装
首先需要安装reportlab库,使用pip命令即可完成安装:
pip install reportlab
基础实现步骤
使用reportlab生成PDF的核心流程分为三步:创建PDF文档对象、添加内容页、写入字符串内容并保存文件。以下是完整的实现代码:
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4
def string_to_pdf(content, output_path, font_path="simhei.ttf"):
# 注册中文字体,避免中文显示乱码
pdfmetrics.registerFont(TTFont("SimHei", font_path))
# 创建PDF画布,设置页面大小为A4
c = canvas.Canvas(output_path, pagesize=A4)
# 设置字体和字号
c.setFont("SimHei", 12)
# 设置起始坐标,A4页面左上角为(0, 841.89),这里从(50, 800)开始写入
x = 50
y = 800
# 按行分割字符串,逐行写入PDF
lines = content.split("n")
for line in lines:
# 如果当前y坐标小于50,新建一页
if y < 50:
c.showPage()
c.setFont("SimHei", 12)
y = 800
c.drawString(x, y, line)
y -= 20 # 行间距设置为20
# 保存PDF文件
c.save()
if __name__ == "__main__":
# 待转换的字符串内容
text_content = "这是一段测试字符串n第二行内容n第三行内容n这是中文内容测试,验证字体是否正常显示"
# 输出PDF路径
output_file = "output.pdf"
string_to_pdf(text_content, output_file)
print("PDF生成完成,路径为:" + output_file)
代码说明
上述代码中需要注意几个关键点:
- 中文字体注册:reportlab默认不支持中文,需要下载中文字体文件(如黑体simhei.ttf),放在代码同目录下,通过
pdfmetrics.registerFont方法注册后才能正常显示中文。 - 坐标系统:reportlab的画布坐标以页面左下角为原点(0,0),A4页面尺寸为(595.27, 841.89),代码中从(50,800)开始写入,避免内容贴边。
- 分页处理:当内容超过一页时,通过判断y坐标的值,调用
showPage方法新建页面,继续写入剩余内容。
常见问题解决
中文显示乱码
如果出现中文乱码,首先检查中文字体文件是否存在,路径是否正确,字体注册的名称是否和后续setFont方法调用的名称一致。如果字体文件损坏,也会导致中文无法正常显示,可更换其他中文字体文件重试。
字符串换行问题
如果字符串内容较长,没有手动换行,会出现内容超出页面右侧的情况。可以通过计算字符串宽度,自动换行的方式解决,以下是自动换行的补充代码:
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
def auto_wrap_text(text, font_name, font_size, max_width):
# 自动换行函数,根据最大宽度拆分文本
words = text
lines = []
current_line = ""
for char in words:
test_line = current_line + char
# 获取当前测试行的宽度
width = pdfmetrics.stringWidth(test_line, font_name, font_size)
if width <= max_width:
current_line = test_line
else:
lines.append(current_line)
current_line = char
if current_line:
lines.append(current_line)
return lines
def string_to_pdf_auto_wrap(content, output_path, font_path="simhei.ttf"):
pdfmetrics.registerFont(TTFont("SimHei", font_path))
c = canvas.Canvas(output_path, pagesize=A4)
c.setFont("SimHei", 12)
x = 50
y = 800
max_width = A4[0] - 100 # 左右各留50的边距
# 先按手动换行分割,再对每一行做自动换行
raw_lines = content.split("n")
all_lines = []
for raw_line in raw_lines:
wrapped_lines = auto_wrap_text(raw_line, "SimHei", 12, max_width)
all_lines.extend(wrapped_lines)
for line in all_lines:
if y < 50:
c.showPage()
c.setFont("SimHei", 12)
y = 800
c.drawString(x, y, line)
y -= 20
c.save()
if __name__ == "__main__":
long_text = "这是一段非常长的测试字符串,没有手动换行,需要程序自动根据页面宽度进行换行处理,验证自动换行功能是否正常工作,确保内容不会超出页面右侧边界"
string_to_pdf_auto_wrap(long_text, "auto_wrap_output.pdf")
print("自动换行PDF生成完成")
其他方案简介
如果不想使用reportlab,也可以选择fpdf库实现简单场景的字符串转PDF,以下是fpdf的实现示例:
from fpdf import FPDF
class PDF(FPDF):
def header(self):
self.set_font("SimHei", "B", 12)
self.cell(0, 10, "字符串生成PDF示例", 0, 1, "C")
def footer(self):
self.set_y(-15)
self.set_font("SimHei", "I", 8)
self.cell(0, 10, "第 " + str(self.page_no()) + " 页", 0, 0, "C")
def fpdf_string_to_pdf(content, output_path):
pdf = PDF()
pdf.add_font("SimHei", "", "simhei.ttf", uni=True)
pdf.set_font("SimHei", "", 12)
pdf.add_page()
pdf.multi_cell(0, 10, content)
pdf.output(output_path)
if __name__ == "__main__":
test_content = "使用fpdf库生成的PDF内容n第二行内容"
fpdf_string_to_pdf(test_content, "fpdf_output.pdf")
print("fpdf生成PDF完成")
fpdf的优势是代码更简洁,multi_cell方法可以自动处理换行,但自定义样式的能力不如reportlab,开发者可以根据实际需求选择合适的方案。