feat: 更新鸿蒙应用配置与功能优化

- 添加鸿蒙分层图标配置和生成脚本
- 修复数据导出JSON解析问题
- 优化关于页面和团队信息展示
- 更新应用版本至1.4.1
- 清理代码警告和冗余文件
- 添加字体和二维码测试脚本
- 完善鸿蒙适配文档和指南
This commit is contained in:
Developer
2026-04-25 09:52:06 +08:00
parent 3c90407bb5
commit 4ec348b28e
63 changed files with 4538 additions and 1818 deletions

139
scripts/gen_hmos_icons.py Normal file
View File

@@ -0,0 +1,139 @@
"""
鸿蒙(HarmonyOS) 分层图标生成脚本
从源图标提取 foreground + background符合华为审核规范 1024x1024
"""
import os
import json
import math
from PIL import Image, ImageDraw
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ASSETS_ICONS = os.path.join(SCRIPT_DIR, "..", "assets", "icons")
OHOS_MEDIA = os.path.join(SCRIPT_DIR, "..", "ohos", "AppScope", "resources", "base", "media")
OHOS_ENTRY_MEDIA = os.path.join(SCRIPT_DIR, "..", "ohos", "entry", "src", "main", "resources", "base", "media")
SOURCE_ICON = os.path.join(ASSETS_ICONS, "icon_1024x1024.png")
OUTPUT_SIZE = 1024
def get_dominant_bg_color(img):
samples = [
(80, 80), (img.width - 81, 80),
(80, img.height - 81), (img.width - 81, img.height - 81),
(img.width // 2, 60), (img.width // 2, img.height - 61),
(60, img.height // 2), (img.width - 61, img.height // 2),
(150, 150), (img.width - 151, img.height - 151),
]
colors = []
for pos in samples:
px = img.getpixel(pos)
if len(px) >= 3:
colors.append((px[0], px[1], px[2]))
r_sum = sum(c[0] for c in colors)
g_sum = sum(c[1] for c in colors)
b_sum = sum(c[2] for c in colors)
n = len(colors)
return (r_sum // n, g_sum // n, b_sum // n)
def color_distance(c1, c2):
return math.sqrt(
(c1[0] - c2[0]) ** 2 +
(c1[1] - c2[1]) ** 2 +
(c1[2] - c2[2]) ** 2
)
def create_rounded_mask(size, radius):
mask = Image.new("L", (size, size), 0)
draw = ImageDraw.Draw(mask)
draw.rounded_rectangle([0, 0, size - 1, size - 1], radius=radius, fill=255)
return mask
def generate_background(img, output_path, bg_color):
bg = Image.new("RGB", (OUTPUT_SIZE, OUTPUT_SIZE), bg_color)
bg.save(output_path, "PNG")
print(f" background: {output_path} ({os.path.getsize(output_path) / 1024:.1f}KB)")
print(f" 颜色: RGB{bg_color}")
def generate_foreground(img, output_path, bg_color, tolerance=50):
from PIL import ImageChops
fg = img.convert("RGBA").resize((OUTPUT_SIZE, OUTPUT_SIZE), Image.LANCZOS)
pixels = fg.load()
width, height = fg.size
for y in range(height):
for x in range(width):
r, g, b, a = pixels[x, y]
dist = color_distance((r, g, b), bg_color)
if dist < tolerance and a > 200:
alpha = int(255 * (dist / tolerance))
pixels[x, y] = (r, g, b, alpha)
elif dist < tolerance * 0.5:
pixels[x, y] = (r, g, b, 0)
mask = create_rounded_mask(OUTPUT_SIZE, int(OUTPUT_SIZE * 0.22))
fg.putalpha(ImageChops.multiply(fg.split()[3], mask))
fg.save(output_path, "PNG")
print(f" foreground: {output_path} ({os.path.getsize(output_path) / 1024:.1f}KB)")
def generate_layered_json(output_dir, fg_name="foreground_icon.png", bg_name="background_icon.png"):
config = {
"layered-image": {
"foreground": f"$media:{fg_name.replace('.png', '')}",
"background": f"$media:{bg_name.replace('.png', '')}"
}
}
json_path = os.path.join(output_dir, "layered_image.json")
with open(json_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=2, ensure_ascii=False)
print(f" layered_image.json: {json_path}")
return json_path
def main():
if not os.path.exists(SOURCE_ICON):
print(f"错误: 源文件不存在 {SOURCE_ICON}")
return
print(f"源图标: {SOURCE_ICON}")
img = Image.open(SOURCE_ICON).convert("RGBA")
print(f" 尺寸: {img.size}")
bg_color = get_dominant_bg_color(img)
print(f" 背景色采样: RGB{bg_color}")
os.makedirs(OHOS_MEDIA, exist_ok=True)
os.makedirs(OHOS_ENTRY_MEDIA, exist_ok=True)
print("\n--- AppScope/resources/base/media ---")
bg_path = os.path.join(OHOS_MEDIA, "background_icon.png")
fg_path = os.path.join(OHOS_MEDIA, "foreground_icon.png")
generate_background(img, bg_path, bg_color)
generate_foreground(img, fg_path, bg_color)
generate_layered_json(OHOS_MEDIA)
print("\n--- entry/src/main/resources/base/media ---")
bg_entry = os.path.join(OHOS_ENTRY_MEDIA, "background_icon.png")
fg_entry = os.path.join(OHOS_ENTRY_MEDIA, "foreground_icon.png")
generate_background(img, bg_entry, bg_color)
generate_foreground(img, fg_entry, bg_color)
generate_layered_json(OHOS_ENTRY_MEDIA)
print("\n完成!")
if __name__ == "__main__":
main()