DP Tesela

Documentación de Tesela

Tesela es un formato de imagen con pérdida (y sin pérdida) escrito desde cero en Rust. A igual calidad perceptual ocupa menos que WebP, AVIF y JPEG XL en fotos, capturas de pantalla e ilustraciones, y se usa en la web gracias a un módulo de WebAssembly.

Admite transparencia, un modo sin pérdida exacto y una vista previa progresiva. El codificador y el decodificador son la misma base de código en nativo y en el navegador, y producen exactamente los mismos bytes.

Estado. La versión 1 del formato está congelada, con especificación y archivos de conformidad. La versión 2 (particiones rectangulares y nuevas tablas de probabilidad) es la que escribe el codificador por defecto y aún puede cambiar. Es un proyecto independiente y experimental: ningún navegador lo soporta de forma nativa.

Primeros pasos

Sin instalar nada

El comparador codifica tus fotos con Tesela, WebP, AVIF, JPEG XL y JPEG dentro del navegador y te muestra tamaño, calidad y un visor para compararlas. Nada sale de tu ordenador.

Con la línea de comandos

Necesitas Rust. Acepta PNG y JPEG.

git clone https://github.com/davidpalmerojara/FVD.git tesela
cd tesela
cargo build --release
./target/release/tesela encode foto.jpg foto.tsl -q 85        # comprimir
./target/release/tesela decode foto.tsl foto_decodificada.png # descomprimir
./target/release/tesela roundtrip foto.jpg -q 85              # tamaño y métricas en JSON

En Windows (PowerShell) el ejecutable es .\target\release\tesela.exe y compilar requiere las Build Tools de Visual Studio, que rustup ofrece instalar. En WSL basta con sudo apt install build-essential.

El comparador en local

python3 web/serve.py      # http://localhost:8000/compare/

Con serve.py, Tesela codifica con varios hilos también en el navegador (ver Servidor).

Uso en la web

Hay dos formas de mostrar imágenes .tsl. Las dos usan el mismo módulo de WebAssembly (tesela.wasm, ~630 KB, que se descarga una vez y queda en la caché).

Opción 1: HTML normal (recomendada)

<script src="/tesela-auto.js"></script>   <!-- en el <head> -->
<img src="foto.tsl" alt="Descripción">

Copia a la raíz de tu web tesela-auto.js, tesela-sw.js, tesela.wasm, tesela.js, tesela-core.js y tesela-worker.js. Un Service Worker entrega cada .tsl al navegador ya decodificado, así que funcionan <img>, srcset, <picture>, los fondos CSS y «Guardar imagen como».

Ver la demo con HTML normal.

Opción 2: elemento <tesela-img>

<script type="module" src="tesela.js"></script>
<tesela-img src="foto.tsl" alt="Descripción" fallback="foto.jpg" loading="lazy"></tesela-img>

Muestra la vista previa progresiva en cuanto llegan sus primeros bytes y, si algo falla, carga el fallback. Atributos: src, alt, fallback y loading="lazy". Ver la demo.

API de JavaScript

import { decode, encode, toObjectURL, decodePreview } from './tesela.js';

const imageData = await decode(bytes);                 // ArrayBuffer → ImageData
const tsl = await encode(imageData, { quality: 85 });  // ImageData → Uint8Array (.tsl)
const url = await toObjectURL(bytes);                  // URL para cualquier <img>
const preview = await decodePreview(firstBytes);       // vista previa, si ya ha llegado

Opciones de encode: quality (0–100, por defecto 75), effort (1–9, por defecto 4) y tune ('balanced', 'perceptual' o 'psnr'). Decodificar reparte las teselas de la imagen entre varios Web Workers.

Servidor

Línea de comandos

tesela encode <entrada.png|jpg|gif|webp> <salida.tsl> [opciones]   # GIF, APNG o WebP animado → animación
tesela decode <entrada.tsl> <salida.png|salida.gif|carpeta/>   # animaciones: GIF o un PNG por fotograma
tesela compare <original.png> <distorsionada.png>     # métricas en JSON
tesela roundtrip <entrada> [opciones de encode]         # codifica, decodifica, verifica y mide
OpciónEfecto
-q 1..100Calidad, en una escala parecida a la de JPEG: -q 85 se ve parecido a un JPEG de calidad 85.
-e 1..9Esfuerzo de búsqueda (por defecto 4). Los niveles 1–3 son modos rápidos: -e 3 codifica unas 2,5 veces más rápido y ocupa un 3 % más; -e 1, unas 5 veces más rápido y un 8 % más. Incluso con -e 1 comprime como AVIF.
--tune balanced|perceptual|psnrPerfil de ajuste: equilibrado, calidad visual o fidelidad numérica.
--losslessCompresión sin pérdida, exacta bit a bit.
--previewAñade la vista previa progresiva (~300 bytes).
--sin-metadatosNo guarda el perfil de color ni el EXIF. Por defecto se conservan, y la orientación EXIF se aplica a los píxeles.
--screen / --no-screenFuerza o desactiva las herramientas de contenido sintético (por defecto se detecta solo).
--threads NHilos del codificador (0 = todos). El resultado es idéntico con cualquier número.
--tile NTamaño de las teselas en píxeles (múltiplo de 64, por defecto 1024).
--v1Escribe la versión 1 (congelada) en lugar de la 2.
--420 / --444Fuerza el submuestreo de croma.

Cómo funciona

Tesela sigue la estructura clásica de los códecs modernos (predicción, transformada, cuantización y codificación entrópica), con decisiones tomadas por optimización tasa-distorsión: el codificador prueba alternativas y se queda con la que minimiza distorsión + λ·bits.

