gendesign/backend/app/services/photos/thumbs.py
2026-04-27 20:26:55 +03:00

57 lines
1.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Thumbnail generation for DOM.РФ photos.
Strategy: original PNG/JPG ~1-3 MB downloaded by scraper to
data/raw/domrf_photos/<obj_id>/<file_id>.{png,jpg}. We additionally write a
WebP cover-thumbnail at 320×240 (~10-30 KB) next to it, suffix `_thumb.webp`.
The frontend grid uses /api/v1/photos/<obj_id>/<file_id>?size=thumb. Lightbox
opens the original DOM.РФ URL (we don't need to mirror originals).
"""
from __future__ import annotations
import logging
from pathlib import Path
from PIL import Image, ImageOps
logger = logging.getLogger(__name__)
THUMB_SIZE: tuple[int, int] = (320, 240)
THUMB_QUALITY: int = 70
THUMB_SUFFIX: str = "_thumb.webp"
def thumb_path_for(src: Path) -> Path:
"""Return canonical thumbnail path next to the source file."""
return src.with_name(src.stem + THUMB_SUFFIX)
def make_thumbnail(
src: Path,
*,
size: tuple[int, int] = THUMB_SIZE,
quality: int = THUMB_QUALITY,
overwrite: bool = False,
) -> Path | None:
"""Generate a WebP cover-thumbnail next to src. Returns thumb path on success.
Skips if thumb already exists and overwrite=False. Returns None on any error
(logged) so callers can keep going with the next file.
"""
if not src.exists():
return None
dst = thumb_path_for(src)
if dst.exists() and not overwrite:
return dst
try:
with Image.open(src) as im:
im = ImageOps.exif_transpose(im)
im = im.convert("RGB")
im = ImageOps.fit(im, size, method=Image.Resampling.LANCZOS)
dst.parent.mkdir(parents=True, exist_ok=True)
im.save(dst, format="WEBP", quality=quality, method=4)
return dst
except Exception as e:
logger.warning("thumbnail %s failed: %s", src, e)
return None