Files
lidar_rendu/scripts/transcode_q60.py

55 lines
2.2 KiB
Python

"""Transcode les AVIF q98 des visualisations en AVIF q60 (one-shot).
Usage (dans le conteneur, volume output monté) :
python3 /tmp/transcode_q60.py [--quality 60] [--workers N]
Ne remplace un fichier que si la version q60 est plus légère (garde-fou).
"""
import sys
import os
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
from PIL import Image
QUALITY = int(sys.argv[sys.argv.index('--quality') + 1]) if '--quality' in sys.argv else 60
WORKERS = int(sys.argv[sys.argv.index('--workers') + 1]) if '--workers' in sys.argv else (os.cpu_count() or 4)
ROOT = Path('/data/output/visualisations')
def transcode(path):
try:
before = path.stat().st_size
img = Image.open(path)
img.load()
tmp = path.with_name(path.name + '.q60.tmp.avif')
img.save(tmp, format='AVIF', quality=QUALITY)
after = tmp.stat().st_size
if after < before:
os.replace(tmp, path)
return (path.name, before, after, 'remplacé')
tmp.unlink()
return (path.name, before, after, 'conservé (q60 plus lourd)')
except Exception as exc: # noqa: BLE001
return (path.name, 0, 0, f'ERREUR {exc}')
if __name__ == '__main__':
files = sorted(ROOT.rglob('*.avif'))
files = [f for f in files if '.q60.tmp' not in f.name]
print(f'{len(files)} AVIF à transcoder en q{QUALITY}, {WORKERS} workers', flush=True)
total_before = total_after = n_ok = 0
with ProcessPoolExecutor(max_workers=WORKERS) as pool:
for i, (name, before, after, status) in enumerate(pool.map(transcode, files), 1):
total_before += before
total_after += min(before, after)
if status.startswith('remplacé'):
n_ok += 1
if i % 50 == 0 or i == len(files):
print(f' {i}/{len(files)} — {n_ok} remplacés — '
f'{total_before / 2**30:.1f} → {total_after / 2**30:.1f} Gio', flush=True)
elif status.startswith('ERREUR'):
print(f' {name}: {status}', flush=True)
print(f'FIN: {total_before / 2**30:.1f} → {total_after / 2**30:.1f} Gio '
f'({n_ok} fichiers réencodés)', flush=True)