"""Ordered copy-level remarks and their generated LaTeX image.""" from pathlib import Path from PIL import Image from copienator import atomic_update_json, read_json from copienator.custom_remarks import copy_key FILENAME = "general_remarks.json" IMAGE_FILENAME = "Remarques_generales.jpg" def validate(data): if not isinstance(data, dict) or any( not isinstance(key, str) or copy_key(key) != key or not isinstance(remarks, list) or any(not isinstance(text, str) for text in remarks) for key, remarks in data.items() ): raise ValueError(f"Format invalide dans {FILENAME}.") def load_remarks(root: Path) -> dict[str, list[str]]: data = read_json(root / FILENAME, default={}) validate(data) return data def remarks_for_copy(root: Path, copy_id: str) -> list[str]: return load_remarks(root).get(copy_key(copy_id), []) def set_remarks(root: Path, copy_id: str, remarks: list[str]) -> list[str]: key = copy_key(copy_id) current = [text.strip() for text in remarks if text.strip()] previous = [] def update(data): nonlocal previous validate(data) previous = data.get(key, []) if current: data[key] = current else: data.pop(key, None) atomic_update_json(root / FILENAME, update, default_factory=dict) return previous def render(root: Path, copy_id: str, width: int) -> Image.Image | None: remarks = remarks_for_copy(root, copy_id) if not remarks: return None from copienator.commands.annotating import render_real_latex_text text = r"\textbf{Remarques générales}\par\medskip " + r"\par\medskip ".join(remarks) content = render_real_latex_text(text, max(100, width - 40)).convert("RGB") image = Image.new("RGB", (max(width, content.width + 40), content.height + 40), "white") image.paste(content, (20, 20)) return image def existing(directory: Path) -> Image.Image | None: path = directory / IMAGE_FILENAME if path.is_file(): with Image.open(path) as image: return image.convert("RGB") return None