Cómo redimensionar imágenes con Pillow en Python

Publicado el: 11/07/2026
Tempo de leitura: 4 minutos
Redimensionamento de imagens com Pillow em Python

Redimensionar imágenes es una tarea frecuente en automatización, comercio electrónico, blogs, aplicaciones web y procesamiento de datos. Con Pillow, la biblioteca de imágenes más utilizada en Python, puedes cambiar dimensiones, conservar proporciones, crear miniaturas, convertir formatos y procesar carpetas completas sin depender de programas gráficos.

Para complementar este tutorial, consulta las guías sobre archivos en Python, listas, funciones, try y except y automatización de tareas. Como referencias externas, revisa la documentación oficial de Pillow Image y la documentación oficial de pathlib.

Instalar Pillow

python -m pip install Pillow

El nombre del paquete es Pillow, pero la importación utiliza PIL por compatibilidad histórica:

from PIL import Image

Instálalo dentro de un entorno virtual para evitar conflictos entre proyectos.

Abrir una imagen

from PIL import Image

with Image.open("foto.jpg") as imagen:
    print(imagen.size)
    print(imagen.mode)
    print(imagen.format)

size devuelve una tupla con ancho y alto. mode describe los canales, por ejemplo RGB o RGBA, y format identifica JPEG, PNG u otro formato detectado.

Redimensionamiento básico

from PIL import Image

with Image.open("foto.jpg") as imagen:
    nueva = imagen.resize((800, 600))
    nueva.save("foto-800x600.jpg", quality=90)

resize() crea una imagen nueva. En este ejemplo se fuerza una proporción de 4:3. Si el archivo original tiene otra proporción, el contenido quedará estirado o comprimido.

Conservar la relación de aspecto

Para mantener la proporción, calcula la nueva altura a partir del ancho:

def redimensionar_por_ancho(imagen, ancho_objetivo):
    ancho, alto = imagen.size
    proporcion = ancho_objetivo / ancho
    alto_objetivo = round(alto * proporcion)
    return imagen.resize((ancho_objetivo, alto_objetivo), Image.Resampling.LANCZOS)

LANCZOS ofrece buena calidad cuando reduces fotografías. Pillow también dispone de otros filtros, como NEAREST, BILINEAR y BICUBIC.

Crear miniaturas

El método thumbnail() modifica la imagen para que quepa dentro de un cuadro máximo sin deformarla:

with Image.open("foto.jpg") as imagen:
    imagen.thumbnail((400, 400), Image.Resampling.LANCZOS)
    imagen.save("miniatura.jpg", quality=88)

Una imagen de 1200 por 800 terminaría en 400 por 267. Ninguna dimensión supera el límite indicado.

resize() frente a thumbnail()

Usa resize() cuando necesitas dimensiones exactas y controlas el cálculo de proporción. Usa thumbnail() cuando quieres encajar la imagen dentro de un tamaño máximo. Recuerda que thumbnail() modifica el objeto actual, mientras que resize() devuelve uno nuevo.

Recortar para dimensiones exactas

En ocasiones necesitas una miniatura cuadrada sin deformación. Primero ajusta la imagen para cubrir el área y después recorta el centro:

from PIL import Image, ImageOps

with Image.open("foto.jpg") as imagen:
    cuadrada = ImageOps.fit(
        imagen,
        (500, 500),
        method=Image.Resampling.LANCZOS,
        centering=(0.5, 0.5),
    )
    cuadrada.save("foto-cuadrada.jpg", quality=90)

ImageOps.fit() evita franjas vacías y conserva la proporción, aunque elimina parte de los bordes.

Procesar transparencia

PNG puede incluir un canal alfa. JPEG no admite transparencia. Si conviertes una imagen RGBA directamente a JPEG, puedes recibir un error:

with Image.open("logo.png") as imagen:
    if imagen.mode in {"RGBA", "LA"}:
        fondo = Image.new("RGB", imagen.size, "white")
        alfa = imagen.getchannel("A")
        fondo.paste(imagen, mask=alfa)
        fondo.save("logo.jpg", quality=90)

El fondo blanco reemplaza las áreas transparentes antes de guardar.

Corregir orientación EXIF

Las fotografías de móviles pueden guardar la orientación en metadatos. Sin corrección, una imagen puede aparecer girada:

from PIL import Image, ImageOps

with Image.open("movil.jpg") as imagen:
    corregida = ImageOps.exif_transpose(imagen)
    corregida.thumbnail((1200, 1200), Image.Resampling.LANCZOS)
    corregida.save("movil-corregida.jpg", quality=90)

Aplica exif_transpose() antes del redimensionamiento.

Procesar una carpeta completa

from pathlib import Path
from PIL import Image, ImageOps, UnidentifiedImageError

ENTRADA = Path("imagenes-originales")
SALIDA = Path("imagenes-redimensionadas")
SALIDA.mkdir(parents=True, exist_ok=True)

EXTENSIONES = {".jpg", ".jpeg", ".png", ".webp"}

