dana-medical-site/migrations/import/make_webp.py
2026-10-14 13:33:13 +00:00

68 lines
2.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.

"""WebP-копии картинок сайта: рядом с «имя.jpg» кладёт «имя.jpg.webp».
Сервер (internal/api/media_webp.go) отдаёт копию браузерам, которые принимают WebP;
пути в базе не меняются. Копия сохраняется, только если она меньше оригинала.
Повторный запуск пересоздаёт копию, если оригинал новее.
python make_webp.py D:/dana/media # локально
python make_webp.py /data/media --quality 80 # на сервере, в контейнере с Pillow
"""
import argparse
import os
import sys
from PIL import Image, ImageOps
EXTS = ('.jpg', '.jpeg', '.png')
def convert(src, quality):
dst = src + '.webp'
if os.path.exists(dst) and os.path.getmtime(dst) >= os.path.getmtime(src):
return 'fresh', 0, 0
with Image.open(src) as im:
im = ImageOps.exif_transpose(im) # фото с телефона: поворот из EXIF
lossless = src.lower().endswith('.png') and im.mode in ('P', 'L') and max(im.size) <= 256
if im.mode not in ('RGB', 'RGBA'):
im = im.convert('RGBA' if 'A' in im.getbands() or im.info.get('transparency') is not None else 'RGB')
tmp = dst + '.tmp'
im.save(tmp, 'WEBP', quality=quality, method=6, lossless=lossless)
before, after = os.path.getsize(src), os.path.getsize(tmp)
if after >= before:
os.remove(tmp)
if os.path.exists(dst):
os.remove(dst)
return 'bigger', before, before
os.replace(tmp, dst)
return 'done', before, after
def main():
ap = argparse.ArgumentParser()
ap.add_argument('root')
ap.add_argument('--quality', type=int, default=80)
a = ap.parse_args()
stats = {'done': 0, 'fresh': 0, 'bigger': 0, 'error': 0}
before = after = 0
for dirpath, _, files in os.walk(a.root):
for f in files:
if not f.lower().endswith(EXTS):
continue
p = os.path.join(dirpath, f)
try:
state, b, s = convert(p, a.quality)
except Exception as e: # битый файл не должен останавливать остальные
stats['error'] += 1
print('ошибка:', p, e, file=sys.stderr)
continue
stats[state] += 1
before += b
after += s
print(f"готово: {stats['done']}, уже были: {stats['fresh']}, WebP не меньше оригинала: {stats['bigger']}, ошибок: {stats['error']}")
if before:
print(f'обработанные файлы: {before / 1e6:.1f} МБ → {after / 1e6:.1f} МБ')
if __name__ == '__main__':
main()