feat: image download, resize-to-fit, baseline JPEG conversion
Made-with: Cursor
This commit is contained in:
61
src/images.py
Normal file
61
src/images.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
from PIL import Image as PILImage
|
||||
|
||||
import config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _url_hash(url: str) -> str:
|
||||
return hashlib.sha256(url.encode()).hexdigest()[:16]
|
||||
|
||||
|
||||
def _resize_to_fit(img: PILImage.Image) -> PILImage.Image:
|
||||
w, h = img.size
|
||||
if w >= h:
|
||||
max_w, max_h = config.IMAGE_MAX_LANDSCAPE
|
||||
else:
|
||||
max_w, max_h = config.IMAGE_MAX_PORTRAIT
|
||||
|
||||
scale = min(max_w / w, max_h / h)
|
||||
|
||||
new_w = int(w * scale)
|
||||
new_h = int(h * scale)
|
||||
|
||||
if new_w == w and new_h == h:
|
||||
return img
|
||||
|
||||
return img.resize((new_w, new_h), PILImage.Resampling.LANCZOS)
|
||||
|
||||
|
||||
def process_image(url: str, output_dir: str) -> tuple[str, int, int]:
|
||||
"""Download an image, resize it, save as baseline JPEG.
|
||||
|
||||
Returns (local_path, width, height). Deduplicates by URL hash.
|
||||
"""
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
filename = f"{_url_hash(url)}.jpg"
|
||||
local_path = os.path.join(output_dir, filename)
|
||||
|
||||
if os.path.exists(local_path):
|
||||
img = PILImage.open(local_path)
|
||||
return local_path, img.width, img.height
|
||||
|
||||
response = requests.get(url, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
img = PILImage.open(BytesIO(response.content))
|
||||
|
||||
if img.mode in ("RGBA", "P", "LA"):
|
||||
img = img.convert("RGB")
|
||||
|
||||
img = _resize_to_fit(img)
|
||||
|
||||
img.save(local_path, format="JPEG", progressive=False, quality=85)
|
||||
|
||||
return local_path, img.width, img.height
|
||||
Reference in New Issue
Block a user