for ruta in ENTRADA.iterdir():
    if not ruta.is_file() or ruta.suffix.lower() not in EXTENSIONES:
        continue

    destino = SALIDA / f"{ruta.stem}-web.webp"

    try:
        with Image.open(ruta) as imagen:
            imagen = ImageOps.exif_transpose(imagen)
            imagen.thumbnail((1600, 1600), Image.Resampling.LANCZOS)
            imagen.save(destino, format="WEBP", quality=85, method=6)
    except (OSError, UnidentifiedImageError) as error:
        print(f"No se pudo procesar {ruta.name}: {error}")

El script filtra extensiones, crea la carpeta de salida, corrige orientación, conserva proporciones y convierte los resultados a WebP.

No sobrescribir originales

Durante las primeras pruebas, guarda siempre en otra carpeta. Sobrescribir imágenes originales puede causar pérdidas irreversibles, especialmente si reduces resolución o cambias compresión. Añade un modo de simulación para mostrar qué archivos serían procesados.

Evitar nombres duplicados

Dos carpetas distintas pueden contener archivos con el mismo nombre. Si recorres subdirectorios, conserva parte de la estructura original o genera un nombre único. Otra opción es comprobar si el destino ya existe:

if destino.exists():
    print(f"Omitido: {destino.name}")
    continue

Calidad y tamaño

En JPEG, una calidad entre 80 y 92 suele ofrecer un equilibrio razonable. Valores máximos producen archivos grandes sin una mejora visual proporcional. En WebP, prueba valores entre 75 y 90. La configuración ideal depende del tipo de imagen y del uso final.

Metadatos

Al guardar una imagen nueva, algunos metadatos pueden perderse. Esto puede ser beneficioso para privacidad, porque elimina información de cámara y ubicación, pero debes decidirlo conscientemente. Si necesitas conservar perfiles de color o datos EXIF, copia únicamente lo necesario.

Imágenes muy grandes

Pillow puede emitir advertencias ante imágenes con cantidades enormes de píxeles para proteger contra archivos maliciosos o bombas de descompresión. No desactives esa protección sin validar el origen, tamaño y memoria disponible.

Funciones reutilizables

def preparar_para_web(origen, destino, limite=(1600, 1600), calidad=85):
    with Image.open(origen) as imagen:
        imagen = ImageOps.exif_transpose(imagen)
        imagen.thumbnail(limite, Image.Resampling.LANCZOS)

        if imagen.mode not in {"RGB", "RGBA"}:
            imagen = imagen.convert("RGB")

        imagen.save(destino, format="WEBP", quality=calidad, method=6)

Separar la transformación en una función facilita pruebas, reutilización y cambios futuros.

Errores frecuentes

Los fallos más comunes son deformar la proporción, olvidar cerrar archivos, guardar RGBA como JPEG, ignorar EXIF, sobrescribir originales y utilizar rutas construidas manualmente. También es un error asumir que una extensión garantiza que el contenido es una imagen válida.

Pruebas recomendadas

Prueba imágenes horizontales, verticales, cuadradas, transparentes, con orientación EXIF, formatos diferentes y archivos corruptos. Comprueba que ninguna dimensión supere el límite, que las proporciones se mantengan y que los originales permanezcan intactos.

Conclusión

Pillow permite crear flujos completos de preparación de imágenes con pocas dependencias. Utiliza thumbnail() para límites máximos, ImageOps.fit() para recortes exactos y exif_transpose() para fotografías correctamente orientadas. Procesa los archivos en una carpeta separada, valida entradas y elige calidad mediante pruebas reales, no por valores máximos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Compactando arquivos ZIP automaticamente com Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear archivos ZIP con Python y zipfile

    Crea archivos ZIP con Python y zipfile: carpetas, filtros, arcname, compresión, contenido en memoria, verificación, hashes y backups seguros.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Como evitar KeyError usando defaultdict em Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    defaultdict en Python: evita KeyError y simplifica diccionarios

    Aprende defaultdict en Python para evitar KeyError, contar, agrupar, crear estructuras anidadas y compararlo con get, setdefault y Counter.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Copiando e movendo arquivos com Python usando shutil
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    Cómo copiar y mover archivos en Python con shutil

    Aprende shutil en Python para copiar, mover, eliminar y comprimir archivos y carpetas con validaciones, hashes, logs y modo simulación.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Monitoramento de pastas em tempo real com Python Watchdog
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    Watchdog en Python: monitoriza carpetas en tiempo real

    Aprende Watchdog en Python para monitorizar carpetas, filtrar eventos, evitar duplicados, esperar archivos completos y automatizar procesos seguros.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Instalação offline de pacotes Python sem internet
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    Cómo instalar paquetes de Python sin conexión a Internet

    Aprende a instalar paquetes de Python sin Internet con pip download, ruedas, requirements.txt, --no-index, hashes y repositorios internos.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Como acelerar código Python usando lru cache
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    lru_cache en Python: acelera funciones con caché

    Aprende lru_cache en Python: memoización, maxsize, cache_info, cache_clear, argumentos hashables, recursión y errores frecuentes.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026