from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.colors import HexColor
import os
import json
import re
# 注册中文字体
try:
pdfmetrics.registerFont(TTFont('SimSun', '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', subfontIndex=0))
pdfmetrics.registerFont(TTFont('SimHei', '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', subfontIndex=0))
print("Chinese fonts loaded successfully")
except Exception as e:
print(f"Warning: Could not load Chinese font: {e}")
SimSun = 'Helvetica'
SimHei = 'Helvetica-Bold'
# 创建样式
styles = getSampleStyleSheet()
# 标题样式
title_style = ParagraphStyle(
'CustomTitle',
parent=styles['Heading1'],
fontName='Helvetica-Bold',
fontSize=24,
leading=30,
alignment=TA_CENTER,
spaceAfter=20,
textColor=HexColor('#1a1e24')
)
# 章节标题样式
h1_style = ParagraphStyle(
'CustomH1',
parent=styles['Heading1'],
fontName='SimHei',
fontSize=18,
leading=24,
spaceBefore=20,
spaceAfter=12,
textColor=HexColor('#3B6D8A')
)
# 子章节标题样式
h2_style = ParagraphStyle(
'CustomH2',
parent=styles['Heading2'],
fontName='SimHei',
fontSize=14,
leading=18,
spaceBefore=15,
spaceAfter=8,
textColor=HexColor('#2C2C30')
)
# 正文样式
body_style = ParagraphStyle(
'CustomBody',
parent=styles['BodyText'],
fontName='SimSun',
fontSize=10.5,
leading=16,
alignment=TA_JUSTIFY,
spaceBefore=6,
spaceAfter=6,
firstLineIndent=24,
textColor=HexColor('#2C2C30')
)
# 列表样式
bullet_style = ParagraphStyle(
'CustomBullet',
parent=styles['BodyText'],
fontName='SimSun',
fontSize=10.5,
leading=16,
leftIndent=36,
bulletIndent=18,
spaceBefore=3,
spaceAfter=3,
textColor=HexColor('#2C2C30')
)
# 图片说明样式
caption_style = ParagraphStyle(
'Caption',
parent=styles['BodyText'],
fontName='SimSun',
fontSize=9,
leading=12,
alignment=TA_CENTER,
spaceBefore=6,
spaceAfter=12,
textColor=HexColor('#7A7A84')
)
# 创建PDF文档
output_path = '/Users/chenxuan/Documents/CODE/visual-html./docs/软件说明书_v2.pdf'
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
rightMargin=2.79*cm,
leftMargin=2.79*cm,
topMargin=2.79*cm,
bottomMargin=2.5*cm
)
# 读取content.json
content_file = '/Users/chenxuan/Documents/CODE/visual-html./.dumate/pdf-软件说明书-20260726-a4e67093/content.json'
with open(content_file, 'r', encoding='utf-8') as f:
content = json.load(f)
# 构建文档内容
story = []
# 添加封面
cover_title = Paragraph("可视化大屏模板系统
软件说明书", title_style)
story.append(Spacer(1, 100))
story.append(cover_title)
story.append(Spacer(1, 30))
# 版本信息
cover_info = Paragraph("版本号:V1.0
开发完成日期:2026年7月", ParagraphStyle(
'CoverInfo',
parent=body_style,
alignment=TA_CENTER,
fontSize=12,
spaceBefore=20
))
story.append(cover_info)
story.append(PageBreak())
# 处理内容块
image_counter = 0
for block in content:
block_type = block.get('type', '')
if block_type == 'h2':
text = block.get('text', '').replace('', '').replace('', '')
story.append(Paragraph(text, h1_style))
elif block_type == 'h3':
text = block.get('text', '').replace('', '').replace('', '')
story.append(Paragraph(text, h2_style))
elif block_type == 'body':
text = block.get('text', '')
# 移除HTML标签
text = re.sub(r'<[^>]+>', '', text)
if text.strip():
story.append(Paragraph(text, body_style))
elif block_type == 'bullet':
text = block.get('text', '')
text = re.sub(r'<[^>]+>', '', text)
story.append(Paragraph('• ' + text, bullet_style))
elif block_type == 'figure':
image_path = block.get('path', '')
caption = block.get('caption', '')
if image_path and os.path.exists(image_path):
try:
img = Image(image_path, width=16*cm, height=9*cm)
img.hAlign = 'CENTER'
story.append(Spacer(1, 12))
story.append(img)
if caption:
image_counter += 1
story.append(Paragraph(f"图 {image_counter}: {caption}", caption_style))
story.append(Spacer(1, 12))
except Exception as e:
print(f"Error adding image {image_path}: {e}")
# 生成PDF
doc.build(story)
print(f"PDF生成成功: {output_path}")
print(f"共插入 {image_counter} 张图片")