La plupart des applications web gèrent encore l'envoi d'images comme une boîte noire. Un utilisateur dépose un fichier, le navigateur l'envoie, et le serveur accepte soit le payload, soit renvoie une erreur 413 pour laquelle personne ne s'est préparé. La compression côté navigateur change la donne. Elle vous donne la possibilité de réduire la taille des payloads avant qu'ils n'atteignent le réseau, ce qui signifie des téléchargements plus rapides, des factures de bande passante moins élevées et moins de timeouts côté serveur. Mais ce travail est facile à rater. Si vous traitez la compression comme un curseur magique nommé « qualité », vous enverrez des images corrompues, des miniatures étirées et des expériences utilisateur confuses. La meilleure approche consiste à traiter l'ensemble du flux comme un pipeline.
Pensez en pipelines, pas en curseurs
Divisez le travail en étapes distinctes. Lisez le fichier depuis l'élément d'entrée. Redimensionnez l'image selon vos dimensions cibles. Encodez un nouveau Blob. Puis, rendez le résultat à l'utilisateur. Chaque étape effectue une seule tâche et transmet sa sortie à la suivante. Cette séparation ne sert pas seulement à produire un code plus propre. Elle rend les tests unitaires simples. Vous pouvez injecter un buffer connu dans l'étape de redimensionnement sans jamais toucher à un champ de saisie de fichier. Vous pouvez vérifier que votre encodeur produit un JPEG de moins de 200 KB sans attendre un aller-retour vers le serveur. Lorsqu'un problème survient, vous savez exactement quelle étape a échoué.
Garder ces fonctions séparées permet également d'éviter les surprises lors des téléchargements. Si vous regroupez le redimensionnement et l'encodage dans une seule fonction complexe, une erreur de décodage à mi-chemin pourrait laisser votre file d'attente de téléchargement dans un état incohérent. Un pipeline vous oblige à valider à chaque frontière. Si le fichier ne peut pas être décodé, vous le détectez avant même de créer un canvas. Si le Blob encodé est trop volumineux, vous le détectez avant de demander au serveur de le stocker.
Définissez un contrat avant d'écrire le code
Avant que quiconque n'écrive un appel de dessin sur le canvas, rédigez les règles et partagez-les avec l'équipe. Choisissez les types MIME acceptés. Autoriserez-vous le JPEG, le PNG, le WebP ou l'AVIF ? Chacun a des implications sur les canaux alpha, le support des navigateurs et le coût CPU. Fixez une taille d'entrée maximale. Une photo brute de 30 MB provenant d'un téléphone haut de gamme peut figer ou faire planter un vieil ordinateur portable si vous tentez de la décoder entièrement en mémoire. Définissez des dimensions de sortie maximales. Si votre interface n'affiche jamais d'images plus larges que 2048 pixels, il est inutile de laisser passer une photo de 6000 pixels de large dans le pipeline.
Plus important encore, prévoyez les échecs de décodage. Un fichier corrompu, un profil de couleur exotique ou un téléchargement tronqué peuvent provoquer une erreur sur le constructeur Image. Votre pipeline a besoin d'un bloc catch clair et d'un message d'erreur lisible par l'humain. Ne laissez pas le navigateur mourir silencieusement et laissez l'utilisateur fixer un spinner pendant que rien ne se passe.
Respectez l'image
La distorsion fait amateur. Conservez le ratio d'aspect et limitez le côté le plus long. Si votre zone cible est de 1024 par 1024 pixels, une photo de 4000 par 3000 pixels devrait aboutir à 1024 par 768, et non à 1024 par 1024. Calculez le facteur d'échelle à partir du bord le plus long et laissez le bord le plus court suivre. Cela empêche les images de s'étirer de manière étrange.
Pour l'exportation réelle, utilisez la méthode toBlob du canvas. Elle vous donne un contrôle direct sur le format de sortie et le réglage de la qualité, et elle s'exécute de manière asynchrone pour ne pas bloquer le thread principal. Créez un canvas hors écran (offscreen canvas), dessinez l'image redimensionnée dessus, puis appelez canvas.toBlob avec le type et la valeur de qualité de votre choix. Ce nouveau Blob est ce que vous transmettrez à votre logique de téléchargement ou à votre API de stockage.
Affichez les résultats
La compression est un travail invisible. Si vous ne faites pas apparaître les chiffres, les utilisateurs ne feront pas confiance au processus. Créez une interface qui leur permet de comparer l'original avec le résultat. Affichez la taille du fichier original, la nouvelle taille du fichier, les nouvelles dimensions et le type de format final. Voir une photo de téléphone de 4.2 MB passer à un WebP de 380 KB dissipe la crainte que vous ne soyez en train de dégrader secrètement leur image.
Cette transparence aide également au dépannage. Lorsqu'un utilisateur se plaint qu'un téléchargement a échoué, la première chose que vous vérifierez est si les dimensions de sortie ont dépassé la limite de votre serveur, ou si le format est passé de PNG à JPEG en perdant le canal alpha. Placez ces données dans l'interface utilisateur afin que l'utilisateur puisse diagnostiquer le problème par lui-même avant d'ouvrir un ticket de support.
Les préréglages valent mieux que la recompression
Ne compressez jamais la même image deux fois. Chaque passage dans un encodeur avec perte supprime davantage de détails et introduit des artefacts de blocage. Si vous laissez un utilisateur cliquer répétitivement sur « optimiser », la troisième génération ressemblera à une photocopie d'une photocopie. Au lieu de cela, générez chaque sortie à partir du fichier source original et proposez des préréglages :
- Fichier plus petit : Réduisez la qualité et limitez agressivement les dimensions pour les miniatures ou les aperçus rapides.
- Équilibré : Visez un niveau de qualité modéré avec des dimensions raisonnables, adaptées aux flux de réseaux sociaux et aux galeries.
- Plus de détails : Maintenez une qualité élevée et conservez des dimensions plus grandes pour la photographie, l'art ou les aperçus d'impression.
Stockez le Blob original en mémoire afin que l'utilisateur puisse basculer entre les préréglages sans accumuler des générations de perte de qualité. Générez toujours à partir de la source, jamais à partir du dernier résultat.
Testez comme vos utilisateurs effectuent leurs uploads
Votre machine de développement avec une connexion fibre et 32 Go de RAM n'est pas la réalité. Testez avec les fichiers réels que les utilisateurs transportent. Les photos de téléphones iOS et Android utilisent des orientations de métadonnées différentes et peuvent provenir de sources HEIC. Les éléments transparents tels que les logos et les icônes se comportent différemment lors d'une conversion JPEG car le format JPEG ne prend tout simplement pas en charge les canaux alpha. Les fichiers énormes exposeront les limites de mémoire sur les appareils dotés de 2 Go de RAM. Les processeurs mobiles lents révéleront exactement le temps que prend réellement cet appel toBlob.
Utilisez Chrome DevTools pour brider le CPU et le réseau. Essayez un téléphone Android vieux de cinq ans. Si votre pipeline bloque l'interface utilisateur pendant trois secondes lors de l'encodage, vous devez déplacer le travail lourd dans un Web Worker afin que l'interface reste réactive.
Livrez l'essentiel d'abord
Il est tentant de prendre en charge tous les formats et
