WebP animado combina la compresión superior de WebP con soporte de animación, ofreciendo archivos un 30–80 % más pequeños que GIF equivalente con mejor calidad.
WebP animado vs GIF
| Característica | GIF | WebP animado |
|---|---|---|
| Colores máximos | 256 | Millones |
| Transparencia | 1 bit | Alfa completo |
| Compresión | Mala | Muy buena |
| Soporte navegadores | 100 % | 96 % |
| Tamaño vs GIF | 100 % | 30–60 % |
GIF → WebP con FFmpeg
ffmpeg -i animacion.gif animacion.webp
ffmpeg -i animacion.gif -quality 85 animacion.webp
ffmpeg -i animacion.gif -vf "scale=400:-1" -quality 80 animacion_400.webp
ffmpeg -i animacion.gif -loop 0 animacion.webp # bucle infinito
Vídeo → WebP animado
# MP4 → WebP animado (primeros 5 segundos a 15 fps)
ffmpeg -i video.mp4 -t 5 -vf "fps=15,scale=480:-1" -quality 80 clip.webp
# Segmento del segundo 10 al 15
ffmpeg -ss 10 -i video.mp4 -t 5 -vf "fps=12,scale=400:-1" -quality 80 seg.webp
Python con Pillow
from PIL import Image
def gif_a_webp(gif_path, webp_path, calidad=80):
with Image.open(gif_path) as gif:
frames, duraciones = [], []
try:
while True:
frames.append(gif.copy().convert('RGBA'))
duraciones.append(gif.info.get('duration', 100))
gif.seek(gif.tell() + 1)
except EOFError:
pass
frames[0].save(
webp_path, format='WEBP', save_all=True,
append_images=frames[1:], duration=duraciones,
loop=0, quality=calidad, method=6,
)
print(f"WebP: {webp_path} ({len(frames)} frames)")
gif_a_webp('animacion.gif', 'animacion.webp', calidad=82)
Crear desde frames individuales
from PIL import Image
from pathlib import Path
def frames_a_webp(directorio, salida, fps=12, calidad=80):
exts = {'.png', '.jpg', '.jpeg'}
rutas = sorted(f for f in Path(directorio).iterdir() if f.suffix.lower() in exts)
frames = [Image.open(r).convert('RGBA') for r in rutas]
ms = int(1000 / fps)
frames[0].save(
salida, format='WEBP', save_all=True,
append_images=frames[1:], duration=ms, loop=0, quality=calidad,
)
print(f"WebP: {salida} ({len(frames)} frames, {fps} fps)")
frames_a_webp('frames/', 'animacion.webp', fps=15)
Extraer frames de un WebP animado
from PIL import Image
with Image.open('animacion.webp') as webp:
n = getattr(webp, 'n_frames', 1)
print(f"Frames: {n}")
for i in range(n):
webp.seek(i)
webp.copy().save(f'frames/frame_{i:04d}.png')
Comparar tamaños
import os, subprocess
from pathlib import Path
def comparar(gif_path):
gif = Path(gif_path)
webp = gif.with_suffix('.webp')
subprocess.run(['ffmpeg', '-i', str(gif), '-quality', '80', str(webp), '-y'],
capture_output=True)
tam_gif = os.path.getsize(gif)
tam_webp = os.path.getsize(webp)
print(f"GIF: {tam_gif//1024} KB")
print(f"WebP: {tam_webp//1024} KB ({(1-tam_webp/tam_gif)*100:.0f}% menos)")
comparar('logo_animado.gif')
HTML con fallback
<picture>
<source srcset="animacion.webp" type="image/webp">
<img src="animacion.gif" alt="Animación" width="400" height="300">
</picture>
Cuándo usar WebP animado
- Sí: animaciones web, avatares, stickers, demos de producto
- No: contenido compartido por email (soporte limitado en clientes de correo)