A5 硬币清单 PDF 生成器 是做什么的?
使用时机
- 用户想要一份可打印的硬币收藏清单
- 用户提到 A5、Filofax、活页夹或用于硬币的规划页
- 用户想要将 Numista 导出数据与系列主清单进行交叉引用
- 用户正在对先前生成的硬币清单 PDF 进行迭代
页面设置
from reportlab.lib.pagesizes import A5
PAGE_W, PAGE_H = A5 # 148mm x 210mm (419.53 x 595.28 pts)
LEFT_M = 18*mm # 更宽 — 为 Filofax 6 孔打孔留出空间
RIGHT_M = 6*mm
TOP_M = 9*mm
BOT_M = 8*mm
USABLE_W = PAGE_W - LEFT_M - RIGHT_M # ~124mm
6 孔定位导引
在每一页上绘制。Filofax A5 标准孔位(距顶边距离):
HOLE_POSITIONS_MM = [19, 51, 70, 140, 159, 191]
for h in HOLE_POSITIONS_MM:
y = PAGE_H - h*mm
c.setStrokeColor(HexColor("#CCCCCC"))
c.setLineWidth(0.25)
c.circle(4.5*mm, y, 2.2*mm, stroke=1, fill=0)
字体
使用 Carlito(与 Calibri 度量兼容,采用 SIL 开源字体许可)。在 Linux 上,通常位于:
/usr/share/fonts/truetype/crosextra/Carlito-Regular.ttf
/usr/share/fonts/truetype/crosextra/Carlito-Bold.ttf
/usr/share/fonts/truetype/crosextra/Carlito-Italic.ttf
在 Windows 或 macOS 上,从 Google Fonts 下载 Carlito 并指向相应文件。
注册所有三个变体。切勿回退到 Helvetica:下面的布局是为 Calibri 风格的度量调整的。
排版规则(硬性约束)
| 元素 | 字体 | 大小 | 备注 |
|---|---|---|---|
| 封面标题 | Carlito-Bold | 20pt | 黑色横条中居中显示 |
| 封面副标题 | Carlito-Bold | 16pt | 标题下方 |
| 章节标题 | Carlito-Bold | 8.5-9pt | 黑色横条中白色文字 |
| 列标题 | Carlito-Bold | 7.5pt | 灰色,位于分隔线上方 |
| 正文 — 所有列 | Carlito / Carlito-Bold | 11pt | 名称、年代、当前状态列统一大小 |
| 已收集详细行 | Carlito-Italic | 8.5pt | 灰色,位于已收集行下方 |
| 页脚 | Carlito | 6pt | 页码 + 清单名称 |
| 面值列 | Carlito | 9pt | 右对齐,缩写形式(5Y、10Y、1J) |
关键:保持“名称”、“年代”和“当前状态”列使用相同的字体大小(11pt)。 混合大小在打印页面上会显得不专业。
行布局
ROW_H = 16-18 # pts — 行之间留出充足间距
SEC_H = 17 # 章节标题栏高度
COL_H = 13 # 列标题高度
COLLECTED_EXTRA = 11 # 已收集行详情行额外高度
- 在每行底部绘制一条细分隔线(0.2pt, #DDDDDD)
- 交替行背景:每隔一行使用 #EBEBEB 填充
- 已收集行:加粗文本 + 复选框中的勾选标记
列位置(从 LEFT_M 开始)
COL_CK = 0 # 复选框
COL_YR = 11 # 年份
COL_NM = 36 # 硬币名称(主列)
# 右侧列——向右推以避免与年代文本重叠
COL_ERA = 84*mm # 时代标记(B/P/N)或面值
COL_NOW = 89*mm # 当前状态 / 辅助信息
关键教训:类似“300 BCE-1279”的年代/日期字符串在 11pt 下宽度约为 28mm。时代标记和“当前状态”列必须从 84mm 后开始,以避免重叠。 这是多次迭代修复的结果。
灰度设计(强制)
专为灰度激光打印机设计。绝不要依赖颜色传达含义。
| 视觉元素 | 灰度方法 |
|---|---|
| 已收集行高亮 | 斜线填充(非颜色填充) |
| 章节标题 | 黑色实心条上的白色文字 |
| 交替行 | #EBEBEB 与白色 |
| 时代指示符 | 文本字母(B/P/N),非彩色圆点 |
| 已收集铸币厂标记 | 粗体与常规字重(非颜色) |
| 复选框 | 用线条绘制勾选标记,非 Unicode |
斜线填充实现:
def hatch(c, x, y, w, h):
c.saveState()
p = c.beginPath(); p.rect(x, y, w, h)
c.clipPath(p, stroke=0)
c.setStrokeColor(HexColor("#CCCCCC"))
c.setLineWidth(0.35)
for i in range(-int(h), int(w+h), 5):
c.line(x+i, y, x+i+h, y+h)
c.restoreState()
勾选标记(非 X,非 Unicode):
c.setStrokeColor(BLK); c.setLineWidth(1.2)
cx = LEFT_M + COL_CK + 1; cy = ty - 1
c.line(cx+2, cy+4, cx+4, cy+1.5)
c.line(cx+4, cy+1.5, cx+8, cy+7.5)
页面流(连续)
切勿为每个章节单独占用页面。 章节连续排列。小章节(3-5 项)必须与前一章节的尾部打包在同一页面上。
# 防止孤行:章节标题需要标题 + 列标题 + 至少 1 行
if item_type == 'section_header':
needed = h + COL_H + 2 + ROW_H + 4
if y - needed < BOT_M:
y = new_page(c)
封面页结构
- 黑色横条,包含标题(20pt)和副标题(16pt)
- 横条下方的副标题行(12pt,灰色)
- 水平分隔线
- 统计框(#EBEBEB 填充):“总计:X 已有:Y 缺少:Z”(14pt 粗体)
- 覆盖率百分比(11pt,灰色)
- 收藏者姓名(14pt 粗体)+ Numista 用户名(11pt)
- 图例部分(如适用)
- 系列摘要,计数右对齐
不要包含
- 单独的空白备注页(浪费纸张)
- 依赖颜色的元素
- Unicode 勾选标记或特殊字符(字体覆盖问题)
- 任何元素小于 7pt 的字体大小
- 文档中任何地方超过 1 页的空白区域
输出
将 PDF 保存到用户可以打开的位置(在 claude.ai 上:/mnt/user-data/outputs/ 并调用 present_files;在 Claude Code 中:工作文件夹)。在交付前使用 pdf2image 渲染页面进行可视化质量检查。