3. 模板设计基础:画布、坐标、字体与背景
做证书模板,说白了就是在一张白纸上精确地摆放内容。我刚开始接触这个领域时,觉得不就是画个框、写几个字嘛,结果第一版做出来的证书,文字跑到了边框外面,背景图也拉伸得不成样子。嗯,后来我才明白,模板设计的核心就四个东西:画布概念、坐标系统、字体与颜色、背景图加载。今天咱们就把这几个基础打牢。
3.1 画布概念:你的数字工作台
画布(Canvas)就是你证书的虚拟纸张。在 Python 的 PIL/Pillow 库中,我们通过 Image.new() 来创建它。我个人习惯把画布想象成一块画板,所有元素都在这块板上定位。
from PIL import Image, ImageDraw, ImageFont
# 创建一张 A4 横向画布,背景白色
canvas_width = 2480 # 像素,约 300 DPI 下的 A4 宽
canvas_height = 1745 # 像素,约 300 DPI 下的 A4 高
canvas = Image.new('RGB', (canvas_width, canvas_height), 'white')
draw = ImageDraw.Draw(canvas)
画布尺寸的单位是像素。为什么是 2480×1745?因为标准 A4 纸是 210mm×297mm,横向时宽 297mm、高 210mm,按 300 DPI 换算:297/25.4×300 ≈ 3508,210/25.4×300 ≈ 2480。等等,我上面写的 2480×1745 是另一种常用尺寸——实际上很多证书模板用 1920×1350 或 2480×1745,取决于你的打印需求。我在项目中遇到过客户要求「必须 300 DPI 打印清晰」,那就老老实实按物理尺寸换算。
3.2 坐标系统:从左上角开始
PIL 的坐标系统很简单:原点 (0,0) 在画布左上角,x 轴向右增加,y 轴向下增加。这和数学课上学的坐标系不一样,你想想看,屏幕渲染都是这么干的。
| 位置 | 坐标 (x, y) | 说明 |
|---|---|---|
| 左上角 | (0, 0) | 原点 |
| 右上角 | (width, 0) | x 最大,y 为 0 |
| 左下角 | (0, height) | x 为 0,y 最大 |
| 右下角 | (width, height) | x 和 y 都最大 |
| 中心点 | (width/2, height/2) | 常用作对齐参考 |
举个例子,你想在画布正中央写一行字,那就先算出中心坐标,然后通过 textbbox 获取文字尺寸,再做偏移。
text = "荣誉证书"
font = ImageFont.truetype("simhei.ttf", 120)
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
center_x = canvas_width // 2
center_y = canvas_height // 2
# 让文字中心对齐画布中心
draw.text((center_x - text_width // 2, center_y - text_height // 2), text, fill='black', font=font)
textbbox 返回的是 (left, top, right, bottom),不是 (x, y, width, height)。我曾经在这里栽过跟头,直接用 right 和 bottom 当宽高用,结果文字全跑偏了。
3.3 字体与颜色设置
字体是证书的灵魂。一份正式的证书,字体选错了,档次瞬间掉一半。我个人习惯准备三套字体:
- 标题字体:粗壮、庄重,比如 SimHei(黑体)或 FZCuSong(方正粗宋),字号 80-120px。
- 正文字体:清晰易读,比如 SimSun(宋体)或 Microsoft YaHei(微软雅黑),字号 36-48px。
- 装饰字体:手写体或衬线体,用于姓名、日期等,比如 STXingkai(华文行楷),字号 48-72px。
颜色设置更直接,PIL 用 RGB 元组或十六进制字符串都行。
# 几种常用颜色
COLOR_GOLD = (212, 175, 55) # 金色,适合证书标题
COLOR_DARK_BLUE = (0, 51, 102) # 深蓝,适合正文
COLOR_BLACK = (0, 0, 0) # 纯黑
COLOR_GRAY = (128, 128, 128) # 灰色,用于辅助信息
draw.text((100, 100), "荣誉证书", fill=COLOR_GOLD, font=font_title)
draw.text((100, 300), "张三 同志", fill=COLOR_DARK_BLUE, font=font_name)
draw.text((100, 500), "编号:2025-001", fill=COLOR_GRAY, font=font_small)
3.4 背景图加载
纯白背景的证书太单调了。实际项目中,我们通常会用一张设计好的背景图(比如带边框、底纹、Logo 的图片),然后把文字叠加上去。
加载背景图用 Image.open(),然后 paste 到画布上。这里有个关键点:背景图尺寸必须和画布一致,否则需要缩放。
# 加载背景图
bg = Image.open("certificate_bg.png")
# 缩放到画布尺寸(如果尺寸不匹配)
bg = bg.resize((canvas_width, canvas_height), Image.LANCZOS)
# 粘贴到画布
canvas.paste(bg, (0, 0))
# 然后再在上面画文字
draw = ImageDraw.Draw(canvas)
draw.text((500, 800), "荣誉证书", fill=COLOR_GOLD, font=font_title)
如果背景图是 JPEG 格式,注意它没有透明通道。如果你需要背景图局部透明(比如让文字区域透出纯色底),那就用 PNG 格式,并在 paste 时指定 mask 参数。
# 带透明通道的 PNG 背景
bg_rgba = Image.open("certificate_bg.png").convert("RGBA")
canvas_rgba = Image.new('RGBA', (canvas_width, canvas_height), (255, 255, 255, 255))
canvas_rgba.paste(bg_rgba, (0, 0), bg_rgba) # 第三个参数是 mask
3.5 知识体系总览
下面这张图把本章的核心概念串起来了。你一看就明白:画布是基础,坐标是定位工具,字体和颜色是视觉元素,背景图是底层素材——四者配合,才能做出一个合格的证书模板。
3.6 综合示例:一个完整的模板骨架
把上面所有知识点揉在一起,就是一个可运行的模板骨架。你把这个跑通了,后面章节的批量生成就顺了。
from PIL import Image, ImageDraw, ImageFont
# 1. 创建画布
W, H = 2480, 1745
canvas = Image.new('RGB', (W, H), 'white')
draw = ImageDraw.Draw(canvas)
# 2. 加载背景图(如果有)
try:
bg = Image.open("bg.png").resize((W, H), Image.LANCZOS)
canvas.paste(bg, (0, 0))
draw = ImageDraw.Draw(canvas) # 重新获取 draw 对象
except FileNotFoundError:
pass # 没有背景图就用纯白
# 3. 加载字体
font_title = ImageFont.truetype("simhei.ttf", 120)
font_name = ImageFont.truetype("stxingkai.ttf", 80)
font_body = ImageFont.truetype("simsun.ttf", 48)
# 4. 定义颜色
GOLD = (212, 175, 55)
DARK_BLUE = (0, 51, 102)
GRAY = (128, 128, 128)
# 5. 绘制文字(居中)
title = "荣誉证书"
bbox = draw.textbbox((0, 0), title, font=font_title)
tw, th = bbox[2]-bbox[0], bbox[3]-bbox[1]
draw.text(((W-tw)//2, 200), title, fill=GOLD, font=font_title)
name = "张三"
bbox = draw.textbbox((0, 0), name, font=font_name)
nw, nh = bbox[2]-bbox[0], bbox[3]-bbox[1]
draw.text(((W-nw)//2, 500), name, fill=DARK_BLUE, font=font_name)
# 6. 保存模板
canvas.save("certificate_template.png")
print("模板已生成:certificate_template.png")
draw.line() 画出中心十字线,调试完再删掉。我早期做模板时全靠这个笨办法,后来才学会用 textbbox 精确计算。