Ridimensionare immagini al volo
Ridimensionamento rapido delle immagini
Come architetto web, uno dei tanti problemi riguarda la gestione delle risorse. E il problema più significativo riguarda le immagini. Un approccio ingenuo sarebbe impostare un’immagine e permettere al browser di ridimensionarla tramite CSS:
Tuttavia, ciò significa che scarichi l’immagine originale. Ciò comporta due problemi: la dimensione dell’immagine originale e il ridimensionamento tramite browser non ottimale.
In questo articolo verranno illustrare due alternative: soluzioni tradizionali e innovative.
Ridimensionamento in anticipo
La soluzione tradizionale per una singola risorsa immagine è sempre stata il ridimensionamento in anticipo. Prima del rilascio, i designer dedicavano del tempo per fornire diverse versioni di immagini a diverse risoluzioni. Su questo blog, utilizzo questa tecnica. Fornisco tre risoluzioni per visualizzare l’immagine principale dell’articolo in contesti diversi come immagini di sfondo:
- Annunciamo nuovi strumenti per aiutare ogni azienda ad abbracciare l’IA generativa
- Cosa sono esattamente le operazioni di Large Language Model (LLMops)?
- LLMOps vs MLOps Capire le differenze
- Grande per l’articolo nella sua pagina
- VoAGI per l’articolo nella pagina principale
- Piccola per articoli correlati in una pagina dell’articolo
Rimovo anche i metadati JPEG per una riduzione delle dimensioni ancora maggiore.
Tuttavia, l’approccio tradizionale è quello di sfruttare l’elemento HTML picture
:
L’elemento HTML
<picture>
contiene zero o più elementi<source>
e un elemento<img>
per offrire versioni alternative di un’immagine per diversi scenari di visualizzazione/dispositivi.Il browser considererà ogni elemento figlio
<source>
e sceglierà la migliore corrispondenza tra di essi. Se nessuna corrispondenza viene trovata, o il browser non supporta l’elemento<picture>
, viene selezionato l’URL dell’attributo src dell’elemento<img>
. L’immagine selezionata viene quindi presentata nello spazio occupato dall’elemento<img>
.
A sua volta, si può utilizzarlo come segue:
Questo metodo ha funzionato per anni, ma presenta due problemi. In primo luogo, fornire più risoluzioni per ciascuna immagine richiede molto tempo. Si potrebbe automatizzare il processo e ottenere buoni risultati con l’IA.
Tuttavia, il volume di archiviazione necessario potrebbe essere due o tre volte la dimensione dell’immagine originale, a seconda del numero di risoluzioni extra create. In un ambiente ricco di risorse, ad esempio nell’e-commerce, i costi aumenterebbero significativamente.
Ridimensionamento al volo
Di recente mi sono imbattuto in imgproxy
, un componente per ridimensionare le immagini al volo:
imgproxy rende i siti web e le applicazioni rapidissimi, risparmiando costi di archiviazione e SaaS
Offre un endpoint in cui è possibile inviare un URL codificato che definisce:
- L’immagine da ridimensionare e la sua posizione, ad esempio locale, un URL HTTP, un bucket S3, ecc.
- Diverse impostazioni di dimensionamento, ad esempio le dimensioni, se adattare o riempire, ecc.
- Il formato.
imgproxy
supporta formati standard come JPEG e PNG, ma anche formati più moderni come WebP e AVIF. Può anche scegliere il formato migliore in base all’intestazione ‘Accept’. - Molte (molte!) altre opzioni, come filigrana, filtraggio, rotazione, ecc.
imgproxy
offre sia una versione Open Source gratuita che una versione a pagamento; tutto ciò incluso in questo articolo fa parte della prima.
Una soluzione potrebbe essere che lo sviluppatore web inserisca ogni URL di imgproxy
nell’HTML:
Questo rivelerebbe dettagli legati alla topologia sulla pagina web. Non è una soluzione mantenibile. Possiamo risolvere il problema con un proxy inverso o un API Gateway. Userò Apache APISIX per ovvie ragioni.
Con questo approccio, l’HTML precedente diventa molto più semplice:
Apache APISIX intercetta le richieste che iniziano con /resize
, riscrive l’URL per imgproxy
e inoltra l’URL riscritto a imgproxy
. Ecco l’intero flusso:
La configurazione corrispondente di Apache APISIX appare come segue:
- Abbina le richieste precedute da
/resize
- Riscrivi l’URL
- Intercetta la larghezza e l’immagine nella regolare espressione
- Formatta l’URL per
imgproxy
.http://server:3000
è il server che ospita l’immagine originale;@webp
indica una preferenza per il formato WebP (se il browser lo supporta)
Con quanto sopra, /resize/200/ai-generated.jpg
su Apache APISIX viene riscritto come /rs:fill/w:200/plain/http://server:3000/ai-generated.jpg@webp
su imgproxy
.
Testing
Possiamo configurare un piccolo campione di test con Docker Compose:
- Semplice server web che ospita l’HTML e l’immagine principale
Ora possiamo testare la configurazione precedente con gli strumenti per sviluppatori del browser, emulando dispositivi con schermo piccolo, ad esempio l’iPhone SE. Il risultato è il seguente:
- A causa della risoluzione dello schermo, l’immagine richiesta è quella con una larghezza di 400px, non l’originale. Puoi vederlo nell’URL della richiesta
- L’immagine restituita è nel formato WebP; il suo peso è di 14,4 kb
- L’immagine JPEG originale pesa 154 kb, più di dieci volte di più. È un grande risparmio di larghezza di banda di rete!
Discussione
Ridurre i costi di archiviazione di un fattore di dieci è sicuramente un grande vantaggio. Tuttavia, non è tutto rose e fiori. Il ridimensionamento dell’immagine comporta un’intensa operazione di calcolo, che richiede tempo CPU per ogni richiesta. Inoltre, per quanto efficiente sia imgproxy
, crea un’immagine richiedendo tempo. Abbiamo scambiato i costi di archiviazione con i costi CPU e ora subiamo un leggero calo delle prestazioni.
Per risolvere il problema, abbiamo bisogno di uno strato di caching di fronte, che sia personalizzato oppure, molto probabilmente, un CDN. Potresti obiettare che archivieremo nuovamente le risorse; quindi, i costi di archiviazione aumenteranno di nuovo. Tuttavia, la differenza significativa è che la cache funziona solo per le immagini utilizzate, mentre in precedenza pagavamo per archiviare tutte le immagini nella soluzione iniziale. È possibile applicare anche ricette note per la memorizzazione nella cache, come il pre-riscaldamento, quando si sa che un gruppo di immagini sarà molto richiesto, ad esempio prima di un evento.
Conclusioni
In questo post, abbiamo descritto come utilizzare Apache APISIX con imgproxy
per ridurre i costi di archiviazione delle immagini in diverse risoluzioni. Con la memorizzazione nella cache in cima, si aggiungono ulteriori componenti all’architettura complessiva ma si riducono i costi di archiviazione.
Questo post è stato ispirato dalla relazione di Andreas Lehr alla StackConf.
Il codice sorgente completo di questo post può essere trovato su GitHub.