Files
xianyan/tools/replace_platform_icons.py
Developer 74b615afc4 资源2
2026-06-04 00:30:05 +08:00

213 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""
Created: 2026-06-02
Updated: 2026-06-02
Name: replace_platform_icons.py
Desc: Replace app icons for iOS, macOS, Android, OHOS platforms
using processed icons from assets/templates/resized folder.
Original icons are backed up before replacement.
"""
import os
import shutil
from PIL import Image
BASE = '/Users/wushu/Documents/trae_projects/project/xianyan'
SOURCE_DIR = os.path.join(BASE, 'assets/templates/resized')
BACKUP_ROOT = os.path.join(BASE, 'assets/templates/backup_platform_icons')
def get_source_icon(size):
"""Get source icon path for a given pixel size."""
filename = f'icon_{size}x{size}.png'
path = os.path.join(SOURCE_DIR, filename)
if os.path.exists(path):
return path
print(f" WARNING: Source icon {filename} not found!")
return None
def backup_and_replace(target_path, source_path):
"""Backup original icon and replace with new one."""
if not os.path.exists(target_path):
print(f" SKIP: Target not found: {target_path}")
return False
# Create backup path maintaining directory structure
rel_path = os.path.relpath(target_path, BASE)
backup_path = os.path.join(BACKUP_ROOT, rel_path)
backup_dir = os.path.dirname(backup_path)
os.makedirs(backup_dir, exist_ok=True)
# Backup if not already backed up
if not os.path.exists(backup_path):
shutil.copy2(target_path, backup_path)
# Copy source to target
shutil.copy2(source_path, target_path)
# Verify
new_img = Image.open(target_path)
src_img = Image.open(source_path)
if new_img.size == src_img.size:
return True
else:
print(f" ERROR: Size mismatch after copy! {new_img.size} vs {src_img.size}")
return False
def replace_ios_runner():
"""Replace iOS Runner app icons."""
print("\n=== iOS Runner AppIcon ===")
ios_dir = os.path.join(BASE, 'ios/Runner/Assets.xcassets/AppIcon.appiconset')
# Mapping: target_filename -> source_pixel_size
mapping = {
'Icon-App-1024x1024@1x.png': 1024,
'Icon-App-20x20@1x.png': 20,
'Icon-App-20x20@2x.png': 40,
'Icon-App-20x20@3x.png': 60,
'Icon-App-29x29@1x.png': 29,
'Icon-App-29x29@2x.png': 58,
'Icon-App-29x29@3x.png': 87,
'Icon-App-40x40@1x.png': 40,
'Icon-App-40x40@2x.png': 80,
'Icon-App-40x40@3x.png': 120,
'Icon-App-60x60@2x.png': 120,
'Icon-App-60x60@3x.png': 180,
'Icon-App-76x76@1x.png': 76,
'Icon-App-76x76@2x.png': 152,
'Icon-App-83.5x83.5@2x.png': 167,
}
count = 0
for target_name, size in mapping.items():
source = get_source_icon(size)
if source:
target = os.path.join(ios_dir, target_name)
if backup_and_replace(target, source):
print(f" OK: {target_name} <- icon_{size}x{size}.png")
count += 1
print(f" Replaced: {count}/{len(mapping)}")
return count
def replace_ios_widget():
"""Replace iOS Widget app icon."""
print("\n=== iOS Widget AppIcon ===")
widget_dir = os.path.join(BASE, 'ios/XianyanWidget/Assets.xcassets/AppIcon.appiconset')
mapping = {
'Icon-App-1024x1024.png': 1024,
}
count = 0
for target_name, size in mapping.items():
source = get_source_icon(size)
if source:
target = os.path.join(widget_dir, target_name)
if backup_and_replace(target, source):
print(f" OK: {target_name} <- icon_{size}x{size}.png")
count += 1
print(f" Replaced: {count}/{len(mapping)}")
return count
def replace_macos():
"""Replace macOS app icons."""
print("\n=== macOS AppIcon ===")
macos_dir = os.path.join(BASE, 'macos/Runner/Assets.xcassets/AppIcon.appiconset')
mapping = {
'app_icon_16.png': 16,
'app_icon_32.png': 32,
'app_icon_64.png': 64,
'app_icon_128.png': 128,
'app_icon_256.png': 256,
'app_icon_512.png': 512,
'app_icon_1024.png': 1024,
}
count = 0
for target_name, size in mapping.items():
source = get_source_icon(size)
if source:
target = os.path.join(macos_dir, target_name)
if backup_and_replace(target, source):
print(f" OK: {target_name} <- icon_{size}x{size}.png")
count += 1
print(f" Replaced: {count}/{len(mapping)}")
return count
def replace_android():
"""Replace Android launcher icons."""
print("\n=== Android mipmap ===")
res_dir = os.path.join(BASE, 'android/app/src/main/res')
# Android density -> pixel size
mapping = {
'mipmap-mdpi': 48,
'mipmap-hdpi': 72,
'mipmap-xhdpi': 96,
'mipmap-xxhdpi': 144,
'mipmap-xxxhdpi': 192,
}
count = 0
for density, size in mapping.items():
source = get_source_icon(size)
if source:
target = os.path.join(res_dir, density, 'ic_launcher.png')
if backup_and_replace(target, source):
print(f" OK: {density}/ic_launcher.png <- icon_{size}x{size}.png")
count += 1
print(f" Replaced: {count}/{len(mapping)}")
return count
def replace_ohos():
"""Replace OHOS (HarmonyOS) app icons."""
print("\n=== OHOS icons ===")
# All OHOS icons are 1024x1024
paths = [
'ohos/AppScope/resources/base/media/app_icon.png',
'ohos/AppScope/resources/base/media/foreground_icon.png',
'ohos/entry/src/main/resources/base/media/icon.png',
'ohos/entry/src/main/resources/base/media/foreground_icon.png',
]
source = get_source_icon(1024)
count = 0
if source:
for rel_path in paths:
target = os.path.join(BASE, rel_path)
if backup_and_replace(target, source):
print(f" OK: {rel_path} <- icon_1024x1024.png")
count += 1
print(f" Replaced: {count}/{len(paths)}")
return count
def main():
os.makedirs(BACKUP_ROOT, exist_ok=True)
print(f"Source: {SOURCE_DIR}")
print(f"Backup: {BACKUP_ROOT}")
total = 0
total += replace_ios_runner()
total += replace_ios_widget()
total += replace_macos()
total += replace_android()
total += replace_ohos()
print(f"\n{'='*60}")
print(f"Total icons replaced: {total}")
print(f"Backup location: {BACKUP_ROOT}")
print("Done!")
if __name__ == '__main__':
main()