
.part .art-main pre{background:#1E1B16;color:#E8E3D8;border-radius:10px;padding:16px 18px;overflow-x:auto;font:13px/1.7 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;margin:14px 0}
.part .art-main pre code{background:none;color:inherit;padding:0;font-size:13px}
.part .art-main code:not(pre code){background:#F1EEE7;color:#B4531B;border-radius:5px;padding:2px 6px;font:0.92em ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.part .art-main p code{white-space:nowrap}
凌晨一点,我盯着刚出炉的文章封面:背景色块规整,版式没问题,唯独标题那行中文,成了一排整整齐齐的方框。
PIL 没抛异常,日志全绿,字体文件路径肉眼查了三遍都对。程序没报错就等于渲染成功?恰恰相反,它失败了还笑嘻嘻地给你画方框。
这就是没有设计师、还要求 65 个工具页全部有封面图标的人的日常——静默失败:程序错了却不吭声,比崩溃难抓十倍。
被坑惨了之后我认了一件事:没有设计师,也不会有人来接盘你的设计债。图标必须从一开始就能被代码管理、被机器验证。
上一篇说过工作站出图:单张质量确实顶,色彩、质感、构图都能打。硬伤也摆在那——7 分钟才出 9 张,同一条 prompt 跑两遍,风格就开始漂。
PIL 这边呢?65 套「封面 + 图标」分钟级跑完,跑一百遍结果一模一样。
画质输了怎么办?说人话:用户分不清 4K 精修和几何色块的差距,但一眼就能看出这 65 个页面是不是“同一个人做的”。
一致性:65 个图标长得像一家公司出的,而不是 65 家——这是 PIL 的躺赚项,工作站永远给不了。
所以我的分工是:工作站出关键位(首页、系列头图),PIL 承包全部长尾页面。拿精装修的方式去盖安置房,不叫勤奋,叫突击套利式的资源错配。
先解决“65 个图标该长什么样”这个审美黑洞。我的做法是把配色从审美问题降维成映射问题。
调色板体系:四个色系写死在代码里,分类到颜色一一对应,谁也不许自由发挥。
<p>PALETTE = {
"dev": ("#0F172A", "#38BDF8"), # 深底 + 亮蓝
"growth": ("#1C1917", "#FBBF24"), # 炭黑 + 琥珀
"design": ("#111827", "#F472B6"), # 墨底 + 粉
"tools": ("#0B1E12", "#4ADE80"), # 深绿底 + 荧光绿
}
颜色能当导航用吗?能,前提是你别搞出 65 种颜色。用户刷过几篇之后,看见蓝的就知道是开发类,看见绿的就是工具——这是白送的信息维度。
每个色系只有两个 token:底色铺场,强调色画符号、压标题下划线。朴素,但成系列。
字体是整条产线最容易翻车的环节,两个坑摞在一起:版权,和缺字。
随手从系统里薅一个商业字体打包进项目,等于给代码库埋雷。wqy-zenhei(文泉驿正黑):开源免费、可随项目分发、CJK 覆盖完整,PIL 渲染中文的兜底答案。
from PIL import ImageFont
font = ImageFont.truetype("wqy-zenhei.ttc", 42)
为什么不直接用系统默认字体?因为服务器上根本不存在“默认中文字体”这回事,Linux 容器里一薅一个空。
还有个细节:标题里混进生僻字时,wqy-zenhei 一样直接画方框、不报错。字体选对只解决一半问题,另一半交给第六节。
封面和图标尺寸不同、用途不同,但我不写两套渲染逻辑。
双产出:同一份布局参数(底色、强调色、标题、符号),按 800x450 和 180x180 各画一遍,谁也不欠谁。
为什么不写两套逻辑?因为两套逻辑就是两倍的翻车点,改一次文案要同步改两处,早晚漏。
取舍放在数据层,不放代码层:LAYOUT["icon"] 只保留符号加极短标题,LAYOUT["cover"] 放完整标题和系列名,同一个 render(spec, size) 吃进去。
改一个工具名?动一行配置,重跑,65 套图秒级全部更新。这种确定性才是量产该有的样子。
这次最想写出来的教训:渲染成没成功,不能靠肉眼。
人眼检查 65 张图行不行?行,但第三轮之后你就会开始瞎。像素级验证:不信日志,信像素——裁出标题区域,数深色像素,低于阈值直接判失败。
def title_rendered_ok(img, box, min_dark=80):
region = img.crop(box).convert("L")
dark = sum(1 for p in region.getdata() if p < 96)
return dark > min_dark # 方框描边太稀,空文本趋近于零
这 20 行能同时抓住几种翻车:字形缺失变方框(描边像素远低于汉字笔画密度)、标题画偏出界、文字色和背景色撞了。字体文件压根没找到时 PIL 会抛异常,那个反而好抓。
生成脚本跑完自动过一遍,任何一张不过就 fail 掉整个构建。别赌运气,运气在 CI 面前一文不值。
产线最后一道工序是体积:PIL 直出的 PNG 单张几十 KB,65 套加起来不小。上线前我统一丢给本站的 图片压缩 过一道,本地跑不上传,批量拖进去一分钟收工——和这条 PIL 产线一个脾气:快、确定、不废话。
1. PIL 画的图这么朴素,会不会拉低点击率?
点击率吃的是对比度和信息清晰度,不是装饰密度。65 个页面视觉成系列,辨识度反而是加分项。
2. 用 AI 生图批量跑全部不就完了?
中文文字渲染不可靠、风格会漂、不可复现——改一个标题就得重抽卡,这在维护视角下是负资产。
3. 像素级验证是不是过度工程?
20 行代码换 65 张图的自动质检,是整个方案里性价比最高的一段。过度工程是不写它。
评论列表 (0条)