180 lines
4.9 KiB
Python
180 lines
4.9 KiB
Python
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("可视化大屏模板系统<br/>软件说明书", title_style)
|
|
story.append(Spacer(1, 100))
|
|
story.append(cover_title)
|
|
story.append(Spacer(1, 30))
|
|
|
|
# 版本信息
|
|
cover_info = Paragraph("<b>版本号:V1.0</b><br/>开发完成日期: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('<b>', '').replace('</b>', '')
|
|
story.append(Paragraph(text, h1_style))
|
|
elif block_type == 'h3':
|
|
text = block.get('text', '').replace('<b>', '').replace('</b>', '')
|
|
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} 张图片")
|