Un número de calidad es una mentira: lo que mide ssimulacra2 en su lugar
Todo codificador de imagen tiene un mando de calidad: -q 80, -quality 90, un cq-level. Parece una promesa: ponlo en 80 y cada imagen sale “80% de bien”. No es así. El número fija un parámetro de compresión, no un resultado, y el resultado depende por completo de la imagen.
Podemos mostrar exactamente cuánto miente.
El mismo ajuste, calidad radicalmente distinta
Codificamos 1.998 fotografías reales a JPEG con un -q 80 fijo (libjpeg-turbo) y puntuamos cada una con ssimulacra2, una métrica perceptual donde un valor más alto significa más cercano al original.
vips -q 80 en 1.998 fotos |
ssimulacra2 |
|---|---|
| peor imagen | 58 |
| percentil 10 | 74 |
| mediana | 77 |
| percentil 90 | 80 |
| mejor imagen | 87 |
Un solo ajuste. Una dispersión de 29 puntos en la calidad real. A -q 80, una foto sale con 58: visiblemente degradada, con bloques y borrones, mientras otra pasa con 87, indistinguible del original y cargando bytes que no necesitaba. El número del mando no decía nada sobre ninguna de las dos.
Y empeora entre codificadores. -q 80 en JPEG no es -q 80 en WebP ni es cq-level 30 en AVIF: cada escala la define su propio codificador, así que las mismas cifras significan cosas distintas. Un número de calidad ni siquiera es comparable consigo mismo en otra herramienta.
Por qué el contenido de una foto decide su calidad
Un ajuste de calidad elige con qué agresividad descartar detalle. Un cielo plano o un retrato suave tienen poco detalle que perder, así que los ajustes agresivos apenas duelen: puntúa alto. Una foto de follaje, grava o tela no es más que detalle fino, así que el mismo ajuste la destroza: puntúa bajo. El codificador aplicó la misma regla; las imágenes tenían cantidades muy distintas que perder.
Por eso “usa simplemente calidad 80” te entrega en silencio dos fallos a la vez: algunas imágenes degradadas más allá de lo que un usuario nota, y algunas imágenes un 30% más grandes de lo necesario. No se ve en los ajustes, solo en la salida.
Qué usar como objetivo en su lugar
Apunta al resultado, no al parámetro. ssimulacra2 está pensado para esto: está calibrado en unidades de diferencia percibida (aproximadamente, “diferencias justo perceptibles” respecto al original), así que una puntuación objetivo significa lo mismo en cada imagen y en cada formato.
- ~90: indistinguible del original a visión normal.
- ~85: alta calidad; hay que buscar la diferencia.
- ~80: buena; suficiente para la mayoría de imágenes web.
- por debajo de ~70: la diferencia es visible.
Elige un objetivo, y deja que la calidad del codificador se busque imagen por imagen para alcanzarlo. La foto de follaje recibe un ajuste de calidad más alto porque lo necesita; el cielo plano recibe uno más bajo porque puede permitírselo. Cada imagen llega a la misma calidad percibida, cada una con los menos bytes que la alcanzan. Ninguna imagen queda arruinada en silencio, ninguna queda inflada en silencio.
Esto es lo que hace Patu en cada imagen: una búsqueda por imagen sobre la calidad del codificador para alcanzar un objetivo de ssimulacra2, en lugar de un -q fijo que significa algo distinto en cada foto.
curl -X POST "https://patu.dev/v1/compress?target=85" \
-H "X-Api-Key: $PATU_KEY" \
--data-binary @photo.jpg -o photo.avif
La métrica hace el trabajo que un número de calidad finge hacer: describir la imagen que realmente obtienes.
Método y datos: el harness de benchmark de Patu sobre la categoría de fotos (1.998 fotografías reales); libjpeg-turbo vía vips; puntuado con ssimulacra2 vía la implementación de rust-av. Los percentiles corresponden a todas las imágenes puntuadas en el ajuste fijo.