调整应用图标小黄鸭占比
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 8.7 KiB |
92
scripts/resize_duck_icon.py
Normal file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""缩小小黄鸭在图标中的占比,并重新生成所有 mipmap 资源。"""
|
||||
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
# 项目路径
|
||||
APP_RES = Path(__file__).parent.parent / "app" / "src" / "main" / "res"
|
||||
|
||||
# Android 标准密度对应比例
|
||||
DENSITIES = {
|
||||
"mipmap-xhdpi": 2, # 108 dp * 2 = 216 px
|
||||
"mipmap-xxhdpi": 3, # 108 dp * 3 = 324 px
|
||||
"mipmap-xxxhdpi": 4, # 108 dp * 4 = 432 px
|
||||
}
|
||||
|
||||
# 小黄鸭缩放比例(0.75 = 占原来 75%)
|
||||
DUCK_SCALE = 0.75
|
||||
|
||||
# 背景色取自 ic_launcher_background.xml
|
||||
BG_COLOR = (0x83, 0xD0, 0xF1, 0xFF)
|
||||
|
||||
|
||||
def make_rounded_mask(size: int, radius_ratio: float = 0.22) -> Image.Image:
|
||||
"""生成圆角矩形 mask(用于圆角方形图标)。"""
|
||||
mask = Image.new("L", (size, size), 0)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
radius = int(size * radius_ratio)
|
||||
draw.rounded_rectangle((0, 0, size, size), radius=radius, fill=255)
|
||||
return mask
|
||||
|
||||
|
||||
def make_circle_mask(size: int) -> Image.Image:
|
||||
"""生成圆形 mask(用于圆形图标)。"""
|
||||
mask = Image.new("L", (size, size), 0)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
draw.ellipse((0, 0, size, size), fill=255)
|
||||
return mask
|
||||
|
||||
|
||||
def compose_icon(foreground: Image.Image, size: int, mask: Image.Image) -> Image.Image:
|
||||
"""将前景合成到纯色背景上,并应用形状 mask。"""
|
||||
bg = Image.new("RGBA", (size, size), BG_COLOR)
|
||||
# 将前景缩放到当前密度尺寸
|
||||
fg = foreground.resize((size, size), Image.Resampling.LANCZOS)
|
||||
bg.alpha_composite(fg)
|
||||
# 应用形状 mask
|
||||
result = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||
result.paste(bg, (0, 0), mask)
|
||||
return result.convert("RGB")
|
||||
|
||||
|
||||
def main():
|
||||
# 读取最高分辨率前景图
|
||||
src_fg = Image.open(APP_RES / "mipmap-xxxhdpi" / "ic_launcher_foreground.webp").convert("RGBA")
|
||||
src_size = src_fg.size[0]
|
||||
|
||||
# 缩放鸭子内容,增加透明边距
|
||||
new_size = int(src_size * DUCK_SCALE)
|
||||
fg_resized = src_fg.resize((new_size, new_size), Image.Resampling.LANCZOS)
|
||||
|
||||
# 放置到原始尺寸透明画布中央
|
||||
foreground_scaled = Image.new("RGBA", (src_size, src_size), (0, 0, 0, 0))
|
||||
offset = (src_size - new_size) // 2
|
||||
foreground_scaled.paste(fg_resized, (offset, offset), fg_resized)
|
||||
|
||||
for folder, scale in DENSITIES.items():
|
||||
px = 108 * scale # 自适应图标前景标准尺寸
|
||||
folder_path = APP_RES / folder
|
||||
folder_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 生成新的前景 webp
|
||||
fg = foreground_scaled.resize((px, px), Image.Resampling.LANCZOS)
|
||||
fg.save(folder_path / "ic_launcher_foreground.webp", "WEBP", quality=95)
|
||||
|
||||
# 生成合成后的圆角方形和圆形 PNG
|
||||
icon_size = 48 * scale # 启动图标标准尺寸
|
||||
rounded_mask = make_rounded_mask(icon_size)
|
||||
circle_mask = make_circle_mask(icon_size)
|
||||
|
||||
compose_icon(fg, icon_size, rounded_mask).save(
|
||||
folder_path / "ic_launcher.png", "PNG"
|
||||
)
|
||||
compose_icon(fg, icon_size, circle_mask).save(
|
||||
folder_path / "ic_launcher_round.png", "PNG"
|
||||
)
|
||||
|
||||
print(f"Generated {folder}: {px}x{px} foreground, {icon_size}x{icon_size} icons")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||