108 lines
3.2 KiB
Python
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()
|