"""Assemblage visuel des planches d'autocollants des sets filtrés.""" from pathlib import Path from typing import List from PIL import Image, ImageDraw, ImageFont from lib.filesystem import ensure_parent_dir from lib.rebrickable.stats import read_rows def load_sticker_parts(path: Path) -> List[dict]: """Charge la liste des autocollants par set.""" return read_rows(path) def plot_sticker_sheets( stickers_path: Path, destination_path: Path, resources_dir: Path = Path("figures/rebrickable"), columns: int = 6, ) -> None: """Assemble les images d'autocollants exclusifs en grille triée par année.""" rows = load_sticker_parts(stickers_path) rows.sort(key=lambda r: (int(r["year"]), r["set_num"], r["part_num"])) selected: List[dict] = [] images: List[Image.Image] = [] for row in rows: image_path = resources_dir / row["set_id"] / "stickers" / f"{row['part_num']}.jpg" if not image_path.exists(): continue img = Image.open(image_path).convert("RGBA") max_side = 260 ratio = min(max_side / img.width, max_side / img.height, 1.0) if ratio < 1.0: img = img.resize((int(img.width * ratio), int(img.height * ratio))) images.append(img) selected.append(row) if not images: return font = ImageFont.load_default() def measure(text: str) -> tuple[int, int]: bbox = ImageDraw.Draw(Image.new("RGB", (10, 10))).textbbox((0, 0), text, font=font) return bbox[2] - bbox[0], bbox[3] - bbox[1] labels = [f"{row['year']} • {row['set_id']} • {row['part_num']}" for row in selected] text_height = max(measure(label)[1] for label in labels) max_width = max(img.width for img in images) max_height = max(img.height for img in images) columns = max(1, columns) rows_count = (len(images) + columns - 1) // columns cell_width = max(max_width + 40, 240) cell_height = max_height + text_height + 20 width = columns * cell_width height = rows_count * cell_height canvas = Image.new("RGBA", (width, height), (255, 255, 255, 255)) draw = ImageDraw.Draw(canvas) for index, (img, label) in enumerate(zip(images, labels)): col = index % columns row_idx = index // columns x = col * cell_width + (cell_width - img.width) // 2 y = row_idx * cell_height + 6 canvas.paste(img, (x, y), img) text_width, _ = measure(label) text_x = col * cell_width + (cell_width - text_width) // 2 text_y = y + img.height + 6 draw.text((text_x, text_y), label, fill="#111111", font=font) ensure_parent_dir(destination_path) canvas.convert("RGB").save(destination_path, "PNG")