"""Conversions between on-disk/base64 image representations and PIL images.""" import base64 import json import os from io import BytesIO from PIL import Image from PIL.Image import Image as PILImage from logging_utils import print_decode_error, print_encode_error, print_thumbnail_error LANCZOS = getattr(Image, "Resampling", Image).LANCZOS def make_thumb_b64(path: str, max_dim: int = 220) -> str: if not os.path.exists(path): return "" try: img = Image.open(path).convert("RGB") img.thumbnail((max_dim, max_dim), LANCZOS) buf = BytesIO() img.save(buf, format="JPEG", quality=65) return f"data:image/jpeg;base64,{base64.b64encode(buf.getvalue()).decode()}" except Exception as e: print_thumbnail_error(path, e) return "" def encode_full_image(path: str) -> str: if not os.path.exists(path): return "" try: with open(path, "rb") as f: data = f.read() ext = path.rsplit(".", 1)[-1].lower() mime = {"jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "webp": "image/webp"}.get(ext, "image/jpeg") return f"data:{mime};base64,{base64.b64encode(data).decode()}" except Exception as e: print_encode_error(path, e) return "" def b64_to_pil_list(b64_json_str: str) -> list[PILImage]: if not b64_json_str or b64_json_str.strip() in ("", "[]"): return [] try: b64_list = json.loads(b64_json_str) except Exception: return [] pil_images: list[PILImage] = [] for b64_str in b64_list: if not b64_str or not isinstance(b64_str, str): continue try: if b64_str.startswith("data:image"): _, data = b64_str.split(",", 1) else: data = b64_str image_data = base64.b64decode(data) pil_images.append(Image.open(BytesIO(image_data)).convert("RGB")) except Exception as e: print_decode_error(e) return pil_images