feat: add emote style for v2 (#1217)

* feat: add emote style for v2

* feat: delete asset probe apply
This commit is contained in:
espressif2022
2025-09-19 14:14:43 +08:00
committed by GitHub
parent 4616fa3486
commit 8d58bdb21b
19 changed files with 1275 additions and 569 deletions

185
scripts/spiffs_assets/build.py Executable file → Normal file
View File

@@ -113,8 +113,170 @@ def process_emoji_collection(emoji_collection_dir, assets_dir):
return emoji_list
def load_emoji_config(emoji_collection_dir):
"""Load emoji config from config.json file"""
config_path = os.path.join(emoji_collection_dir, "emote.json")
if not os.path.exists(config_path):
print(f"Warning: Config file not found: {config_path}")
return {}
try:
with open(config_path, 'r', encoding='utf-8') as f:
config_data = json.load(f)
# Convert list format to dict for easy lookup
config_dict = {}
for item in config_data:
if "emote" in item:
config_dict[item["emote"]] = item
return config_dict
except Exception as e:
print(f"Error loading config file {config_path}: {e}")
return {}
def generate_index_json(assets_dir, srmodels, text_font, emoji_collection):
def process_board_emoji_collection(emoji_collection_dir, target_board_dir, assets_dir):
"""Process emoji_collection parameter"""
if not emoji_collection_dir:
return []
emoji_config = load_emoji_config(target_board_dir)
print(f"Loaded emoji config with {len(emoji_config)} entries")
emoji_list = []
for emote_name, config in emoji_config.items():
if "src" not in config:
print(f"Error: No src field found for emote '{emote_name}' in config")
continue
eaf_file_path = os.path.join(emoji_collection_dir, config["src"])
file_exists = os.path.exists(eaf_file_path)
if not file_exists:
print(f"Warning: EAF file not found for emote '{emote_name}': {eaf_file_path}")
else:
# Copy eaf file to assets directory
copy_file(eaf_file_path, os.path.join(assets_dir, config["src"]))
# Create emoji entry with src as file (merge file and src)
emoji_entry = {
"name": emote_name,
"file": config["src"] # Use src as the actual file
}
eaf_properties = {}
if not file_exists:
eaf_properties["lack"] = True
if "loop" in config:
eaf_properties["loop"] = config["loop"]
if "fps" in config:
eaf_properties["fps"] = config["fps"]
if eaf_properties:
emoji_entry["eaf"] = eaf_properties
status = "MISSING" if not file_exists else "OK"
eaf_info = emoji_entry.get('eaf', {})
print(f"emote '{emote_name}': file='{emoji_entry['file']}', status={status}, lack={eaf_info.get('lack', False)}, loop={eaf_info.get('loop', 'none')}, fps={eaf_info.get('fps', 'none')}")
emoji_list.append(emoji_entry)
print(f"Successfully processed {len(emoji_list)} emotes from config")
return emoji_list
def process_board_icon_collection(icon_collection_dir, assets_dir):
"""Process emoji_collection parameter"""
if not icon_collection_dir:
return []
icon_list = []
for root, dirs, files in os.walk(icon_collection_dir):
for file in files:
if file.lower().endswith(('.bin')) or file.lower() == 'listen.eaf':
src_file = os.path.join(root, file)
dst_file = os.path.join(assets_dir, file)
copy_file(src_file, dst_file)
filename_without_ext = os.path.splitext(file)[0]
icon_list.append({
"name": filename_without_ext,
"file": file
})
return icon_list
def process_board_layout(layout_json_file, assets_dir):
"""Process layout_json parameter"""
if not layout_json_file:
print(f"Warning: Layout json file not provided")
return []
print(f"Processing layout_json: {layout_json_file}")
print(f"assets_dir: {assets_dir}")
if os.path.isdir(layout_json_file):
layout_json_path = os.path.join(layout_json_file, "layout.json")
if not os.path.exists(layout_json_path):
print(f"Warning: layout.json not found in directory: {layout_json_file}")
return []
layout_json_file = layout_json_path
elif not os.path.isfile(layout_json_file):
print(f"Warning: Layout json file not found: {layout_json_file}")
return []
try:
with open(layout_json_file, 'r', encoding='utf-8') as f:
layout_data = json.load(f)
# Layout data is now directly an array, no need to get "layout" key
layout_items = layout_data if isinstance(layout_data, list) else layout_data.get("layout", [])
processed_layout = []
for item in layout_items:
processed_item = {
"name": item.get("name", ""),
"align": item.get("align", ""),
"x": item.get("x", 0),
"y": item.get("y", 0)
}
if "width" in item:
processed_item["width"] = item["width"]
if "height" in item:
processed_item["height"] = item["height"]
processed_layout.append(processed_item)
print(f"Processed {len(processed_layout)} layout elements")
return processed_layout
except Exception as e:
print(f"Error reading/processing layout.json: {e}")
return []
def process_board_collection(target_board_dir, res_path, assets_dir):
"""Process board collection - merge icon, emoji, and layout processing"""
# Process all collections
if os.path.exists(res_path) and os.path.exists(target_board_dir):
emoji_collection = process_board_emoji_collection(res_path, target_board_dir, assets_dir)
icon_collection = process_board_icon_collection(res_path, assets_dir)
layout_json = process_board_layout(target_board_dir, assets_dir)
else:
print(f"Warning: EAF directory not found: {res_path} or {target_board_dir}")
emoji_collection = []
icon_collection = []
layout_json = []
return emoji_collection, icon_collection, layout_json
def generate_index_json(assets_dir, srmodels, text_font, emoji_collection, icon_collection, layout_json):
"""Generate index.json file"""
index_data = {
"version": 1
@@ -128,6 +290,12 @@ def generate_index_json(assets_dir, srmodels, text_font, emoji_collection):
if emoji_collection:
index_data["emoji_collection"] = emoji_collection
if icon_collection:
index_data["icon_collection"] = icon_collection
if layout_json:
index_data["layout"] = layout_json
# Write index.json
index_path = os.path.join(assets_dir, "index.json")
@@ -148,7 +316,7 @@ def generate_config_json(build_dir, assets_dir):
"image_file": os.path.join(workspace_dir, "build/output/assets.bin"),
"lvgl_ver": "9.3.0",
"assets_size": "0x400000",
"support_format": ".png, .gif, .jpg, .bin, .json",
"support_format": ".png, .gif, .jpg, .bin, .json, .eaf",
"name_length": "32",
"split_height": "0",
"support_qoi": False,
@@ -174,6 +342,9 @@ def main():
parser.add_argument('--wakenet_model', help='Path to wakenet model directory')
parser.add_argument('--text_font', help='Path to text font file')
parser.add_argument('--emoji_collection', help='Path to emoji collection directory')
parser.add_argument('--res_path', help='Path to res directory')
parser.add_argument('--target_board', help='Path to target board directory')
args = parser.parse_args()
@@ -195,10 +366,16 @@ def main():
# Process each parameter
srmodels = process_wakenet_model(args.wakenet_model, build_dir, assets_dir)
text_font = process_text_font(args.text_font, assets_dir)
emoji_collection = process_emoji_collection(args.emoji_collection, assets_dir)
if(args.target_board):
emoji_collection, icon_collection, layout_json = process_board_collection(args.target_board, args.res_path, assets_dir)
else:
emoji_collection = process_emoji_collection(args.emoji_collection, assets_dir)
icon_collection = []
layout_json = []
# Generate index.json
generate_index_json(assets_dir, srmodels, text_font, emoji_collection)
generate_index_json(assets_dir, srmodels, text_font, emoji_collection, icon_collection, layout_json)
# Generate config.json
config_path = generate_config_json(build_dir, assets_dir)

View File

@@ -31,7 +31,7 @@ def get_file_path(base_dir, filename):
return os.path.join(base_dir, f"{filename}.bin" if not filename.startswith("emojis_") else filename)
def build_assets(wakenet_model, text_font, emoji_collection, build_dir, final_dir):
def build_assets(wakenet_model, text_font, emoji_collection, target_board, build_dir, final_dir):
"""Build assets.bin using build.py with given parameters"""
# Prepare arguments for build.py
@@ -42,14 +42,21 @@ def build_assets(wakenet_model, text_font, emoji_collection, build_dir, final_di
cmd.extend(["--wakenet_model", wakenet_path])
if text_font != "none":
text_font_path = os.path.join("../../components/xiaozhi-fonts/build", f"{text_font}.bin")
text_font_path = os.path.join("../../components/78__xiaozhi-fonts/cbin", f"{text_font}.bin")
cmd.extend(["--text_font", text_font_path])
if emoji_collection != "none":
emoji_path = os.path.join("../../components/xiaozhi-fonts/build", emoji_collection)
cmd.extend(["--emoji_collection", emoji_path])
if target_board != "none":
res_path = os.path.join("../../managed_components/espressif2022__esp_emote_gfx/emoji_large", "")
cmd.extend(["--res_path", res_path])
target_board_path = os.path.join("../../main/boards/", f"{target_board}")
cmd.extend(["--target_board", target_board_path])
print(f"\n正在构建: {wakenet_model}-{text_font}-{emoji_collection}")
print(f"\n正在构建: {wakenet_model}-{text_font}-{emoji_collection}-{target_board}")
print(f"执行命令: {' '.join(cmd)}")
try:
@@ -57,7 +64,10 @@ def build_assets(wakenet_model, text_font, emoji_collection, build_dir, final_di
result = subprocess.run(cmd, check=True, cwd=os.path.dirname(__file__))
# Generate output filename
output_name = f"{wakenet_model}-{text_font}-{emoji_collection}.bin"
if(target_board != "none"):
output_name = f"{wakenet_model}-{text_font}-{target_board}.bin"
else:
output_name = f"{wakenet_model}-{text_font}-{emoji_collection}.bin"
# Copy generated assets.bin to final directory with new name
src_path = os.path.join(build_dir, "assets.bin")
@@ -80,6 +90,15 @@ def build_assets(wakenet_model, text_font, emoji_collection, build_dir, final_di
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description='构建多个 SPIFFS assets 分区')
parser.add_argument('--mode',
choices=['emoji_collections', 'emoji_target_boards'],
default='emoji_collections',
help='选择运行模式: emoji_collections 或 emoji_target_boards (默认: emoji_collections)')
args = parser.parse_args()
# Configuration
wakenet_models = [
"none",
@@ -100,6 +119,11 @@ def main():
"emojis_32",
"emojis_64",
]
emoji_target_boards = [
"esp-box-3",
"echoear",
]
# Get script directory
script_dir = os.path.dirname(os.path.abspath(__file__))
@@ -113,18 +137,33 @@ def main():
ensure_dir(final_dir)
print("开始构建多个 SPIFFS assets 分区...")
print(f"运行模式: {args.mode}")
print(f"输出目录: {final_dir}")
# Track successful builds
successful_builds = 0
total_combinations = len(wakenet_models) * len(text_fonts) * len(emoji_collections)
# Build all combinations
for wakenet_model in wakenet_models:
for text_font in text_fonts:
for emoji_collection in emoji_collections:
if build_assets(wakenet_model, text_font, emoji_collection, build_dir, final_dir):
successful_builds += 1
if args.mode == 'emoji_collections':
# Calculate total combinations for emoji_collections mode
total_combinations = len(wakenet_models) * len(text_fonts) * len(emoji_collections)
# Build all combinations with emoji_collections
for wakenet_model in wakenet_models:
for text_font in text_fonts:
for emoji_collection in emoji_collections:
if build_assets(wakenet_model, text_font, emoji_collection, "none", build_dir, final_dir):
successful_builds += 1
elif args.mode == 'emoji_target_boards':
# Calculate total combinations for emoji_target_boards mode
total_combinations = len(wakenet_models) * len(text_fonts) * len(emoji_target_boards)
# Build all combinations with emoji_target_boards
for wakenet_model in wakenet_models:
for text_font in text_fonts:
for emoji_target_board in emoji_target_boards:
if build_assets(wakenet_model, text_font, "none", emoji_target_board, build_dir, final_dir):
successful_builds += 1
print(f"\n构建完成!")
print(f"成功构建: {successful_builds}/{total_combinations}")