126 lines
5.8 KiB
Python
126 lines
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
每日英语听力材料 PDF 生成脚本(学习用)
|
||
|
||
用途:把一段英语学习材料(英文原文 + 逐句音标 + 中文翻译 + 生词表 + 听力技巧)
|
||
生成一份排版美观、可离线收藏的 PDF 文档。
|
||
|
||
依赖:
|
||
pip install reportlab
|
||
系统字体(Linux):
|
||
- DejaVu Sans:覆盖英文与 IPA 音标字符
|
||
- 文鼎 UMingCN(uming.ttc):覆盖中文字符(宋体风格)
|
||
|
||
关键知识点:
|
||
1. reportlab 的 Platypus(SimpleDocTemplate + Paragraph + Table)负责自动排版、分页;
|
||
2. reportlab 内置字体不支持中文/IPA,需用 TTFont 注册系统 TTF/TTC 字体;
|
||
3. 同一段落里混排中文与英文/IPA 时,用 <font name="..."> 标签切换字体;
|
||
4. 注意:reportlab 不支持 CFF 轮廓的字体(如 NotoSansCJK.otf),只能用 TrueType;
|
||
5. .ttc 集合字体通过 subfontIndex 选择子字体。
|
||
"""
|
||
import html as h
|
||
|
||
from reportlab.lib import colors
|
||
from reportlab.lib.pagesizes import A4
|
||
from reportlab.lib.styles import ParagraphStyle
|
||
from reportlab.lib.units import mm
|
||
from reportlab.pdfbase import pdfmetrics
|
||
from reportlab.pdfbase.ttfonts import TTFont
|
||
from reportlab.platypus import (Paragraph, SimpleDocTemplate, Spacer,
|
||
Table, TableStyle)
|
||
|
||
# ------------------------- 1. 注册字体 -------------------------
|
||
BASE = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
|
||
BASE_BOLD = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'
|
||
CJK = '/usr/share/fonts/truetype/arphic/uming.ttc'
|
||
|
||
pdfmetrics.registerFont(TTFont('Base', BASE))
|
||
pdfmetrics.registerFont(TTFont('Base-Bold', BASE_BOLD))
|
||
pdfmetrics.registerFont(TTFont('CJK', CJK, subfontIndex=0)) # UMingCN
|
||
|
||
|
||
def esc(s: str) -> str:
|
||
"""转义 < > & 等,避免 Paragraph 把内容当成 XML 标签。"""
|
||
return h.escape(s, quote=False)
|
||
|
||
|
||
# ------------------------- 2. 定义样式 -------------------------
|
||
title = ParagraphStyle('title', fontName='Base-Bold', fontSize=18, leading=24,
|
||
textColor=colors.HexColor('#B22222'), alignment=1, spaceAfter=6)
|
||
meta = ParagraphStyle('meta', fontName='CJK', fontSize=10, leading=14,
|
||
textColor=colors.HexColor('#666666'), alignment=1, spaceAfter=10)
|
||
h1 = ParagraphStyle('h1', fontName='CJK', fontSize=13, leading=18,
|
||
textColor=colors.HexColor('#8B0000'), spaceBefore=10, spaceAfter=6)
|
||
en = ParagraphStyle('en', fontName='Base', fontSize=11.5, leading=17, spaceBefore=4)
|
||
ipa = ParagraphStyle('ipa', fontName='Base', fontSize=9.5, leading=14,
|
||
textColor=colors.HexColor('#555555'), leftIndent=6, spaceAfter=2)
|
||
note = ParagraphStyle('note', fontName='CJK', fontSize=9.5, leading=14,
|
||
textColor=colors.HexColor('#2F5D8A'), leftIndent=12, spaceAfter=4)
|
||
zh = ParagraphStyle('zh', fontName='CJK', fontSize=11, leading=18, spaceBefore=3)
|
||
|
||
|
||
def sen(num: str, text: str):
|
||
return Paragraph('<font name="Base-Bold">%s</font> %s' % (esc(num), esc(text)), en)
|
||
|
||
|
||
# ------------------------- 3. 准备内容数据 -------------------------
|
||
sentences = [
|
||
# (编号, 英文句子, 音标, 发音要点中文说明)
|
||
("1.", "Today is October 1st — China's National Day.",
|
||
"/təˈdeɪ ɪz oʊkˈtoʊbər fɜːrst | ˈtʃaɪnəz ˈnæʃənəl deɪ/",
|
||
"● 连读:October 1st 中 /r/ 与 /f/ 自然衔接。"),
|
||
("2.", "Streets are decorated with red flags, and cities glow with lanterns and flowers.",
|
||
"/striːts ər ˈdekəreɪtɪd wɪð red flægz | ənd ˈsɪtiz gloʊ wɪð ˈlæntərnz ənd ˈflaʊərz/",
|
||
"● 重读:decorated、glow 是画面词,加重读出画面感。"),
|
||
]
|
||
|
||
words = [
|
||
# (单词, 音标, 中文释义)
|
||
("decorate", "/ˈdekəreɪt/", "装饰"),
|
||
("glow", "/gloʊ/", "发光,焕发光彩"),
|
||
]
|
||
|
||
# ------------------------- 4. 组装文档 -------------------------
|
||
story = []
|
||
story.append(Paragraph('<font name="Base-Bold">Happy National Day!</font>'
|
||
'<font name="CJK">(国庆节快乐)</font>', title))
|
||
story.append(Paragraph('每日英语听力推送 · 示例材料 · 约1分钟朗读量', meta))
|
||
|
||
story.append(Paragraph('一、英文原文(逐句 + IPA 音标)', h1))
|
||
for num, text, ip, n in sentences:
|
||
story.append(sen(num, text))
|
||
story.append(Paragraph(esc(ip), ipa))
|
||
story.append(Paragraph(esc(n), note))
|
||
|
||
story.append(Paragraph('二、生词与短语', h1))
|
||
cell_en = ParagraphStyle('c1', fontName='Base', fontSize=10, leading=13)
|
||
cell_ipa = ParagraphStyle('c2', fontName='Base', fontSize=10, leading=13,
|
||
textColor=colors.HexColor('#555555'))
|
||
cell_zh = ParagraphStyle('c3', fontName='CJK', fontSize=10, leading=13)
|
||
head = ParagraphStyle('ch', fontName='CJK', fontSize=10, leading=13, textColor=colors.white)
|
||
data = [[Paragraph('单词/短语', head), Paragraph('音标', head), Paragraph('释义', head)]]
|
||
for w, ip, z in words:
|
||
data.append([Paragraph(esc(w), cell_en),
|
||
Paragraph(esc(ip), cell_ipa),
|
||
Paragraph(esc(z), cell_zh)])
|
||
tbl = Table(data, colWidths=[52*mm, 58*mm, 62*mm])
|
||
tbl.setStyle(TableStyle([
|
||
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#8B0000')),
|
||
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#F5F0E6')]),
|
||
('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor('#CCCCCC')),
|
||
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
||
('LEFTPADDING', (0, 0), (-1, -1), 5),
|
||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||
]))
|
||
story.append(tbl)
|
||
|
||
# ------------------------- 5. 写出 PDF -------------------------
|
||
doc = SimpleDocTemplate("每日英语听力_示例.pdf", pagesize=A4,
|
||
rightMargin=18*mm, leftMargin=18*mm,
|
||
topMargin=16*mm, bottomMargin=16*mm,
|
||
title="每日英语听力示例")
|
||
doc.build(story)
|
||
print("PDF generated OK")
|
||
#(注:内容由AI生成)
|