Pillow: O que É e Como Funciona | Python Brasil
Aprenda Pillow em Python: abrir, manipular e salvar imagens, redimensionar, filtros, texto, thumbnails e boas praticas para processamento de imagens.
O que e Pillow?
Pillow e a biblioteca mais popular para processamento de imagens em Python. Ela e um fork moderno e ativamente mantido da PIL (Python Imaging Library) e suporta uma ampla variedade de formatos de imagem, incluindo JPEG, PNG, GIF, TIFF, BMP e WebP. Com Pillow, voce pode abrir, manipular, transformar e salvar imagens de forma programatica.
Pillow e usada em aplicacoes web para redimensionar imagens de upload, gerar thumbnails, aplicar marcas dagua, converter entre formatos e criar graficos simples.
Instalacao e Operacoes Basicas
# Instalacao
# pip install Pillow
from PIL import Image
# Abrir uma imagem
img = Image.open('foto.jpg')
print(f'Formato: {img.format}') # JPEG
print(f'Tamanho: {img.size}') # (1920, 1080)
print(f'Modo: {img.mode}') # RGB
# Salvar em outro formato
img.save('foto.png')
img.save('foto.webp', quality=80)
# Mostrar a imagem (abre no visualizador padrao)
# img.show()
# Informacoes detalhadas
print(f'Largura: {img.width}')
print(f'Altura: {img.height}')
Redimensionamento e Recorte
from PIL import Image
img = Image.open('foto.jpg')
# Redimensionar (pode distorcer a proporcao)
redimensionada = img.resize((800, 600))
redimensionada.save('redimensionada.jpg')
# Redimensionar mantendo proporcao
img.thumbnail((800, 800)) # modifica in-place, mantendo aspecto
img.save('thumbnail.jpg')
# Redimensionar com proporcao usando calculo
largura_desejada = 800
proporcao = largura_desejada / img.width
nova_altura = int(img.height * proporcao)
redimensionada = img.resize((largura_desejada, nova_altura), Image.LANCZOS)
# Recortar (crop) — (esquerda, topo, direita, baixo)
recortada = img.crop((100, 100, 500, 400))
recortada.save('recortada.jpg')
# Recortar o centro da imagem
def recortar_centro(img, largura, altura):
"""Recorta a regiao central da imagem."""
esq = (img.width - largura) // 2
topo = (img.height - altura) // 2
dir = esq + largura
baixo = topo + altura
return img.crop((esq, topo, dir, baixo))
centro = recortar_centro(img, 400, 400)
centro.save('centro.jpg')
Rotacao e Transformacoes
from PIL import Image, ImageOps
img = Image.open('foto.jpg')
# Rotacao
rotacionada = img.rotate(45, expand=True, fillcolor='white')
rotacionada.save('rotacionada.jpg')
# Espelhamento
espelhada_h = img.transpose(Image.FLIP_LEFT_RIGHT)
espelhada_v = img.transpose(Image.FLIP_TOP_BOTTOM)
# Rotacoes de 90 graus
rotacionada_90 = img.transpose(Image.ROTATE_90)
rotacionada_180 = img.transpose(Image.ROTATE_180)
# Corrigir orientacao EXIF (fotos de celular)
img_corrigida = ImageOps.exif_transpose(img)
img_corrigida.save('corrigida.jpg')
Filtros e Ajustes
from PIL import Image, ImageFilter, ImageEnhance
img = Image.open('foto.jpg')
# Filtros
borrada = img.filter(ImageFilter.GaussianBlur(radius=5))
nitida = img.filter(ImageFilter.SHARPEN)
bordas = img.filter(ImageFilter.FIND_EDGES)
contornos = img.filter(ImageFilter.CONTOUR)
relevo = img.filter(ImageFilter.EMBOSS)
# Ajustes de brilho, contraste, cor e nitidez
brilho = ImageEnhance.Brightness(img).enhance(1.3) # 30% mais brilho
contraste = ImageEnhance.Contrast(img).enhance(1.5) # 50% mais contraste
saturacao = ImageEnhance.Color(img).enhance(0.5) # 50% menos saturacao
nitidez = ImageEnhance.Sharpness(img).enhance(2.0) # dobrar nitidez
# Converter para escala de cinza
cinza = img.convert('L')
cinza.save('cinza.jpg')
# Converter para preto e branco
pb = img.convert('1')
# Converter para RGBA (com transparencia)
rgba = img.convert('RGBA')
Adicionar Texto e Marca D’agua
from PIL import Image, ImageDraw, ImageFont
img = Image.open('foto.jpg')
draw = ImageDraw.Draw(img)
# Texto simples
draw.text((10, 10), 'Python Brasil', fill='white')
# Texto com fonte customizada
try:
fonte = ImageFont.truetype('arial.ttf', size=36)
except IOError:
fonte = ImageFont.load_default()
draw.text((50, 50), 'Titulo da Imagem', fill='white', font=fonte)
# Marca dagua semi-transparente
def adicionar_marca_dagua(img_path: str, texto: str, saida: str):
"""Adiciona marca dagua de texto a uma imagem."""
img = Image.open(img_path).convert('RGBA')
# Criar camada transparente
marca = Image.new('RGBA', img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(marca)
try:
fonte = ImageFont.truetype('arial.ttf', size=48)
except IOError:
fonte = ImageFont.load_default()
# Posicionar no canto inferior direito
bbox = draw.textbbox((0, 0), texto, font=fonte)
largura_texto = bbox[2] - bbox[0]
altura_texto = bbox[3] - bbox[1]
x = img.width - largura_texto - 20
y = img.height - altura_texto - 20
draw.text((x, y), texto, fill=(255, 255, 255, 128), font=fonte)
resultado = Image.alpha_composite(img, marca)
resultado.convert('RGB').save(saida)
adicionar_marca_dagua('foto.jpg', 'Python Brasil', 'com_marca.jpg')
Composicao de Imagens
from PIL import Image
# Combinar duas imagens lado a lado
def combinar_horizontal(img1_path: str, img2_path: str, saida: str):
img1 = Image.open(img1_path)
img2 = Image.open(img2_path)
# Ajustar alturas
altura = min(img1.height, img2.height)
img1 = img1.resize((int(img1.width * altura / img1.height), altura))
img2 = img2.resize((int(img2.width * altura / img2.height), altura))
largura_total = img1.width + img2.width
resultado = Image.new('RGB', (largura_total, altura))
resultado.paste(img1, (0, 0))
resultado.paste(img2, (img1.width, 0))
resultado.save(saida)
# Gerar thumbnails em lote
from pathlib import Path
def gerar_thumbnails(pasta_entrada: str, pasta_saida: str, tamanho=(200, 200)):
"""Gera thumbnails para todas as imagens de uma pasta."""
entrada = Path(pasta_entrada)
saida = Path(pasta_saida)
saida.mkdir(parents=True, exist_ok=True)
extensoes = {'.jpg', '.jpeg', '.png', '.webp'}
for arquivo in entrada.iterdir():
if arquivo.suffix.lower() in extensoes:
img = Image.open(arquivo)
img.thumbnail(tamanho, Image.LANCZOS)
img.save(saida / f'thumb_{arquivo.name}')
print(f'Thumbnail criado: {arquivo.name}')
Erros Comuns
O erro mais frequente e tentar salvar uma imagem RGBA como JPEG — o formato JPEG nao suporta transparencia. Converta para RGB antes com img.convert('RGB'). Outro erro e usar resize() sem manter a proporcao, distorcendo a imagem. Tambem e comum nao fechar imagens apos o uso, consumindo memoria em loops. Esquecer de instalar Pillow e importar PIL gera confusao, ja que o nome do pacote no pip difere do nome no import.
Boas Praticas
Use Image.LANCZOS como filtro de redimensionamento para melhor qualidade. Prefira thumbnail() quando quiser manter a proporcao. Feche imagens com img.close() ou use context managers. Especifique quality ao salvar JPEG para controlar tamanho do arquivo. Use o formato WebP para web por oferecer melhor compressao. Para processamento em lote, considere processar em paralelo com multiprocessing.
Quando Usar
Pillow e ideal para operacoes basicas e intermediarias de processamento de imagens: redimensionamento, recorte, conversao de formatos, filtros, texto e composicao. Para visao computacional e processamento avancado, considere OpenCV. Para manipulacao de imagens em conjunto com arrays NumPy, Pillow se integra bem atraves de numpy.array(img).