PNG: Gráficos Portátiles de Red para Compresión Lossless Web
PNG (Portable Network Graphics) es el estándar de facto para compresión lossless en la web. Introducido en 1996 para reemplazar GIF (evitando problemas de patentes), PNG se ha convertido en ubicuo para capturas de pantalla, logos, gráficos y cualquier contenido que requiera transparencia y fidelidad perfecta. Todos los navegadores soportan PNG nativamente con cobertura del 100%.
Estructura de Archivo PNG: Chunks e IHDR
Cada archivo PNG es una secuencia de chunks, cada uno con un identificador de tipo de 4 bytes y suma de verificación CRC-32:
89 50 4E 47 0D 0A 1A 0A (firma PNG — nunca cambia)
00 00 00 0D (longitud del chunk = 13 bytes)
49 48 44 52 (tipo de chunk 'IHDR' — encabezado de imagen)
[13 bytes de datos IHDR]
[4 bytes CRC-32]
00 00 xx xx (longitud del chunk IDAT)
49 44 41 54 (tipo de chunk 'IDAT')
[datos de píxeles desinflados]
[4 bytes CRC-32]
00 00 00 00 (longitud IEND = 0)
49 45 4E 44 (tipo de chunk 'IEND' — marca el final)
AE 42 60 82 (CRC-32 IEND)
IHDR (Encabezado de Imagen) — 13 bytes:
| Campo | Bytes | Significado |
|---|---|---|
| Ancho | 4 | Ancho de imagen en píxeles (big-endian) |
| Alto | 4 | Alto de imagen en píxeles |
| Profundidad de Bit | 1 | 1, 2, 4, 8, 16 bits por muestra |
| Tipo de Color | 1 | 0=escala de grises, 2=RGB, 3=indexado (paleta), 4=escala grises+alfa, 6=RGBA |
| Compresión | 1 | 0 = deflate/inflate (único valor válido) |
| Filtro | 1 | 0 = filtrado adaptativo (único valor válido) |
| Entrelazado | 1 | 0 = ninguno, 1 = Adam7 (entrelazado de 7 pasadas) |
Ejemplo IHDR para PNG RGBA 256×256:
00 00 01 00 (ancho = 256)
00 00 01 00 (alto = 256)
08 (8 bits por muestra)
06 (tipo de color 6 = RGBA)
00 (compresión deflate)
00 (filtrado adaptativo)
00 (sin entrelazado)
Tipos de Color: Indexado, RGB, Escala Grises, Alfa
PNG soporta múltiples modos de codificación de color:
| Tipo | Nombre | Canales | Profundidades de Bit | Caso de Uso |
|---|---|---|---|---|
| 0 | Escala Grises | 1 | 1, 2, 4, 8, 16 | Monocromático, escaneo |
| 2 | Color Verdadero (RGB) | 3 | 8, 16 | Fotos, gráficos (sin alfa) |
| 3 | Indexado (Paleta) | 1 | 1, 2, 4, 8 | Gráficos con colores limitados |
| 4 | Escala Grises + Alfa | 2 | 8, 16 | Monocromático con transparencia |
| 6 | RGBA | 4 | 8, 16 | Color completo con transparencia |
Indexado (Tipo 3) — usando chunk PLTE:
IHDR: tipo de color 3, profundidad de bit 8
Chunk PLTE (256×3 bytes):
[R0 G0 B0] [R1 G1 B1] … [R255 G255 B255]
Chunk tRNS (opcional, hasta 256 bytes):
[Alfa0] [Alfa1] … [Alfa255]
IDAT: valores de píxel 0–255 como índices en paleta
Típicamente 30–50% más pequeño que RGB para gráficos con ≤256 colores.
RGBA (Tipo 6):
IHDR: tipo de color 6, profundidad de bit 8
Escanlines IDAT: [R1 G1 B1 A1] [R2 G2 B2 A2] … por píxel
RGB completo de 24 bits + canal alfa de 8 bits, 4 bytes por píxel.
Escanlines y Filtrado: Predicción Adaptativa
PNG no almacena datos de píxeles crudos. En su lugar, cada escanline se filtra mediante uno de 5 tipos de filtro para reducir entropía:
[Tipo de filtro] [datos filtrados para fila]
Tipos de filtro:
| Tipo | Nombre | Fórmula | Propósito |
|---|---|---|---|
| 0 | Ninguno | salida = píxel | Sin filtrado (línea base) |
| 1 | Sub | salida = píxel - IZQUIERDA | Explota correlación horizontal |
| 2 | Arriba | salida = píxel - ARRIBA | Explota correlación vertical |
| 3 | Promedio | salida = píxel - (IZQUIERDA + ARRIBA) / 2 | Predicción basada en promedio |
| 4 | Paeth | salida = píxel - PaethPredictor(IZQUIERDA, ARRIBA, ARRIBAIZQUIERDA) | Predicción direccional |
Predictor Paeth: selecciona IZQUIERDA, ARRIBA o ARRIBAIZQUIERDA basado en cuál es más cercano a su promedio—elimina artefactos diagonales en imágenes naturales.
Ejemplo (filtro Sub en línea horizontal):
Píxeles crudos: [10] [15] [20] [30] [50]
Después de filtro Sub: [10] [5] [5] [10] [20] (cada píxel menos vecino izquierdo)
Tamaño comprimido: ~2 bytes (patrones repetidos se comprimen mejor)
PNG codifica el tipo de filtro para cada escanline, permitiendo que un codificador elija el mejor filtro por fila.
Compresión: Algoritmo Deflate
PNG usa zlib (deflate) en escanlines filtrados:
- Ventana deslizante LZ77: encuentra secuencias de bytes repetidas (hasta 32 KB)
- Codificación Huffman: codifica símbolos frecuentes con menos bits
- Ratio de compresión: típicamente 30–50% en gráficos, 10–20% en fotos
Niveles de compresión (parámetro del codificador PNG):
- Nivel 1: Rápido, compresión pobre (~25% reducción)
- Nivel 6: Predeterminado (buen balance)
- Nivel 9: Lento, mejor compresión (~40% reducción)
Entrelazado: Adam7 para Visualización Progresiva
El entrelazado Adam7 renderiza PNG progresivamente en 7 pasadas:
Pasada 1: píxeles en (x mod 8 == 0, y mod 8 == 0) — 12.5% de píxeles
Pasada 2: píxeles en (x mod 8 == 4, y mod 8 == 0) — 12.5%
Pasada 3: píxeles en (x mod 8 == 0, y mod 8 == 4) — 12.5%
Pasada 4: píxeles en (x mod 8 == 4, y mod 8 == 4) — 12.5%
Pasada 5: píxeles en (x mod 8 == 2, y mod 8 == 0 | 4) — 25%
Pasada 6: píxeles en (x mod 8 == 0 | 4, y mod 8 == 2 | 6) — 12.5%
Pasada 7: píxeles restantes — 12.5%
Resultado: vista previa aproximada visible después de pasada 1, refinada progresivamente. Compensación: ~25% archivo más grande vs. PNG no entrelazado.
Chunks Auxiliares: Perfiles de Color, Metadatos, Gamma
gAMA (Gamma):
Chunk gAMA: 4 bytes
valor = 100000 representa gamma 2.2 (estándar)
Aplica ley de potencia: mostrado = lineal ^ (1/gamma)
Corrige para brillo del monitor (no ampliamente usado en flujos de trabajo de color administrado modernos).
cHRM (Cromaticidad): Define las primarias de color (rojo, verde, azul, punto blanco) para reproducción de color precisa en pantallas.
iCCP (Perfil de Color ICC):
[nombre de perfil terminado en nulo] [tipo de compresión] [perfil ICC comprimido con zlib]
Incrusta espacio de color sRGB/Adobe RGB/ProPhoto RGB. Habilita color preciso en pantallas administradas por color.
tIME (Marca de Tiempo):
2 bytes año, 1 byte mes/día/hora/minuto/segundo
Formato: YYYYMMDDhhmmss
tEXt (Metadatos de Texto):
[palabra clave terminada en nulo] [cadena de texto]
Ejemplo: "Autor\0Juan Pérez"
Soporta múltiples chunks tEXt para comentarios, copyright, etc.
iTXt (Texto Internacional): Metadatos de texto UTF-8 con compresión opcional.
Comparación de Calidad PNG vs. Competidores
| Métrica | PNG (8-bit) | JPEG (Q85) | WebP-L | AVIF-L |
|---|---|---|---|---|
| Tamaño de archivo (foto) | 300 KB | 100 KB | 220 KB | 180 KB |
| Tamaño de archivo (gráfico) | 50 KB | 150 KB | 40 KB | 35 KB |
| Transparencia | ✅ | ❌ | ✅ | ✅ |
| Entrelazado | ✅ | ❌ | ❌ | ❌ |
| Animación | ❌ | ❌ | ✅ | ❌ |
| Soporte de navegadores | 100% | 100% | 97% | 82% |
| Velocidad de codificación | Rápida | Media | Media | Lenta |
PNG es ideal para gráficos; JPEG para fotos; WebP como fallback moderno.
Flujo de Trabajo Práctico de Optimización PNG
Para gráficos (logos, iconos):
- Usar color indexado (Tipo 3) con hasta 256 colores
- Entrelazar solo si archivo es <50 KB (compensación no vale para archivos pequeños)
- Comprimir con nivel 9
Para fotos:
- Usar RGBA (Tipo 6) sin entrelazar
- JPEG típicamente es más pequeño—considerar WebP para web
- PNG solo para archivo lossless o cuando transparencia sea necesaria
Optimización de ImageMagick:
convert entrada.jpg -quality 85 -colors 256 -depth 8 salida.png
convert entrada.png -quality 95 -strip salida-optimizada.png
Python (Pillow):
from PIL import Image
img = Image.open('entrada.jpg')
img = img.convert('RGB')
img.save('salida.png', 'PNG', optimize=True, compress_level=9)
La combinación de PNG de compresión lossless, soporte de transparencia alfa y cobertura universal de navegadores lo hace indispensable para gráficos web y flujos de trabajo profesionales.