La esencia de la compresión: expresar la misma información con menos datos
Antes de adentrarnos en la distinción entre compresión sin pérdida y compresión con pérdida, necesitamos entender qué hace realmente la compresión.
En su núcleo, la compresión trata de expresar la misma información con menos datos. Cualquier dato —ya sea texto, imágenes, audio o vídeo— contiene «redundancia». La redundancia se refiere a las partes que pueden eliminarse sin perder el significado de la información. El trabajo de un algoritmo de compresión es identificar y eliminar esta redundancia.
Consideremos un ejemplo sencillo. La cadena de caracteres AAAAABBBCC ocupa 10 bytes. Pero podemos representar la misma información de forma más compacta registrando «cada carácter y cuántas veces se repite consecutivamente», obteniendo 5A3B2C —solo 6 bytes. El tamaño de los datos cae un 40%, pero el significado es idéntico. Esta es la forma más primitiva de compresión, conocida como Run-Length Encoding (RLE).
Desde la perspectiva de la teoría de la información, Claude Shannon introdujo el concepto de «entropía de la información»: la longitud mínima media de codificación de un flujo de datos está limitada por su entropía. Ningún algoritmo sin pérdida puede romper este límite teórico. Esto significa que recomprimir datos ya comprimidos no produce casi ningún beneficio: la redundancia ya se ha eliminado.
Comprender esta esencia revela dos caminos técnicos fundamentalmente diferentes: la compresión sin pérdida busca una fidelidad perfecta, mientras que la compresión con pérdida descarta deliberadamente detalles que el ojo o el oído humano no pueden percibir fácilmente, intercambiándolos por una ratio de compresión mucho mayor.
Compresión sin pérdida: restaurar cada bit
La promesa central de la compresión sin pérdida es que los datos descomprimidos son idénticos byte a byte al original —ni un solo bit puede diferir. Estos algoritmos eliminan únicamente la «redundancia estadística» y la «redundancia estructural», sin tocar nunca el contenido semántico de la información.
DEFLATE: el algoritmo sin pérdida más utilizado
DEFLATE es el algoritmo subyacente de ZIP, gzip, zlib y muchas otras herramientas. Combina elegantemente dos técnicas clásicas:
- LZ77: utiliza una ventana deslizante para buscar subcadenas repetidas en los datos ya procesados, reemplazándolas por punteros «distancia + longitud». Por ejemplo, la palabra «compresión» que aparece repetidamente en un archivo de texto puede reemplazarse por una referencia hacia atrás a su primera aparición.
- Codificación de Huffman: aplica una codificación de longitud variable al flujo de símbolos producido por LZ77. Los símbolos frecuentes reciben códigos cortos; los símbolos raros reciben códigos largos. Esto acerca la codificación al límite de entropía.
Los puntos fuertes de DEFLATE son su simplicidad, velocidad y compatibilidad universal —casi todas las bibliotecas estándar de los lenguajes de programación incluyen una implementación.
LZMA: ratios más altas mediante modelado contextual
LZMA (Lempel-Ziv-Markov chain Algorithm) se basa en LZ77 con una ventana deslizante mucho mayor (hasta varios GB), un modelo de probabilidad más refinado y codificación por rangos. Comparado con DEFLATE, LZMA suele lograr ratios de compresión más altas, a costa de una velocidad de compresión más lenta y un mayor uso de memoria. El formato 7z se basa en LZMA.
La mejora clave de LZMA es que no depende de una tabla de probabilidad estática. En su lugar, predice dinámicamente la probabilidad del siguiente símbolo en función del contexto. Este «modelado contextual» acerca mucho más la codificación al límite teórico de entropía.
Filtrado PNG: preprocesamiento para datos de imagen
PNG es un formato de imagen sin pérdida, pero no aplica DEFLATE directamente a los valores de píxel en bruto. Antes de la compresión, PNG aplica un «filtro» a cada fila de píxeles para hacer los datos más favorables a DEFLATE.
Un filtro común almacena la diferencia entre cada píxel y su vecino de la izquierda, de arriba o de arriba a la izquierda. Dado que las imágenes naturales tienen píxeles localmente similares, estas diferencias tienden a agruparse alrededor de cero. Estos datos transformados tienen mayor redundancia, lo que permite a DEFLATE comprimirlos mucho más eficazmente.
Esto también explica por qué ZIP no puede comprimir eficazmente imágenes JPEG: JPEG ya está muy comprimido mediante DCT y codificación entrópica, sin dejar casi ninguna redundancia estadística que DEFLATE pueda explotar. Ejecutar ZIP sobre un JPEG suele añadir unos bytes de sobrecarga de cabecera sin ninguna reducción de tamaño.
Compresión con pérdida: el intercambio bajo el umbral de percepción
La idea central de la compresión con pérdida es que la percepción humana tiene límites. Si los detalles descartados caen bajo el umbral perceptivo, la diferencia visual o auditiva es insignificante —pero la reducción de datos puede ser enorme.
DCT: el fundamento matemático de JPEG
La Transformada Discreta del Coseno (DCT) es el corazón de la compresión de imágenes JPEG. Su papel es convertir una imagen del «dominio espacial» al «dominio de la frecuencia».
En el dominio espacial, una imagen se representa mediante los valores de brillo de los píxeles. En el dominio de la frecuencia, la imagen se descompone en una suma de componentes de ondas coseno a diferentes frecuencias: los componentes de baja frecuencia representan grandes zonas suaves, mientras que los de alta frecuencia representan bordes y detalles finos.
La DCT en sí es reversible y no pierde información. La «pérdida» real ocurre en el siguiente paso —la cuantización.
Cuantización: la fuente de la pérdida
La cuantización asigna los coeficientes DCT de alta precisión a un conjunto limitado de valores discretos. En la práctica, cada coeficiente se divide por un valor de una tabla de cuantización y luego se redondea a un entero. Como el ojo humano es menos sensible a los detalles de alta frecuencia, la tabla de cuantización aplica divisores mayores a los coeficientes de alta frecuencia, haciendo que muchos de ellos se conviertan en cero.
Este paso provoca una pérdida de información irreversible —una vez que un coeficiente se redondea a cero, no puede recuperarse. Pero también crea una enorme oportunidad de compresión: las largas secuencias de ceros pueden codificarse de forma muy eficiente con run-length encoding.
Diseñar la tabla de cuantización es un arte: los divisores mayores producen una compresión mayor pero una pérdida de calidad más visible. Esto es exactamente lo que controla el parámetro de calidad JPEG (por ejemplo, quality=80) —escala la tabla de cuantización hacia arriba o hacia abajo.
Predicción inter-fotogramas: la clave de la compresión de vídeo
La compresión de vídeo va un paso más allá de las imágenes fijas. Los fotogramas consecutivos de un vídeo suelen cambiar muy poco (por ejemplo, un fondo estático con una persona en movimiento), por lo que no es necesario almacenar cada fotograma por completo.
La predicción inter-fotogramas utiliza la «estimación de movimiento» para encontrar el desplazamiento entre el fotograma actual y un fotograma de referencia, almacenando solo «vectores de movimiento» y «residuos». Esta eliminación de la redundancia temporal permite que las ratios de compresión de vídeo alcancen cientos o incluso miles a uno —muy por encima de lo que la compresión de imágenes de un solo fotograma puede lograr.
Sin pérdida vs con pérdida: diagrama de comparación
El siguiente diagrama de flujo ilustra las ramas principales y las aplicaciones típicas de las dos familias de compresión:
Diagrama del principio de la DCT
El siguiente diagrama simplifica cómo la DCT transforma un bloque de píxeles de 8x8 del dominio espacial al dominio de la frecuencia, y luego conserva las frecuencias bajas mientras descarta las altas mediante cuantización:
Ejemplos de código
Compresión sin pérdida con zlib
import zlib
# Datos de texto originales con mucha repetición
original = b"compression compression compression " * 50
# Comprimir
compressed = zlib.compress(original, level=9)
print(f"Tamaño original: {len(original)} bytes")
print(f"Tamaño comprimido: {len(compressed)} bytes")
print(f"Ratio: {len(original) / len(compressed):.2f}x")
# Descomprimir y verificar que los datos son idénticos
decompressed = zlib.decompress(compressed)
assert decompressed == original, "¡Los datos no coinciden!"
print("Verificación superada: los datos descomprimidos son idénticos al original")
Al ejecutar este código, normalmente verá una ratio de compresión superior a 10x, y los datos descomprimidos son idénticos byte a byte al original. Esto es lo que significa «sin pérdida».
Compresión con pérdida con PIL
from PIL import Image
import io
# Crear una imagen de prueba rica en detalles de alta frecuencia
img = Image.new("RGB", (512, 512))
pixels = img.load()
for x in range(512):
for y in range(512):
# Generar un patrón con detalles de alta frecuencia
pixels[x, y] = ((x * 7) % 256, (y * 5) % 256, ((x + y) * 3) % 256)
# Guardar como PNG sin pérdida
img.save("test_lossless.png")
png_size = len(open("test_lossless.png", "rb").read())
print(f"Tamaño PNG (sin pérdida): {png_size} bytes")
# Guardar como JPEG con pérdida con calidad 20 para amplificar el efecto
buffer = io.BytesIO()
img.save(buffer, format="JPEG", quality=20)
jpeg_size = buffer.tell()
print(f"Tamaño JPEG (con pérdida): {jpeg_size} bytes")
print(f"Ratio: {png_size / jpeg_size:.2f}x")
# Recargar el JPEG y comparar las diferencias de píxeles
buffer.seek(0)
img_jpeg = Image.open(buffer)
diff_count = sum(
1 for x in range(512) for y in range(512)
if img.getpixel((x, y)) != img_jpeg.getpixel((x, y))
)
print(f"Píxeles modificados: {diff_count} / {512 * 512}")
print("Conclusión: la compresión JPEG altera los valores de píxeles de forma irreversible")
Este código demuestra la marca distintiva de la compresión con pérdida: un archivo más pequeño, pero con valores de píxeles modificados de forma irreversible.
Tabla comparativa
| Dimensión | Compresión sin pérdida | Compresión con pérdida |
|---|---|---|
| Principio fundamental | Elimina la redundancia estadística y estructural | Descarta información bajo el umbral de percepción |
| Fidelidad | 100% reversible, idéntico tras la descompresión | Irreversible, pérdida irrecuperable |
| Algoritmos típicos | DEFLATE, LZMA, Brotli, Zstandard | DCT+cuantización, wavelet, MDCT |
| Técnicas clave | LZ77, codificación de Huffman, codificación por rangos | Codificación por transformada, cuantización, predicción |
| Aplicaciones típicas | ZIP, GZIP, 7Z, PNG, FLAC | JPEG, WebP, H.264, MP3, AAC |
| Más adecuado para | Texto, código fuente, archivos, imagen médica | Fotos, vídeo, música, streaming |
| Ratio típica | Normalmente de 2x a 5x | Normalmente de 10x a 100x o superior |
| No adecuado para | Datos ya comprimidos (p. ej., archivos JPEG) | Datos que requieren reproducción exacta (p. ej., texto legal) |
Preguntas frecuentes
P1: ¿Por qué ZIP no puede comprimir una imagen JPEG?
Para cuando se crea un JPEG, ya ha pasado por DCT, cuantización y codificación entrópica. La redundancia estadística en los datos se ha eliminado casi por completo. DEFLATE no puede encontrar patrones de repetición explotables, por lo que ejecutar ZIP sobre un JPEG no solo no reduce el tamaño, sino que puede añadir unos bytes de sobrecarga de cabecera.
P2: ¿Es PNG siempre más grande que JPEG para la misma imagen?
No necesariamente. Para imágenes con grandes áreas de color sólido o una paleta limitada (como logotipos, iconos o capturas de pantalla), la combinación filtro-más-DEFLATE de PNG suele ser más pequeña que JPEG y conserva una calidad perfecta. Pero para fotografías naturales ricas en color, la combinación DCT-más-cuantización de JPEG suele lograr ratios de compresión superiores a 10x, haciéndola mucho más pequeña que PNG.
P3: ¿Se puede comprimir repetidamente el mismo archivo con un algoritmo sin pérdida?
No. Cada pasada de compresión sin pérdida acerca los datos a su límite de entropía. Tras la primera pasada, la redundancia desaparece en gran medida, y una segunda pasada casi no tiene nada que explotar —incluso puede crecer ligeramente debido a los metadatos añadidos. Por eso «comprimir un archivo ya comprimido» es inútil.
Resumen
La compresión sin pérdida y la compresión con pérdida no son bandos opuestos, sino opciones óptimas elegidas para diferentes características de la información:
- La compresión sin pérdida sirve a datos donde «ni un solo bit puede estar mal» —texto, código, archivos. Utiliza técnicas como LZ77 y la codificación de Huffman para eliminar la redundancia estadística garantizando una reconstrucción perfecta.
- La compresión con pérdida sirve a detalles «que el ojo y el oído no pueden percibir» —fotos, vídeo, música. Utiliza DCT, cuantización y predicción inter-fotogramas para hacer concesiones bajo el umbral de percepción, intercambiando una pérdida de información controlada por mejoras de un orden de magnitud en la ratio de compresión.
Comprender la diferencia fundamental entre estos dos caminos es la piedra angular para dominar toda la tecnología de compresión. En artículos posteriores, profundizaremos en las implementaciones algorítmicas específicas de cada camino, entendiendo la elegancia de la compresión línea a línea.
Lecturas relacionadas:
- Guía completa de compresión de archivos: principios y métodos de compresión PDF/imagen/vídeo/documento
- Principios y métodos de compresión PDF: cómo reducir eficazmente el tamaño de un PDF
- Guía de compresión de imágenes: comparación y selección de formatos JPG/PNG/WebP
¿Necesita comprimir archivos? Pruebe SmartSlim
Basado en un motor de compresión Rust de desarrollo propio, soporta más de 40 formatos en 10 categorías como PDF, imágenes, vídeo, Office y OFD. La compresión se realiza localmente y los datos no salen de su dominio.