我就是这样制作VI——设计与程序间不对称的harmony
从两张 PNG 出发,用 Python 自动化生成完整品牌视觉识别系统的完整记录。
一、什么是 VI?为什么要做?
VI(Visual Identity,视觉识别系统)是品牌对外沟通的「视觉语言规范」。 它回答一个核心问题:这个品牌在任何地方出现,应该长什么样子?
一套完整的 VI 套件至少包含:
| 类别 | 内容 |
|---|---|
| Logo 本体 | 原始透明底版、各色底版本 |
| Logo 变体 | 水平、垂直、方形、圆形 |
| 色票 | HEX / RGB / CMYK 规格 |
| 字型规范 | 主副字型、字级建议 |
| 使用规范 | 保留空间、禁止行为 |
| 应用品范例 | 名片、信头、社群头像 |
没有 VI,每次设计师、工程师、营销人员「自由发挥」,品牌就逐渐变形。 有了 VI,一个资料夹就能让任何人做出一致的品牌表现。
二、起点:两张 PNG
本次的原始素材只有两张 PNG:

两张图都是 Ascentek 的品牌 logo,内容相同但尺寸略有差异(一张是 16:9 展示版,另一张是较紧凑的版本)。
Logo 组成分析:
- 左侧:纸飞机 / A字形箭头符号,由两个三角形组成
- 主三角:Teal 色(
#03dcd0) - 深色三角:近黑色(
#181c20),制造立体/深度感
- 主三角:Teal 色(
- 右侧:「Ascentek」品牌名称,深色无衬线字型
- 背景:透明(RGBA)
这两个信息就是整套 VI 的根基:形状 + 颜色。
三、品牌元素提取
3.1 色票提取
不靠肉眼猜色,用程序直接从像素读取主色:
def get_dominant_colors(img, k=3):
# 过滤透明像素,只分析有内容的部分
pixels = [px[:3] for px in img.getdata() if px[3] > 0]
# 用 Pillow 的 Adaptive Palette 聚类
small = Image.new('RGB', (len(pixels), 1))
small.putdata(pixels)
pal = small.convert('P', palette=Image.ADAPTIVE, colors=k)
return pal.getpalette()[:k*3]提取结果:
| 角色 | HEX | RGB | CMYK(参考) |
|---|---|---|---|
| Primary | #03dcd0 | 3, 220, 208 | C99 M0 Y5 K14 |
| Secondary | #204b4c | 32, 75, 76 | C58 M1 Y0 K70 |
| Dark / Text | #181c20 | 24, 28, 32 | C25 M12 Y0 K88 |
3.2 Icon 边界侦测
Logo 是「符号 + 文字」的组合图,要做方形/圆形容器版本,必须把符号部分单独截出来。
挑战: 不能手动量像素,要让程序自动找出「符号在哪里结束、文字从哪里开始」。
初始思路:找第一个空白栏(column gap)
# 错误版本 — 会在符号内部的小间隙就停止
for x in range(width):
if not has_opaque_pixels(column[x]):
return x # 太早停了!这个方法的问题:Ascentek 的 logo 符号由两个分开的三角形组成,它们之间有小间隙。程序在这个内部间隙就停下来,结果只截到 teal 三角,深色三角被排除在外:
[teal △] [gap] [dark △] [ 大间距 ] [Ascentek 文字]
↑
这里被误判为 icon 结尾正确思路:找最宽的间距
icon 和文字之间的间距,一定比 icon 内部任何细缝都宽。 所以扫描所有 gap,取最宽的那个:
def find_icon_right(img):
col_has = [any_opaque_pixel_in_column(x) for x in range(width)]
gaps = []
for each gap in col_has:
gaps.append((gap_start_x, gap_width))
return max(gaps, key=width)[start_x]结果:边界从 x=158(只有 teal)修正到 x=214(完整符号),深色三角成功纳入。
四、工具选择
| 工具 | 用途 | 选择原因 |
|---|---|---|
| Python 3 | 脚本语言 | 跨平台、生态丰富 |
| Pillow(PIL) | 图像处理核心 | 纯 Python、无需 numpy、处理 RGBA 完整支持 |
| Montserrat | 品牌字型 | 原 Logo 字型风格、SIL 授权可商用 |
为什么不用 Photoshop / Figma?
- 手动操作无法重现(换 logo 就要全部重做)
- 脚本化后只需替换来源图,重跑一次就更新全部 28 个文件
- 程序码即文件:流程逻辑清楚记录在脚本里
五、核心技术:颜色适配
5.1 深色底适配(Dark Background Adaptation)
问题: Logo 上有深色(#181c20)的三角形和文字。把这个 Logo 直接放在深色底上,深色元素就消失不见了。
正确做法: 像素级判断 — 只把「接近黑色」的像素改成白色,teal 部分原封不动:
def adapt_dark(img):
data = list(img.getdata())
out = []
for r, g, b, a in data:
if a < 10:
out.append((0, 0, 0, 0))
elif r < 80 and g < 80 and b < 80:
out.append((255, 255, 255, a))
else:
out.append((r, g, b, a))
...5.2 单色剪影(Monochrome)
def silhouette(img, color_rgb):
alpha = img.split()[3]
base = Image.new('RGBA', img.size, color_rgb + (255,))
base.putalpha(alpha)
return base5.3 Circle Primary 的陷阱
先把 icon 转成白色剪影,再放在 teal 底:
icon_white = silhouette(icon, C_WHITE)
circ = on_canvas(icon_white, C_PRIMARY)六、Logo 变体生成逻辑
6.1 水平版(Horizontal)
Logo 本身就是水平构图,所以直接加底色就是水平版,不需要重新排版。


6.2 垂直版(Vertical)
需要截出纯符号(icon),重新用 Pillow render 文字后垂直组合。
6.3 方形 / 圆形容器
符号放进正方形容器,加上 15% padding;圆形版建立圆形遮罩套用。
七、应用品设计
7.1 名片(Business Card)
规格:3.5×2 吋 @ 300 dpi = 1050×600 px,双面。


名片是生出来了,但规格大小与 layout 这种事情就很主观了,因人而异就不多说了。
7.2 信头(Letterhead)
规格:A4 @ 300 dpi = 2480×3508 px。Header 内的 Logo 需使用深色适配版(adapt_dark)。
八、与 AI 协作过程中踩到的坑
坑 1:重影(Ghost Text)
解法: 不要在有文字的 logo 上再加文字。
坑 2:深色底 Logo 看不见
解法: 逐像素判断,将深色像素转白,保留 teal 不动(adapt_dark 函数)。
坑 3:Icon 截切不完整
解法: 改成找「最宽的 gap」,icon 和文字之间的间距一定比 icon 内部的缝还宽。
坑 4:Circle Primary 隐形
解法: 圆形主色版必须先把 icon 转成白色剪影(silhouette),再放在 teal 底。
坑 5:美学这种事情,是很难绝对判断的
见仁见智,这些就留待自身判断了。个人对于生成的这张名片觉得相对 LOGO 是大了一点就是了。
九、最终输出结构
VI-ClaudeVersion/
├── logo/ # 所有 Logo 变体(PNG + SVG)
├── applications/ # 应用品范例
├── palette.txt
├── VI_GUIDELINES.md
└── generate_vi.py十、这套做法可以复用在哪里?
修改 generate_vi.py 开头两行即可移植到新品牌:
LOGO_SRC = '你的新logo.png'
BRAND = '你的品牌名'执行 python generate_vi.py,全套 28 个文件一次生成完毕。
十一、核心思维总结
做 VI 的本质不是「画好看的图」,而是制定规则并让它可以被执行。
- 不要手工操作可以自动化的事
- 从像素看真相
- 把设计决策写成函数
- 脚本即文件
- 一键可重现
最好的 VI 系统,是一个不需要原作者在场也能被任何人正确使用的系统。
彩蛋: 其实原始的 LOGO 也是 AI 跑了几张之后老板挑出来的⋯⋯