ContenedorCabecera de 23 bytes y teselas independientes de 1024×1024, que se codifican y decodifican en paralelo. Dentro de cada tesela, el codificador decide los superbloques en frente de onda con varios hilos.
ColorYCbCr con croma 4:2:0, o 4:4:4 en calidades muy altas y en contenido sintético.
ParticiónSuperbloques de 64×64 en un quadtree hasta 4×4; cada nodo puede partirse también en dos mitades rectangulares.
PredicciónPlanar, DC y 33 direcciones, con filtrado de referencias. La croma puede predecirse desde la luma (CCLM).
TransformadaDCT-II ortonormal de 4 a 64 puntos, también rectangular.
CuantizaciónMatriz perceptual, cuantización adaptativa por zonas y RDOQ.
EntropíaCodificador aritmético binario con modelos adaptativos y probabilidades iniciales entrenadas por tipo de contenido y calidad.
RestauraciónFiltro adaptativo por clases (estilo ALF) que el codificador estima por mínimos cuadrados.
Contenido sintéticoPaleta, copia intra de bloques con índice hash y residuo sin transformada.
ExtrasCanal alfa sin pérdida, modo sin pérdida, vista previa progresiva y metadatos: perfil de color ICC (por ejemplo, Display P3 de las fotos de móvil) y EXIF.
AnimaciónCada fotograma guarda solo el rectángulo que cambia, y cada bloque puede predecirse del fotograma anterior con un vector de movimiento de cuarto de píxel o con el movimiento global del fotograma (paneos y zooms). Una terminal de 90 fotogramas ocupa 7 KB (en GIF, 242 KB; en WebP animado, 140 KB).

El diario de experimentos del repositorio recoge qué se probó, cuánto aportó cada técnica y qué se descartó (por ejemplo, la cuantización dependiente de VVC no mejoró los resultados).

Resultados

Medimos el BD-rate frente a WebP: el porcentaje medio de bytes que ahorra cada formato a igual calidad (negativo = mejor), con SSIMULACRA2 como métrica principal de calidad perceptual. Todas las salidas se miden con el mismo programa, y las probabilidades de Tesela se entrenaron con imágenes distintas de las de evaluación.

ConjuntoTeselaAVIFJPEG XLWebP
Fotos · CLIC 2020, 41 profesionales de 2,2 MP−35,9 %−29,6 %−22,2 %0 %
Fotos · Kodak, 24 de 768×512−30,7 %−26,3 %−12,1 %0 %
Fotos grandes · DIV2K, 50 de 2,7 MP−35,1 %−34,4 %−20,3 %0 %
Capturas de pantalla · 9−60,1 %−54,3 %−36,0 %0 %
Ilustraciones · 6−61,8 %−56,0 %+9,5 %0 %

Versiones: AVIF con libavif 1.4 y aom (speed 4, 4:4:4), JPEG XL con libjxl 0.12 (effort 7), WebP con libwebp 1.6 (método 6). En fotos grandes con calidad baja, Tesela y AVIF empatan; la ventaja está en calidad media y alta. Codificar con Tesela es más lento que con AVIF; decodificar, unas 3 veces más rápido en fotos.

Curvas de calidad frente a bits por píxel en Kodak
Kodak
Curvas en fotos grandes
Fotos grandes
Curvas en capturas de pantalla
Capturas
Curvas en ilustraciones
Ilustraciones

Informes completos con todas las métricas (SSIMULACRA2, PSNR, SSIM) y datos crudos en bench/results. El banco de pruebas es reproducible: python3 bench/bench.py.

Especificación

Cada archivo lleva su versión en la cabecera: un .tsl v1 seguirá abriéndose con cualquier versión posterior del decodificador.

Preguntas frecuentes

¿Por qué otro formato de imagen?
Para explorar cuánto se puede mejorar hoy partiendo de cero, con técnicas de los códecs de vídeo modernos y un banco de pruebas honesto. El resultado ocupa menos que los formatos actuales en todos los tipos de contenido probados.
¿Funciona en todos los navegadores?
En todos los modernos (Chrome, Edge, Firefox, Safari, también en móvil), porque se decodifica con WebAssembly. No hay soporte nativo, así que conviene servir también un JPEG como respaldo.
¿Los visitantes pueden guardar las imágenes?
Sí. Con tesela-auto.js el navegador recibe la imagen ya decodificada y «Guardar imagen como» funciona como siempre. Como cualquier imagen de la web, no hay protección contra copias.
¿Por qué codifica más lento que AVIF?
Porque prueba muchas más particiones y predicciones para ahorrar bytes. Usa todos los núcleos, y una imagen se codifica una vez y se decodifica miles. Para cuando importa la velocidad están los modos rápidos: con -e 3 comprime más que AVIF y codifica 2,5 veces más rápido; con -e 1, empata con AVIF y es 5 veces más rápido.
¿Y el modo sin pérdida?
Es exacto bit a bit y mejora a PNG con claridad, pero en fotos ocupa más que WebP sin pérdida y que JPEG XL.
¿Qué limitaciones tiene?
8 bits por canal, sin HDR, y el alfa siempre es sin pérdida. En animación, Tesela gana a AVIF animado en capturas, interfaces, movimiento de cámara y objetos en movimiento, pero en zooms largos AVIF ocupa un 9-18 % menos. El perfil de color se respeta con tesela-auto.js; el elemento <tesela-img> pinta en sRGB. Es un proyecto experimental, sin una auditoría de patentes.
¿Cómo se ha medido?
Con curvas de calidad para cada formato en conjuntos públicos (Kodak, DIV2K) y propios (capturas e ilustraciones generadas), integradas con BD-rate. La metodología y los datos crudos están en el repositorio.

Descargas