""" 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()