BookinglyTech News
Redes y nube

El deslizador de calidad del PNG no hace nada: mediciones reales de canvas.toBlob()

Medir en Chrome qué formatos respetan el argumento de calidad de canvas.toBlob() deja dos sorpresas: PNG lo ignora por completo y WebP gana a JPEG en todo el rango.

3 min de lecturaDev.to0 vistas

Si alguna herramienta web te ofrece un deslizador de calidad para exportar en PNG, ese control no hace nada. Lo ha comprobado quien construye conversores de imagen en el navegador midiendo canvas.toBlob() en Chrome 149 headless sobre Linux: el mismo lienzo codificado en PNG da exactamente 1.345.909 bytes con el argumento de calidad a 0,1 y a 1,0. No es que varíe poco, es que el archivo sale idéntico byte a byte. En un segundo lienzo de 200×200 pasó lo mismo: 17.279 bytes en los dos extremos.

PNG es sin pérdida y ahí muere el argumento

El motivo no tiene misterio. PNG comprime sin pérdida, y el valor de calidad que esperan los codificadores de JPEG y WebP es un objetivo de cuantificación. PNG no cuantifica nada, así que Chrome recibe el número y lo tira. Cualquier interfaz que prometa "baja la calidad al 80% y ahorra la mitad en PNG" está describiendo algo que ningún navegador hace. Para reducir un PNG de verdad solo hay tres vías: menos píxeles (reescalar), menos colores (paleta y cuantización, y eso exige un codificador propio tipo UPNG o ImageQuant, no toBlob) o cambiar de formato.

Los números salen de un lienzo de 1200×800 pensado para castigar a un codificador con pérdida: degradado lineal, 6.000 rectángulos de ruido semitransparente de 4×4 píxeles y texto monoespaciado de 72 px por encima. Sobre esos mismos píxeles:

  • JPEG a 1,0: 962.887 bytes; a 0,8: 96.345; a 0,6: 57.971; a 0,1: 12.124.
  • WebP a 1,0: 477.822 bytes; a 0,8: 68.194; a 0,3: 26.504.

WebP gana a JPEG en todo el rango

La segunda conclusión es que WebP salió más pequeño que JPEG en cada ajuste probado, y con margen: 477.822 frente a 962.887 bytes en calidad máxima, 68.194 frente a 96.345 en 0,8. El codificador JPEG de Chrome a calidad 1,0 sigue siendo una codificación con pérdida, solo que apunta muy arriba y deja de mirar el tamaño. Eso deja mal el reflejo de "uso JPEG porque WebP a lo mejor ocupa más". Dos matices: la curva depende de la imagen (un degradado con ruido es un caso cómodo para JPEG, y con ilustraciones planas los porcentajes se desploman), y en canvas no hay JPEG sin pérdida por mucho que se suba el número.

Hay una tercera parte que no va de calidad. toBlob() no copia el archivo original: codifica los píxeles RGBA que hay en ese momento en el lienzo. Eso deja fuera los metadatos, porque EXIF, GPS, XMP y el perfil ICC no sobreviven a un drawImage, y conviene tener claro si eso es lo que quieres. El canal alfa sobrevive en PNG y WebP, nunca en JPEG: si no pintas un fondo antes, las zonas transparentes salen negras. Y cualquier animación se queda en un solo fotograma.

En la ruta SVG a PNG, que es donde más se nota, el campo de calidad es el control equivocado: al rasterizar solo manda el tamaño en píxeles. Un icono de 24×24 exportado a 512×512 son 512×512 píxeles reales, los atributos del SVG no lo limitan y un archivo que solo traiga viewBox no tiene tamaño intrínseco (el navegador recurre a 300×150 cuando le hacen falta). Los detalles de esa ruta, con recursos externos que se saltan o fuentes web que nunca cargan, están en su guía de SVG a PNG.

Para quien mantenga un pipeline de imágenes, la conclusión práctica es sencilla: si hay un control de calidad en la exportación a PNG, sobra. Y si el navegador puede codificar WebP, mantener JPEG por defecto ya no se sostiene. Las cifras son de un solo equipo y un solo navegador, así que conviene repetir la medición con las imágenes de verdad antes de tocar nada.