Cheat Sheet Pillow: Como Automatizar Redimensionamento, Corte e Marca d'Água em Python


Aprenda a realizar o processamento em lote de imagens utilizando a biblioteca Pillow (PIL) no Python. Este snippet resolve o problema de otimização manual de imagens, aplicando redimensionamento proporcional, corte (crop) centralizado e inserção de marca d'água de forma automatizada em todas as imagens de um diretório.


Python
import os
from PIL import Image

def processar_imagem_em_lote(diretorio_entrada, diretorio_saida, tamanho_alvo=(800, 800), marca_dagua_path=None):
    # Cria o diretório de destino se não existir
    if not os.path.exists(diretorio_saida):
        os.makedirs(diretorio_saida)

    # Carrega a marca d'água uma única vez fora do loop
    img_marca = None
    if marca_dagua_path and os.path.exists(marca_dagua_path):
        img_marca = Image.open(marca_dagua_path).convert("RGBA")

    for arquivo in os.listdir(diretorio_entrada):
        if arquivo.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')):
            caminho_completo = os.path.join(diretorio_entrada, arquivo)
            
            with Image.open(caminho_completo) as img:
                # 1. Redimensiona mantendo o aspecto original
                img.thumbnail(tamanho_alvo)
                
                # 2. Corta (Crop centralizado para mantê-la quadrada)
                largura, altura = img.size
                menor_dimensao = min(largura, altura)
                left = (largura - menor_dimensao) / 2
                top = (altura - menor_dimensao) / 2
                right = (largura + menor_dimensao) / 2
                bottom = (altura + menor_dimensao) / 2
                
                img = img.crop((left, top, right, bottom))
                
                # 3. Aplica a marca d'água no canto inferior direito
                if img_marca:
                    img = img.convert("RGBA")
                    # Redimensiona a marca d'água para 20% do tamanho da imagem
                    tm_marca = int(img.width * 0.2)
                    marca_redim = img_marca.resize((tm_marca, tm_marca))
                    
                    pos_x = img.width - tm_marca - 10
                    pos_y = img.height - tm_marca - 10
                    
                    # O terceiro argumento usa o canal Alpha para transparência
                    img.paste(marca_redim, (pos_x, pos_y), marca_redim)

                # Salva a imagem final convertida em RGB para compatibilidade com JPG
                caminho_saida = os.path.join(diretorio_saida, f"processada_{arquivo}")
                img.convert("RGB").save(caminho_saida, "JPEG", quality=85)
                print(f"Sucesso: {arquivo} processado e salvo.")

# Exemplo de uso prático
if __name__ == "__main__":
    DIR_ENTRADA = "./imagens_originais"
    DIR_SAIDA = "./imagens_processadas"
    MARCA_DAGUA = "./logo_watermark.png"

    processar_imagem_em_lote(DIR_ENTRADA, DIR_SAIDA, tamanho_alvo=(800, 800), marca_dagua_path=MARCA_DAGUA)
  • Uso do thumbnail() vs resize(): O método thumbnail() altera as dimensões in-place mantendo a proporção de aspecto (aspect ratio) da imagem sem distorcê-la, enquanto o resize() força as dimensões exatas informadas.

  • Tupla no crop(): O método crop() exige uma tupla no formato (left, upper, right, lower). Atenção ao cálculo para garantir que a área cortada permaneça centralizada.

  • Tratamento do canal Alpha (Transparência): Para aplicar marcas d'água transparentes sem fundo preto, ambas as imagens precisam estar no modo RGBA. Ao usar paste(), passe a própria imagem com transparência como terceiro parâmetro para atuar como máscara (mask).

  • Conversão de Modo para Salvamento: Imagens editadas em modo RGBA devem ser convertidas de volta para RGB antes de salvar como JPEG, sob risco de exceção por incompatibilidade do formato.

  • Gerenciamento de Memória: O bloco with Image.open(...) garante o fechamento adequado dos arquivos de imagem a cada iteração do loop, prevenindo erros de vazamento de recursos no sistema operacional.

Comentários

Postagens mais visitadas deste blog

Gerando Relatórios em PDF com Python (ReportLab e FPDF)

Python para Computação Quântica: Introdução com Qiskit

C# e Banco de Dados: Como Conectar e Realizar Operações com SQL Server