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%)