⟳ Automazione

Ridimensionare e convertire immagini in blocco con Python

Ridimensionare, comprimere e convertire centinaia di immagini con Python e Pillow: proporzioni, orientamento, qualità JPEG, WebP e metadati GPS.

Le foto scattate con un telefono recente pesano diversi megabyte ciascuna e hanno risoluzioni pensate per la stampa, non per un catalogo online, una relazione tecnica o un allegato email. Ridurle una per una con un programma di grafica è un lavoro da evitare. Con Python e la libreria Pillow si può elaborare un'intera cartella in pochi secondi, ottenendo file leggeri, uniformi e senza informazioni indesiderate.

Installazione e struttura dello script

pip install Pillow

Lo schema è sempre lo stesso: elencare le immagini di una cartella di origine, elaborarle una alla volta e salvarle in una cartella di destinazione diversa. Gli originali non vanno mai sovrascritti: se la qualità scelta si rivela troppo bassa, si deve poter ricominciare.

from pathlib import Path
from PIL import Image, ImageOps

origine = Path("foto_originali")
destinazione = Path("foto_web")
destinazione.mkdir(exist_ok=True)

estensioni = {".jpg", ".jpeg", ".png", ".tif", ".tiff"}
for file in sorted(origine.iterdir()):
    if file.suffix.lower() not in estensioni:
        continue
    with Image.open(file) as img:
        img = ImageOps.exif_transpose(img)
        img.thumbnail((1600, 1600))
        if img.mode in ("RGBA", "P"):
            img = img.convert("RGB")
        img.save(destinazione / f"{file.stem}.jpg", quality=82, optimize=True)

Ogni riga risolve un problema concreto, che vale la pena guardare da vicino.

Mantenere le proporzioni

thumbnail((1600, 1600)) riduce l'immagine in modo che né la larghezza né l'altezza superino 1600 pixel, mantenendo le proporzioni. Una foto orizzontale 4000×3000 diventa 1600×1200; una verticale 3000×4000 diventa 1200×1600. Se l'immagine è già più piccola, non viene ingrandita. È quasi sempre il comportamento desiderato.

resize, al contrario, porta l'immagine esattamente alle dimensioni indicate e la deforma se le proporzioni non coincidono. Serve solo quando occorre una misura precisa, e in quel caso conviene prima ritagliare. ImageOps.fit fa entrambe le cose: ritaglia al centro e ridimensiona, utile per miniature quadrate tutte uguali.

L'orientamento delle foto

Molte fotocamere non ruotano davvero i pixel quando si scatta in verticale: salvano l'immagine orizzontale e scrivono nei metadati EXIF un'indicazione di rotazione. I visualizzatori la rispettano, ma un'elaborazione ingenua no, e le foto escono girate di lato. ImageOps.exif_transpose applica la rotazione indicata ai pixel, così il risultato è corretto ovunque. Dimenticarla è l'errore più comune in questi script.

Qualità e formato

Il parametro quality del JPEG va da 1 a 95 circa nella pratica. Valori tra 75 e 85 offrono di norma un buon compromesso tra peso e resa visiva per foto destinate allo schermo. Conviene fare una prova su poche immagini rappresentative e guardarle a dimensione reale prima di elaborare tutto.

Formato Adatto a Note
JPEG Fotografie Nessuna trasparenza, compressione regolabile
PNG Grafica, schermate, loghi Senza perdita, file più pesanti per le foto
WebP Immagini per il web Supporta trasparenza, file spesso più leggeri del JPEG

Il JPEG non supporta la trasparenza: un PNG con canale alfa va convertito in RGB prima di salvarlo, altrimenti Pillow solleva un errore. Le aree trasparenti diventano nere; se serve uno sfondo bianco, si incolla l'immagine su un rettangolo bianco prima del salvataggio. Per il formato WebP basta cambiare l'estensione del file di destinazione in .webp: Pillow sceglie il formato in base all'estensione.

Le foto in formato HEIC, comuni sugli iPhone, non sono lette da Pillow senza un'estensione: il pacchetto pillow-heif aggiunge il supporto.

I metadati: attenzione alla posizione

I file EXIF possono contenere molto più dell'orientamento: modello del telefono, data e ora dello scatto e, se la geolocalizzazione era attiva, le coordinate GPS del luogo. Pubblicare online la foto del magazzino o dell'ufficio di casa con le coordinate incorporate non è una buona idea. Nel salvataggio JPEG mostrato sopra Pillow non riscrive i dati EXIF a meno che non gli vengano passati esplicitamente con il parametro exif, quindi le immagini prodotte ne sono prive. Nel mio lavoro verifico comunque il risultato su un campione con un visualizzatore di metadati, perché è un controllo che costa pochi secondi.

Nomi e sottocartelle

Se le immagini sono organizzate in sottocartelle, per esempio una per prodotto, si usa origine.rglob("*") al posto di iterdir() e si ricrea la stessa struttura nella destinazione:

relativo = file.relative_to(origine)
uscita = (destinazione / relativo).with_suffix(".jpg")
uscita.parent.mkdir(parents=True, exist_ok=True)

Attenzione ai nomi duplicati: foto.png e foto.jpg nella stessa cartella produrrebbero entrambe foto.jpg, e la seconda sovrascriverebbe la prima. Un controllo con uscita.exists() prima di salvare evita la perdita.

Velocità

Per qualche centinaio di immagini lo script impiega pochi secondi o minuti, a seconda della dimensione dei file. Per migliaia di foto si può sfruttare più di un processore con il modulo concurrent.futures e un ProcessPoolExecutor, che elabora più immagini in parallelo senza cambiare la logica della funzione.

In sintesi

  • Pillow elabora intere cartelle di immagini senza programmi di grafica.
  • Usate thumbnail per ridurre mantenendo le proporzioni ed exif_transpose per l'orientamento.
  • Una qualità JPEG tra 75 e 85 è un buon punto di partenza da verificare a occhio.
  • Convertite in RGB prima di salvare in JPEG e valutate WebP per il web.
  • Controllate l'assenza di metadati GPS e non sovrascrivete mai gli originali.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche