Fri Jun 26 2026 20:00:00 GMT-0400 (北美东部夏令时间)

Comprimir Imagens em Python com Pillow, WebP e mozjpeg

Comprima imagens JPEG, PNG e WebP em Python usando Pillow, cwebp e mozjpeg. Inclua configurações de qualidade, loops de tamanho alvo e um script batch rápido.

Comprimir Imagens em Python com Pillow, WebP e mozjpeg

Última atualização: June 27, 2026

Você tem uma pasta de JPEGs no tamanho de câmera, um passo de build que os envia aos usuários e um orçamento de peso da página que continua explodindo. Comprimir esses arquivos manualmente em um editor de imagem não escala. Este guia mostra o Python exato que você precisa para encolher arquivos JPEG, PNG e WebP em um cronograma, em um job CI ou dentro de um manipulador de upload.

Resposta rápida: como comprimir imagens em Python?

Abra a imagem com Pillow e depois salve-a com as flags de formato corretas. Para fotos, salve como JPEG com quality=80, optimize=True e progressive=True. Para os menores arquivos modernos, salve como WebP com quality=80, method=6. Para gráficos planos e capturas de tela, mantenha PNG e passe optimize=True.

from PIL import Image

def compress_jpeg(src, dst, quality=80):
    img = Image.open(src)
    if img.mode in ("RGBA", "P"):
        img = img.convert("RGB")
    img.save(dst, "JPEG", quality=quality, optimize=True, progressive=True)

Essa função de quatro linhas já corta a maioria dos JPEGs de celular e DSLR em 40 a 70 por cento. O restante deste guia adiciona alvos de tamanho, WebP, mozjpeg e um batch runner para que você possa apontar para um diretório e ir embora.

O que você precisa antes de começar?

Você precisa do Python 3.9 ou mais recente e Pillow, o fork mantido do PIL. Pillow lida com JPEG, PNG e WebP nativamente em todas as plataformas comuns.

pip install Pillow

Para a menor saída, você também vai querer dois encoders de linha de comando que o Python possa chamar: cwebp do libwebp e cjpeg do mozjpeg.

brew install webp mozjpeg   # macOS; Linux: apt install webp, build mozjpeg

Verifique para que serve cada peça antes de escrever código:

  • Pillow lê e escreve todos os formatos e faz o redimensionamento.
  • cwebp produz os arquivos WebP mais compactos e expõe mais ajustes do que Pillow.
  • mozjpeg re-codifica JPEGs menores do que o padrão libjpeg usado pelo Pillow.
  • Um helper de relatórios para que cada execução imprima quantos bytes você economizou.

Aqui está o helper usado em todo este guia:

import os

def report(src, dst):
    before, after = os.path.getsize(src), os.path.getsize(dst)
    saved = (1 - after / before) * 100
    print(f"{before/1024:.0f} KB -> {after/1024:.0f} KB ({saved:.0f}% menor)")

Se você precisa apenas de uma compressão pontual e não quer instalar nada, o compressor de imagens baseado em navegador faz o mesmo trabalho para um punhado de arquivos.

Como comprimir um JPEG com Pillow?

As três flags que importam para JPEG são quality, optimize e progressive. quality controla quanto detalhe o encoder descarta. optimize=True executa uma segunda passagem para construir uma tabela Huffman menor. progressive=True reordena o arquivo para que ele pinte de cima para baixo em baixa resolução primeiro, o que parece mais rápido em conexões lentas e geralmente encolhe o arquivo um pouco mais.

Laptop em uma mesa de madeira mostrando código-fonte aberto em um editor

Escolha um valor de qualidade baseado onde a imagem será usada, não um único número global:

Valor de qualidade Uso típico O que esperar
90-95 Imagens heroicas, provas de impressão Próximo ao original, arquivos visivelmente maiores
75-85 A maioria das fotos da web O padrão seguro, grandes economias
60-70 Miniaturas e prévias Suavização visível em detalhes finos
Abaixo de 50 Evitar para fotos Artefatos blocados nas bordas

Um erro comum pega quase todo mundo: JPEG não tem canal alfa. Se você abrir uma captura de tela PNG com transparência e salvá-la diretamente como JPEG, o Pillow levanta cannot write mode RGBA as JPEG. A chamada convert("RGB") na função anterior achata a transparência em um fundo sólido primeiro, razão pela qual ela é executada antes de cada salvamento JPEG.

Comprimindo PNG e convertendo para WebP

PNG é sem perdas (lossless), então você não pode trocar qualidade por tamanho como faz com o JPEG. O que você pode fazer é rodar o otimizador do Pillow e, para qualquer coisa que seja realmente uma foto, mudar completamente o formato.

def compress_png(src, dst):
    Image.open(src).save(dst, "PNG", optimize=True, compress_level=9)

def to_webp(src, dst, quality=80):
    img = Image.open(src)
    img.save(dst, "WEBP", quality=quality, method=6)

method=6 diz ao encoder WebP para gastar mais tempo procurando um arquivo menor. É mais lento por imagem, mas vale a pena em um passo de build. Para uma foto que começou como um PNG de 2 MB, o WebP com qualidade 80 geralmente fica abaixo de 200 KB enquanto parece idêntico no tamanho normal de visualização. As próprias medições do Google colocam o WebP cerca de 25 a 35 por cento menor que JPEG comparável, conforme a documentação WebP.

Use esta tabela para escolher um formato em vez de adivinhar:

Conteúdo da fonte Melhor formato Por quê
Fotografia WebP ou JPEG Gradientes suaves comprimem bem com perdas (lossy)
Logo, ícone, UI plana PNG ou WebP lossless Bordas nítidas permanecem definidas
Captura de tela com texto PNG ou WebP lossless Evita texto embaçado de passes com perdas
Imagem precisando de transparência WebP ou PNG JPEG não pode armazenar um canal alfa

Se você ainda está decidindo entre formatos para um site inteiro, o detalhamento em WebP vs JPEG vs PNG cobre suporte a navegadores e os trade-offs com mais profundidade.

Atingindo um tamanho de arquivo alvo em um loop

"Deixar abaixo de 200 KB" é um requisito comum de ferramentas de email, marketplaces e limites de upload de CMS. Você não pode escolher um número de qualidade que atinja um alvo de bytes na primeira tentativa, porque a mesma qualidade produz tamanhos muito diferentes para uma foto movimentada versus uma plana. Faça um loop descendo da alta qualidade até cair abaixo do limite:

def compress_to_target(src, dst, target_kb=200, q=90, floor=35):
    img = Image.open(src).convert("RGB")
    while q >= floor:
        img.save(dst, "JPEG", quality=q, optimize=True, progressive=True)
        if os.path.getsize(dst) <= target_kb * 1024:
            return q
        q -= 5
    return q

O argumento floor interrompe o loop antes que a qualidade caia para o território de borrão. Se uma imagem não conseguir atingir o alvo acima do limite, a função ainda retorna para que você possa registrá-lo e redimensionar a imagem em vez de comprimir mais. Para orçamentos fixos de bytes como 100 KB ou 50 KB, o mesmo loop funciona; o guia em comprimir imagens sem perder qualidade explica quando redimensionar supera diminuir a qualidade.

Como encolher JPEGs com mozjpeg e cwebp?

Pillow salva JPEGs com o encoder padrão libjpeg. mozjpeg é um encoder drop-in da Mozilla que produz arquivos menores na mesma qualidade visual, geralmente 5 a 15 por cento a mais. Como Pillow não empacota ele, chame o binário cjpeg através de subprocess. O cjpeg do mozjpeg lê PPM de forma confiável, então achate a imagem com Pillow primeiro:

import subprocess

def mozjpeg(src, dst, quality=80):
    Image.open(src).convert("RGB").save("_tmp.ppm")
    subprocess.run(["cjpeg", "-quality", str(quality), "-progressive",
                    "-optimize", "-outfile", dst, "_tmp.ppm"], check=True)
    os.remove("_tmp.ppm")

Para WebP, chamar cwebp diretamente dá a você controles que Pillow não expõe, como -m 6 para esforço máximo e -sharp_yuv para bordas de cor mais limpas:

def cwebp(src, dst, quality=82):
    subprocess.run(["cwebp", "-q", str(quality), "-m", "6",
                    "-sharp_yuv", src, "-o", dst], check=True)

Veja como as opções se comparam para que você possa decidir o que instalar:

Ferramenta Melhor para Trade-off
Pillow Scripting geral, todos os formatos Não é o menor JPEG
mozjpeg Menor JPEG progressivo Binário extra, ida e volta PPM
cwebp (libwebp) Controle WebP mais apertado Binário separado para instalar
pillow-simd Redimensionamento mais rápido em servidores x86 Mais difícil de construir e fixar

O projeto mozjpeg documenta seu encoder e benchmarks no repositório mozjpeg, e a lista completa de opções de salvamento do Pillow está na referência de formatos de arquivo de imagem do Pillow.

Como comprimir uma pasta inteira rapidamente?

Uma única imagem é fácil. A tarefa real é um diretório com centenas. Redimensione qualquer coisa mais larga do que o necessário para seu layout, depois comprima e execute o trabalho através de threads para que uma pasta de 500 imagens termine em segundos em vez de minutos.

Desenvolvedor em estação de trabalho multi-monitor executando código usando fones de ouvido

from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def batch(in_dir, out_dir, quality=80, max_width=1920):
    out = Path(out_dir); out.mkdir(parents=True, exist_ok=True)
    files = [p for p in Path(in_dir).iterdir()
             if p.suffix.lower() in {".jpg", ".jpeg", ".png"}]
    def work(p):
        img = Image.open(p)
        if img.width > max_width:
            h = round(img.height * max_width / img.width)
            img = img.resize((max_width, h), Image.LANCZOS)
        img.convert("RGB").save(out / f"{p.stem}.jpg", "JPEG",
                                quality=quality, optimize=True, progressive=True)
    with ThreadPoolExecutor() as pool:
        list(pool.map(work, files))
    return len(files)

Algumas notas práticas de rodar isso em produção:

  1. Redimensione antes de comprimir. Servir uma foto de 6000 px para uma coluna de 1200 px desperdiça bytes que nenhuma configuração de qualidade pode recuperar.
  2. Pillow libera o GIL durante a codificação, então as threads dão um aumento real na velocidade aqui; você não precisa de multiprocessing para a maioria das pastas.
  3. Escreva em um diretório de saída separado para que uma execução ruim nunca sobrescreva seus originais.
  4. Use Image.LANCZOS para dimensionamento para baixo; ele mantém as bordas mais nítidas do que o filtro padrão.
  5. Registre cada arquivo com o helper report e mantenha os originais até ter inspecionado uma amostra.

Se o seu trabalho é recorrente em vez de pontual, os padrões em processamento em lote de imagens cobrem filas, retries e convenções de nomenclatura. Para um rodar sem código sobre um zip de arquivos, o batch tool e o image converter lidam com mudanças de formato sem um script.

Qual abordagem você deve escolher?

Combine o método ao trabalho em vez de sempre recorrer à ferramenta mais pesada:

  • Fotos da web em um passo de build: Pillow WebP com qualidade 80, ou cwebp com -m 6 quando você quer os últimos poucos por cento.
  • Um orçamento estrito de bytes: o loop compress_to_target, voltando a redimensionar quando o limite é atingido.
  • Pipelines JPEG legados que você não pode mudar: re-codifique a saída com mozjpeg para economias gratuitas.
  • Capturas de tela e diagramas: mantenha PNG com optimize=True, ou WebP lossless se seus navegadores suportarem.

Para a teoria por trás do motivo pelo qual essas configurações funcionam, o guia de compressão de imagens explica perdas (lossy) versus sem perdas (lossless) e como as tabelas de quantização afetam o resultado.

Erros e correções comuns

Um punhado de exceções conta pela maioria das execuções falhas:

  • cannot write mode RGBA as JPEG — chame img.convert("RGB") antes de salvar em JPEG.
  • Image.DecompressionBombError — Pillow protege contra imagens enormes; aumente o limite apenas para arquivos que você confia com Image.MAX_IMAGE_PIXELS = 200_000_000.
  • OSError: broken data stream — o arquivo de origem está truncado; defina ImageFile.LOAD_TRUNCATED_IMAGES = True para salvá-lo, depois baixe novamente quando possível.
  • Saída maior que a entrada — você re-salvou um JPEG já comprimido; comprima do original, não de uma exportação anterior.
  • Cores parecem lavadas — uma fonte CMYK foi salva sem conversão; chame convert("RGB") primeiro.
from PIL import Image, ImageFile
Image.MAX_IMAGE_PIXELS = 200_000_000
ImageFile.LOAD_TRUNCATED_IMAGES = True

Imagem em close-up detalhada de um python repousando sobre uma superfície perfurada.

Conclusão principal

Pillow lida com 90 por cento da compressão de imagens em Python com três flags JPEG e um salvamento WebP. Recorra a mozjpeg e cwebp quando precisar dos arquivos menores possíveis, envolva tudo no loop de tamanho alvo quando um orçamento de bytes for fixo, e passe uma pasta pela função batch threaded quando o volume crescer. Mantenha seus originais, redimensione antes de comprimir e imprima as economias em cada execução para que você sempre saiba o que o pipeline está realmente fazendo.

Use as ferramentas gratuitas enquanto segue o guia.

Imagem de capa de PNG para WebP: Como Converter e Reduzir Imagens PNG

Tue Mar 17 2026 20:00:00 GMT-0400 (北美东部夏令时间)

PNG para WebP: Como Converter e Reduzir Imagens PNG

Converta PNG para WebP para arquivos web menores. Quando o WebP sem perdas é melhor, quando o com perdas funciona, tamanhos reais medidos, e os comandos cwebp e Pillow com um fallback para PNG.