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
thumbnailper ridurre mantenendo le proporzioni edexif_transposeper l'orientamento. - Una qualità JPEG tra 75 e 85 è un buon punto di partenza da verificare a occhio.
- Convertite in
RGBprima di salvare in JPEG e valutate WebP per il web. - Controllate l'assenza di metadati GPS e non sovrascrivete mai gli originali.