from __future__ import annotations from pathlib import Path from PIL import Image, ImageDraw, ImageFont, ImageOps REPO_ROOT = Path(__file__).resolve().parents[1] OUTPUT_DIR = ( REPO_ROOT / "public" / "branding" / "taonier-logo-capybara-jar-ref01-logo-refine-concepts" ) CONTACT_SHEET_PATH = ( OUTPUT_DIR / "taonier-logo-capybara-jar-ref01-logo-refine-contact-sheet.png" ) REFERENCE_IMAGE = ( REPO_ROOT / "public" / "branding" / "taonier-logo-peeking-head-jar-new-animals-concepts" / "taonier-peeking-head-jar-new-animals-01-capybara.png" ) ITEMS = [ ("REF 原01", REFERENCE_IMAGE), ("01 扁平陶橙", "taonier-capybara-jar-ref01-logo-refine-01-flat-terracotta"), ("02 奶白可可", "taonier-capybara-jar-ref01-logo-refine-02-cream-cocoa"), ("03 鼠尾草陶", "taonier-capybara-jar-ref01-logo-refine-03-sage-clay"), ("04 线面徽记", "taonier-capybara-jar-ref01-logo-refine-04-outline-emblem"), ("05 抽象几何", "taonier-capybara-jar-ref01-logo-refine-05-abstract-geometric"), ("06 黑白优先", "taonier-capybara-jar-ref01-logo-refine-06-monochrome-first"), ("07 轻渐变商标", "taonier-capybara-jar-ref01-logo-refine-07-soft-gradient-logo"), ("08 头像强识别", "taonier-capybara-jar-ref01-logo-refine-08-bold-avatar"), ] def load_font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: candidates = [ Path("C:/Windows/Fonts/msyh.ttc"), Path("C:/Windows/Fonts/simhei.ttf"), Path("C:/Windows/Fonts/simsun.ttc"), ] for candidate in candidates: if candidate.exists(): return ImageFont.truetype(str(candidate), size) return ImageFont.load_default() def find_image(stem_or_path: str | Path) -> Path | None: if isinstance(stem_or_path, Path): return stem_or_path if stem_or_path.exists() else None for extension in ("png", "webp", "jpg", "jpeg"): candidate = OUTPUT_DIR / f"{stem_or_path}.{extension}" if candidate.exists(): return candidate return None def normalize_square(image_path: Path) -> Image.Image: image = Image.open(image_path).convert("RGB") if image.size == (1024, 1024): return image if image.width == image.height: normalized = image.resize((1024, 1024), Image.Resampling.LANCZOS) else: normalized = ImageOps.contain(image, (1024, 1024), Image.Resampling.LANCZOS) canvas = Image.new("RGB", (1024, 1024), "#fffdf8") x = (1024 - normalized.width) // 2 y = (1024 - normalized.height) // 2 canvas.paste(normalized, (x, y)) normalized = canvas if image_path.is_relative_to(OUTPUT_DIR): normalized.save(image_path, quality=95) return normalized def bw_preview(image: Image.Image, size: int) -> Image.Image: thumb = ImageOps.grayscale(image).resize((size, size), Image.Resampling.LANCZOS) return ImageOps.autocontrast(thumb).convert("RGB") def main() -> None: cell_size = 268 label_height = 54 test_height = 44 gap = 22 columns = 3 rows = 3 cell_total_height = cell_size + label_height + test_height width = columns * cell_size + (columns + 1) * gap height = rows * cell_total_height + (rows + 1) * gap sheet = Image.new("RGB", (width, height), "#f0ebe5") draw = ImageDraw.Draw(sheet) label_font = load_font(18) test_font = load_font(13) for index, (label, stem_or_path) in enumerate(ITEMS): row = index // columns column = index % columns x = gap + column * (cell_size + gap) y = gap + row * (cell_total_height + gap) image_path = find_image(stem_or_path) if image_path is None: continue source = normalize_square(image_path) thumbnail = source.resize((cell_size, cell_size), Image.Resampling.LANCZOS) sheet.paste(thumbnail, (x, y)) draw.rounded_rectangle( (x, y + cell_size, x + cell_size, y + cell_size + label_height), radius=8, fill="#fffdf8", ) text_box = draw.textbbox((0, 0), label, font=label_font) text_x = x + (cell_size - (text_box[2] - text_box[0])) / 2 text_y = y + cell_size + (label_height - (text_box[3] - text_box[1])) / 2 - 2 draw.text((text_x, text_y), label, fill="#302a25", font=label_font) test_y = y + cell_size + label_height draw.rounded_rectangle( (x, test_y, x + cell_size, test_y + test_height), radius=8, fill="#f7f3ed", ) tiny = source.resize((32, 32), Image.Resampling.LANCZOS) mono = bw_preview(source, 32) sheet.paste(tiny, (x + 52, test_y + 6)) sheet.paste(mono, (x + 104, test_y + 6)) draw.text((x + 150, test_y + 13), "32px / BW", fill="#5c5148", font=test_font) OUTPUT_DIR.mkdir(parents=True, exist_ok=True) sheet.save(CONTACT_SHEET_PATH, quality=95) print(CONTACT_SHEET_PATH) if __name__ == "__main__": main()