diff --git a/bricks/_common/common.mk b/bricks/_common/common.mk index da7235863..4f7eea3e5 100644 --- a/bricks/_common/common.mk +++ b/bricks/_common/common.mk @@ -679,9 +679,16 @@ else FW_SECTIONS := endif -$(BUILD)/pbio_image_media.c $(BUILD)/pb_type_image_attributes.c: $(MEDIA_CONVERT) +# Force rebuild if list of media sources changed. +-include $(BUILD)/media_sources_gen.mk +MEDIA_SOURCES := $(shell $(MEDIA_CONVERT) --list) +MEDIA_FORCE := $(if $(strip $(filter-out $(MEDIA_SOURCES),$(MEDIA_SOURCES_GEN)) $(filter-out $(MEDIA_SOURCES_GEN),$(MEDIA_SOURCES))),media-force) +media-force: +.PHONY: media-force + +$(BUILD)/pbio_image_media.c $(BUILD)/pbio_image_media.h $(BUILD)/pb_type_image_attributes.c: $(MEDIA_CONVERT) $(MEDIA_SOURCES) $(MEDIA_FORCE) $(ECHO) "Generating image media files" - $(Q)$(PYTHON) $(MEDIA_CONVERT) $(BUILD) + $(Q)$(PYTHON) $(MEDIA_CONVERT) --dest $(BUILD) $(BUILD)/font_liberationsans_regular_14.c: $(PBTOP)/lib/pbio/src/image/fonts/LiberationSans-Regular.ttf $(FONT_CONVERT) $(ECHO) "GEN $@" diff --git a/lib/pbio/src/image/media.py b/lib/pbio/src/image/media.py index dba3fc0de..6ae291f84 100755 --- a/lib/pbio/src/image/media.py +++ b/lib/pbio/src/image/media.py @@ -1,38 +1,54 @@ #!/usr/bin/env python3 import argparse +import sys from pathlib import Path from PIL import Image import cairosvg # Take build directory as argument to save generated C files and PNG files. parser = argparse.ArgumentParser(description="Convert image files to C structs.") -parser.add_argument("dest", help="Destination build folder for PNG files.") +parser.add_argument( + "--dest", default="build", help="Destination build folder for generated files." +) +parser.add_argument( + "--list-sources", action="store_true", help="Only list sources files." +) args = parser.parse_args() +media_dir = Path(__file__).parent.relative_to(Path.cwd()) / "media" + +# Collect all SVG and image files in media_dir (svg, png, bmp, jpg), including subfolders. +media_images_sources = ( + list(media_dir.rglob("*.png")) + + list(media_dir.rglob("*.bmp")) + + list(media_dir.rglob("*.jpg")) +) +media_svg_sources = list(media_dir.rglob("*.svg")) +media_sources = media_images_sources + media_svg_sources +media_sources.sort() + +if args.list_sources: + for m in media_sources: + print(m) + sys.exit(0) + build_dir = Path(args.dest) build_dir.mkdir(parents=True, exist_ok=True) -media_dir = Path(__file__).parent / "media" + +media_gen = [] # Convert all SVG files in media_dir to PNG and save in build_dir if not already present. -svg_files = media_dir.rglob("*.svg") -for svg in svg_files: +for svg in media_svg_sources: png = svg.with_suffix(".png").name png_path = build_dir / png - if png_path.exists(): + media_gen.append(png_path) + if png_path.exists() and png_path.stat().st_mtime >= svg.stat().st_mtime: continue with open(svg, "rb") as svg_file: png_bytes = cairosvg.svg2png(file_obj=svg_file) with open(png_path, "wb") as out_png: out_png.write(png_bytes) -# Collect all image files in media_dir (png, bmp, jpg) and build_dir (png), including subfolders. -media_images = ( - list(media_dir.rglob("*.png")) - + list(media_dir.rglob("*.bmp")) - + list(media_dir.rglob("*.jpg")) - + list(build_dir.rglob("*.png")) -) - # Convert rgba to monochrome, treating fully transparent pixels as white. def is_black(r, g, b, a): @@ -60,6 +76,7 @@ def image_to_8bit_map(img): # Process each image. +media_images = media_images_sources + media_gen results = {} for img_path in media_images: with Image.open(img_path) as img: @@ -129,3 +146,8 @@ def image_to_8bit_map(img): f.write( "MP_DEFINE_CONST_DICT(pb_type_image_attributes_dict, pb_type_image_attributes_dict_table);" ) + +with open(build_dir / "media_sources_gen.mk", "w") as f: + f.write("MEDIA_SOURCES_GEN = \\\n ") + f.write(" \\\n ".join(str(m) for m in media_sources)) + f.write("\n")