Первый шаг — не отдавать оригиналы. При загрузке фото агентом мы генерируем 5 вариантов каждого изображения:
# image_processor.py — генерация вариантов при загрузке
import subprocess
from pathlib import Path
VARIANTS = [
{"name": "thumb", "width": 320, "quality": 75},
{"name": "small", "width": 640, "quality": 80},
{"name": "medium", "width": 1024, "quality": 82},
{"name": "large", "width": 1920, "quality": 85},
{"name": "original", "width": None, "quality": 90}, # сжатый оригинал
]
FORMATS = ["webp", "avif", "jpeg"]
def process_image(input_path: str, output_dir: str, image_id: str):
"""Генерирует все варианты изображения в трёх форматах."""
for variant in VARIANTS:
for fmt in FORMATS:
output_path = f"{output_dir}/{image_id}/{variant['name']}.{fmt}"
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
cmd = ["convert", input_path]
# Resize с сохранением пропорций
if variant["width"]:
cmd += ["-resize", f"{variant['width']}x"]
# Оптимизация в зависимости от формата
if fmt == "webp":
cmd += ["-quality", str(variant["quality"]),
"-define", "webp:method=6",
"-define", "webp:auto-filter=true"]
elif fmt == "avif":
cmd += ["-quality", str(variant["quality"]),
"-define", "heic:speed=4"]
else: # jpeg
cmd += ["-quality", str(variant["quality"]),
"-sampling-factor", "4:2:0",
"-strip", # удаляем EXIF
"-interlace", "Plane"] # progressive JPEG
cmd.append(output_path)
subprocess.run(cmd, check=True)
# Результат для одного фото 4000x3000 JPEG (6 MB):
# thumb.webp — 8 KB thumb.avif — 6 KB
# small.webp — 24 KB small.avif — 18 KB
# medium.webp — 62 KB medium.avif — 45 KB
# large.webp — 148 KB large.avif — 105 KB
# original.webp — 420 KB original.avif — 310 KB
Размер страницы с 15 фото: вместо 85 МБ (оригиналы) — 930 КБ (medium WebP) или 675 КБ (medium AVIF). Сжатие в 90-125 раз.
Оставить комментарий