/

用 Python Pillow 做 App 图标:抠图、羽化与跨端尺寸输出
手上只有一张 1024×1024 的 3D logo(奶白底),要产出:鸿蒙分层图标的透明前景 + 一整套 Android 方形 PNG。没有设计软件、没装 ImageMagick,只有 Python。这篇讲怎么用 Pillow 把这事干干净。
一、先看手里有什么栅格化工具
command -v magick convert inkscape rsvg-convert # → 只有个 convert
注意:Windows 自带的 convert 是磁盘格式转换工具,不是 ImageMagick,别被骗了。再查:
node在,但没装sharppython在,Pillow在,但没cairosvg
结论:不折腾装依赖,直接用 Pillow 处理位图最省事。SVG 路线(设计 SVG 再栅格化)这台机器上反而走不通。
二、抠图:floodfill 比颜色阈值靠谱
要把工具箱从奶白底抠成透明。两种思路:
❌ 颜色阈值(会误伤)
「离背景色越近越透明」听着简单,但 logo 里有白色笑脸、白色时钟/锁图标、APK 白字——这些白色和奶白底色差很小,阈值法会把它们一起抠掉,主体就破了。
✅ 四角 floodfill(只抠「连通的背景」)
从四个角做漫水填充,只有和角落连通的奶白区域被标记为背景;被主体包围的白色元素因为不连通,自然保留:
from PIL import Image, ImageDraw, ImageFilter
im = Image.open(src).convert('RGB'); w, h = im.size
work = im.copy(); sent = (255, 0, 255) # 哨兵色
for seed in [(1,1), (w-2,1), (1,h-2), (w-2,h-2)]:
ImageDraw.floodfill(work, seed, sent, thresh=46)
# 被填成哨兵色的 = 背景 → 透明,其余 = 不透明
px = work.load()
alpha = Image.new('L', (w, h), 0); ap = alpha.load()
for y in range(h):
for x in range(w):
if px[x, y] != sent:
ap[x, y] = 255
附带好处:工具箱底部的柔和投影颜色和奶白差得够远,floodfill 到不了,于是被保留下来——只要背景层也用同一奶白色,投影就和背景无缝衔接,3D 落地感还在。
三、边缘羽化:一行高斯模糊
floodfill 的边界是硬的(非 0 即 255),直接用会有锯齿。给 alpha 通道来一发轻微高斯模糊就平滑了:
alpha = alpha.filter(ImageFilter.GaussianBlur(0.6))
cut = im.convert('RGBA'); cut.putalpha(alpha)
sub = cut.crop(cut.getbbox()) # 裁到主体实际边界
四、缩放居中:Lanczos + 安全区比例
把主体按目标占比缩放后居中贴到透明画布。下采样统一用 Lanczos(细节最锐):
SZ = 1024
fill = 0.86 # 主体最大边占画布比例
scale = int(SZ * fill) / max(sub.size)
nw, nh = int(sub.width * scale), int(sub.height * scale)
sub = sub.resize((nw, nh), Image.LANCZOS)
fg = Image.new('RGBA', (SZ, SZ), (0, 0, 0, 0))
fg.paste(sub, ((SZ - nw)//2, (SZ - nh)//2), sub)
fill是个好用的旋钮:鸿蒙分层前景调小一点留安全区,Android 方图可以调大到几乎贴边。
五、一次导出跨端全套尺寸
Android 启动器/商店要一串尺寸,循环 resize 即可:
for s in [1024, 512, 192, 144, 96, 72, 48]:
img.resize((s, s), Image.LANCZOS).save(f'icons/icon_{s}.png', 'PNG')
对应关系:1024 主图/商店、512 Play Store、192~48 对应 xxxhdpi → mdpi。
六、一个低级但耽误时间的坑:Windows 上的 /tmp
脚本里随手写了 im.save('/tmp/out.png'),报:
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/out.png'
因为这是 Windows 原生 Python,/tmp 不是合法路径(哪怕你在 Git Bash 里跑)。改成真实路径(项目内临时目录或 os.environ['TEMP'])即可。「在 bash 里跑 Windows 解释器」时,路径要按 Windows 的来。
小结
没有 ImageMagick/SVG 工具链时,Pillow 处理位图完全够用。
抠纯色底用 四角 floodfill,别用颜色阈值——保住主体里的白色元素。
alpha 高斯模糊 0.6 去锯齿;下采样统一 Lanczos。
fill比例一个旋钮适配多端;尺寸全套循环导出。Windows 原生 Python 不认
/tmp,路径按平台来。
评论区