Petit script sans prétention qui m'a permis de rapidement redimensionner et optimiser des centaines de photos pour faciliter leur partage.
from pathlib import Path
from typing import Tuple
from PIL import Image
INPUT_DIR = Path("original")
OUTPUT_DIR = Path("resized")
def resize(file: Path, /, *, quality: int = 80) -> Path:
"""Resize and optimize *file*."""
output = OUTPUT_DIR / file.name.lower()
im = Image.open(file)
width, height = im.size
im = im.resize((width // 2, height // 2), Image.ANTIALIAS)
im.save(output, optimize=True, quality=quality)
return output
def show_stat(label: str, old: int, new: int) -> None:
"""Display metrics about a given conversion."""
percent = 100 - new * 100 // old
print(f"{label}: {sizeof_fmt(old)} -> {sizeof_fmt(new)} (-{percent}%)")
def sizeof_fmt(num: int, /, *, suffix: str = "B") -> str:
"""
Human readable version of file size.
Supports:
- all currently known binary prefixes (https://en.wikipedia.org/wiki/Binary_prefix)
- negative and positive numbers
- numbers larger than 1,000 Yobibytes
- arbitrary units
Examples:
>>> sizeof_fmt(168963795964)
"157.4 GiB"
>>> sizeof_fmt(168963795964, suffix="o")
"157.4 Gio"
Source: https://stackoverflow.com/a/1094933/1117028
"""
val = float(num)
for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
if abs(val) < 1024.0:
return f"{val:3.1f} {unit}{suffix}"
val /= 1024.0
return f"{val:,.1f} Yi{suffix}"
def stats(old: Path, new: Path) -> Tuple[int, int]:
"""Retrieve *old* and *new* files sizes."""
size_old = old.stat().st_size
size_new = new.stat().st_size
return size_old, size_new
def main():
"""Entry point."""
# Size metrics, in bytes
total_size_new = 0
total_size_old = 0
# Process all pictures
for orignal in INPUT_DIR.glob("*.JPG"):
resized = resize(orignal)
size_old, size_new = stats(orignal, resized)
total_size_old += size_old
total_size_new += size_new
show_stat(orignal.name, size_old, size_new)
# Display global metrics
show_stat("TOTAL", total_size_old, total_size_new)
if __name__ == "__main__":
main()
Les photos originales à traiter se trouvent dans le dossier original. Les photos traitées seront placées dans le dossier resized.
Exemple de sortie :
$ python resize.py
DSCN1303.JPG: 4.8 MiB -> 1011.0 KiB (-80%)
DSCN1465.JPG: 4.3 MiB -> 1.2 MiB (-73%)
DSCN1471.JPG: 4.7 MiB -> 1.2 MiB (-74%)
DSCN1317.JPG: 4.8 MiB -> 519.8 KiB (-90%)
DSCN1459.JPG: 4.7 MiB -> 1.4 MiB (-70%)
# (...)
DSCN1468.JPG: 4.8 MiB -> 1.2 MiB (-76%)
TOTAL: 1.2 GiB -> 203.5 MiB (-83%)