Files
life-echo/api/services/pdf_service.py
2026-01-07 11:56:46 +08:00

108 lines
3.2 KiB
Python

"""
PDF 生成服务
"""
from typing import List
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
from io import BytesIO
import os
class PDFService:
"""PDF 生成服务"""
def __init__(self):
# 尝试注册中文字体
try:
# 使用系统字体或 ReportLab 内置的中文字体
# 如果没有中文字体文件,使用 UnicodeCIDFont
pdfmetrics.registerFont(UnicodeCIDFont('STSong-Light'))
self.chinese_font = 'STSong-Light'
except Exception:
# 如果注册失败,使用默认字体(可能不支持中文)
self.chinese_font = 'Helvetica'
async def generate_pdf(self, book, chapters: List) -> bytes:
"""
生成 PDF
Args:
book: 回忆录对象
chapters: 章节列表
Returns:
PDF 字节数据
"""
buffer = BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=A4)
# 创建样式
styles = getSampleStyleSheet()
title_style = ParagraphStyle(
'CustomTitle',
parent=styles['Heading1'],
fontSize=24,
spaceAfter=30,
alignment=1, # 居中
fontName=self.chinese_font
)
heading_style = ParagraphStyle(
'CustomHeading',
parent=styles['Heading1'],
fontSize=18,
spaceAfter=12,
fontName=self.chinese_font
)
normal_style = ParagraphStyle(
'CustomNormal',
parent=styles['Normal'],
fontSize=12,
leading=18,
fontName=self.chinese_font
)
# 构建内容
story = []
# 封面
story.append(Paragraph(book.title, title_style))
story.append(Spacer(1, 0.5*inch))
story.append(PageBreak())
# 目录
story.append(Paragraph("目录", heading_style))
story.append(Spacer(1, 0.2*inch))
for i, chapter in enumerate(chapters, 1):
story.append(Paragraph(f"{i}. {chapter.title}", normal_style))
story.append(PageBreak())
# 章节内容
for chapter in chapters:
story.append(Paragraph(chapter.title, heading_style))
story.append(Spacer(1, 0.2*inch))
# 分段处理内容
paragraphs = chapter.content.split('\n\n')
for para in paragraphs:
if para.strip():
story.append(Paragraph(para.strip(), normal_style))
story.append(Spacer(1, 0.1*inch))
story.append(PageBreak())
# 生成 PDF
doc.build(story)
buffer.seek(0)
return buffer.read()
# 全局实例
pdf_service = PDFService()