Ma règle de compression semblait simple : produire l'AVIF avec la qualité la plus basse qui atteignait encore un objectif SSIMULACRA2 de 60. Pour les grands ensembles d'images, j'autorisais un échantillon représentatif à descendre jusqu'à 58, tandis que tous les autres devaient rester à 60 ou plus.
Pour les PNG et les sources normales, cette règle me convenait. Puis j'ai commencé à recevoir des WebP qui avaient déjà été compressés avec perte à partir d'originaux de meilleure qualité.
original de meilleure qualité : ~2 MB
↓
WebP avec perte : ~100 KB
↓
AVIF
Cette deuxième conversion devait-elle encore pouvoir passer avec 60 par rapport au WebP ? Au départ, je pensais que oui. Un score de 60 reste un score de 60. Mais la référence, elle, avait changé.
La métrique n'était pas fausse. La référence avait changé.
SSIMULACRA2 compare une image de référence à une image dégradée et mesure la différence perceptuelle entre ces deux entrées précises. La métrique réagit notamment au flou, au ringing et aux contours artificiellement introduits par la compression, et ses données d'évaluation publiées incluent des dégradations provenant de JPEG, WebP, AVIF et d'autres codecs. La documentation](https://github.com/cloudinary/ssimulacra2/blob/main/README.md%22>documentation) de SSIMULACRA2 décrit la métrique et ses repères approximatifs de qualité.
Si j'encode directement un bon original en AVIF, la comparaison correspond essentiellement à source → AVIF. Un score de 60 décrit alors les pertes introduites par cette conversion.
Avec un WebP déjà lossy, l'historique réel est différent :
original
↓ premier encodage avec perte
WebP
↓ deuxième encodage avec perte
AVIF
Mais SSIMULACRA2 ne voit que WebP → AVIF. Il ne sait rien de l'original qui existait avant le WebP. Les artefacts déjà présents dans le WebP font désormais partie de la référence.
Un score de 60 peut donc me dire que l'AVIF ne s'est pas trop éloigné du WebP. Il ne peut pas me dire à quelle distance l'AVIF final se trouve du master perdu.
Le transcodage avec perte crée un deuxième budget de qualité
Imaginons que l'original contienne un dégradé propre. Le premier encodeur ajoute un peu de banding, mais le WebP reste acceptable. Je réencode ensuite ce WebP en AVIF. SSIMULACRA2 peut pénaliser la dégradation supplémentaire introduite par l'encodeur AVIF, mais pas les défauts déjà présents dans la référence.
C'est pourquoi encoder à partir d'une image déjà lossy n'est pas équivalent à encoder directement depuis la meilleure source disponible. Une discussion du projet](https://github.com/AOMediaCodec/libavif/discussions/2640%22>projet) libavif souligne le même phénomène général : des artefacts de compression existants peuvent être conservés dans le nouvel AVIF lorsque l'entrée est déjà compressée.
Cela ne signifie pas qu'AVIF amplifie automatiquement tous les défauts du WebP, ni qu'il ne faut jamais transcoder. Cela signifie simplement que le deuxième encodeur commence son travail après qu'une partie du budget de qualité original a déjà été dépensée.
La politique que j'ai finalement retenue
- Source canonique ou de haute qualité : objectif 60, plancher 58 pour un échantillon.
- WebP lossless : objectif 60, plancher 58.
- Dérivé connu avec perte : objectif 65, plancher 63.
La distinction importante n'est pas JPEG contre WebP. C'est source canonique contre dérivé connu avec perte.
WebP peut être sans perte. La spécification](https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification%22>spécification) WebP lossless décrit un mode qui reconstruit exactement les valeurs des pixels ; il n'y a donc pas de génération lossy précédente à compenser. À l'inverse, un JPEG dont je sais qu'il a déjà subi plusieurs transformations avec perte mérite la même prudence qu'un WebP précédemment compressé.
Pourquoi 65 ?
Aucune règle de SSIMULACRA2 ne dit qu'une deuxième génération avec perte nécessite exactement cinq points supplémentaires. Je n'ai pas trouvé une telle règle parce qu'elle n'existe pas. 65 est une politique d'ingénierie, pas une propriété de la métrique.
Les repères de qualité publiés permettent de situer ce choix : environ 50 correspond à une qualité moyenne ou correcte, tandis que 70 correspond à une qualité élevée ou bonne. 60 se trouve donc dans une zone de compression web assez agressive, loin du niveau visuellement lossless.
Pour une conversion directe depuis une bonne source, j'accepte de dépenser ce budget perceptuel en échange de fichiers plus petits. Pour une deuxième génération avec perte, je voulais limiter davantage la distorsion supplémentaire.
J'ai envisagé 70, mais cela placerait toutes les images transcodées dans une zone nettement plus stricte. Sur les pages qui chargent beaucoup d'images, en particulier sur connexion mobile, ces octets supplémentaires comptent. Je n'avais pas de preuve justifiant d'imposer 70 à toutes les images déjà compressées. J'ai donc retenu 65 comme compromis conservateur.
Pourquoi 65/63 plutôt que 65/62 ?
Ma politique d'origine était 60/58 : un seul échantillon représentatif pouvait tomber deux points sous l'objectif principal. En portant l'objectif à 65, conserver la même politique conduit naturellement à 65/63.
60 - 58 = 2
65 - 63 = 2
Avec 62, l'exception passerait à trois points. Les échantillons normaux deviendraient plus stricts tandis que le plus mauvais gagnerait davantage de marge. Je n'ai trouvé aucune raison technique d'élargir cette exception précisément pour des entrées déjà compressées avec perte.
Ni 63 ni 65 ne sont des nombres magiques. L'intérêt est de conserver une politique cohérente.
Passer de 2 MB à 100 KB ne dit pas quelle est la qualité visuelle
Je ne déduis volontairement pas les seuils SSIMULACRA2 du ratio de compression. Passer de 2 MB à 100 KB paraît spectaculaire, mais la taille du fichier seule dit étonnamment peu de choses sur la dégradation perceptuelle.
Résolution, entropie de l'image, bruit, aplats, line art, chroma subsampling et format précédent influencent fortement l'efficacité de compression. L'étude](https://developers.google.com/speed/webp/docs/webp_study%22>étude) de compression WebP de Google compare les codecs à qualité approximativement équivalente au lieu de supposer que des tailles identiques impliquent une qualité visuelle identique.
Je n'utilise donc pas de règle du type 20× plus petit → objectif 65. Ce qui compte pour ma politique, c'est de savoir si le fichier actuel est un dérivé lossy identifié, pas si le ratio de réduction paraît impressionnant.
Si je possède encore l'original, je ne transcode pas le WebP
Si l'original de haute qualité et le petit WebP lossy existent tous les deux, j'encode directement l'original en AVIF et j'utilise la politique normale 60/58.
préféré :
original → AVIF
à éviter si possible :
original → WebP avec perte → AVIF
Un objectif plus strict pour la deuxième génération ne peut pas restaurer les informations perdues lors du premier encodage. 65 oblige simplement l'AVIF à rester plus proche du WebP ; 70 le garderait encore plus proche. Aucun des deux ne recrée l'original perdu.
Le bug d'implémentation était plus important que 62 contre 63
En réexaminant cette politique, j'ai trouvé un problème plus dangereux dans la logique de l'encodeur. Le code possédait déjà des objectifs spécifiques au format ainsi qu'une fonction capable de retourner une valeur différente pour WebP. Passer WebP de 60 à 65 semblait donc trivial.
Ça ne l'était pas. La décision adaptative de qualité utilisait toujours l'objectif global et le seuil global du pire score. L'objectif propre au format servait ensuite à marquer chaque résultat comme valide ou sous l'objectif, mais il ne contrôlait pas nécessairement la décision qui sélectionnait la qualité AVIF finale.
Un échec subtil devient alors possible : un échantillon WebP peut être correctement signalé sous son objectif de 65, alors que la recherche adaptative accepte tout de même la qualité parce que la condition globale reste 60.
intended WebP target: 65
actual score: 61.2
format-aware label: below target
global search rule: pass if target is still 60
Un seuil ne sert à rien s'il ne participe pas à la décision qui choisit réellement la sortie encodée.
Il est plus sûr d'intégrer les seuils à la politique de chaque échantillon
Je préfère désormais considérer les seuils comme des propriétés de la source plutôt que comme de simples constantes décoratives par format. En pseudocode simplifié :
if sample is a known lossy derivative:
target = 65
floor = 63
else:
target = 60
floor = 58
reject if any sample is below its floor
allow at most one sample below its target
L'important est que les mêmes seuils utilisés pour décrire le résultat décident aussi de son acceptation.
La politique d'échantillonnage compte aussi
Je n'ai pas besoin de tester chaque image à chaque qualité AVIF candidate. Le pipeline sélectionne jusqu'à dix JPEG, PNG ou WebP représentatifs répartis sur la distribution des octets par pixel.
Dans les ensembles de dix images ou moins, tous les échantillons doivent atteindre l'objectif normal. Dans les ensembles plus grands, un seul échantillon peut utiliser le plancher inférieur, tandis que tous les autres doivent atteindre l'objectif principal.
L'échantillonnage rend la recherche praticable, mais c'est aussi une raison de ne pas rendre la règle d'outlier inutilement permissive. Les échantillons choisis sont représentatifs ; ils ne prouvent pas que toutes les images non échantillonnées se comportent exactement de la même façon.
L'expérience qui pourrait remplacer l'heuristique
La réponse la plus solide consisterait à conserver les vrais originaux d'un corpus représentatif et à tester les chaînes complètes :
A: original → AVIF, target 60
B: original → lossy WebP → AVIF, target 60
C: original → lossy WebP → AVIF, target 63
D: original → lossy WebP → AVIF, target 65
E: original → lossy WebP → AVIF, target 70
Pour chaque variante, je mesurerais la taille finale, SSIMULACRA2 par rapport au vrai original, SSIMULACRA2 par rapport au WebP intermédiaire et la qualité retenue par l'encodeur. J'inspecterais également manuellement les images difficiles.
Je n'ai pas réalisé cette expérience contrôlée sur un ensemble suffisamment représentatif d'originaux conservés. Je ne peux donc pas affirmer que 65 est optimal partout. Cette limite est importante.
AVIF ne justifie pas automatiquement un encodage supplémentaire
Si la seule source restante est un WebP de 100 KB et que l'AVIF qui passe 65/63 pèse 96 KB, je remettrais la conversion en question. Économiser 4 KB ne justifie peut-être pas une nouvelle génération avec perte et davantage de complexité de traitement.
Si ce même WebP de 100 KB devient un AVIF de 65 KB tout en respectant la politique de qualité, le compromis devient bien plus intéressant sur des pages très riches en images.
Une conversion de codec doit répondre à deux questions distinctes : la distorsion supplémentaire est-elle acceptable, et la réduction de taille est-elle suffisamment importante ? Satisfaire la première ne garantit pas la seconde.
La règle que j'utilise aujourd'hui
Si je possède le meilleur original disponible, j'encode directement depuis celui-ci et j'utilise 60/58 pour ce type de charge web. Si le WebP est lossless, j'utilise également 60/58. Si le seul fichier restant est un dérivé connu avec perte, j'applique un budget plus strict pour la deuxième génération, actuellement 65/63. Si AVIF réduit à peine la taille, j'envisage de conserver le WebP existant.
La leçon de fond n'est pas que WebP exige un nombre SSIMULACRA2 particulier. Une métrique full-reference ne répond qu'à la question représentée par son image de référence.
Si la référence a déjà perdu de l'information, un score élevé signifie « proche de cette référence », pas « proche de l'image qui existait avant ». Lorsque j'ai commencé à traiter la provenance de l'image comme une composante de la politique de compression, les seuils ont cessé de ressembler à des réglages arbitraires du codec. Ils sont devenus des budgets pour différentes générations de perte.