侧边栏壁纸
博主头像
离开的兔子

行动起来,活在当下

  • 累计撰写 8 篇文章
  • 累计创建 1 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

用Pillow做App图标-抠图超采样与跨端尺寸

Administrator
2026-06-25 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

/

04-cover.png

用 Python Pillow 做 App 图标:抠图、羽化与跨端尺寸输出

手上只有一张 1024×1024 的 3D logo(奶白底),要产出:鸿蒙分层图标的透明前景 + 一整套 Android 方形 PNG。没有设计软件、没装 ImageMagick,只有 Python。这篇讲怎么用 Pillow 把这事干干净。

一、先看手里有什么栅格化工具

command -v magick convert inkscape rsvg-convert   # → 只有个 convert

注意:Windows 自带的 convert磁盘格式转换工具,不是 ImageMagick,别被骗了。再查:

  • node 在,但没装 sharp

  • python 在,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,路径按平台来。

0

评论区