Como faço para gerar miniaturas circulares com PIL?
-
23-08-2019 - |
Pergunta
Como faço para gerar miniaturas de imagens circulares usando PIL? O espaço fora do círculo deve ser transparente.
Snippets seria muito apreciada, obrigado antecipadamente.
Solução
A maneira mais fácil de fazer isso é usando máscaras. Criar uma máscara preta e branca, com qualquer forma que você quiser. E uso putalpha
para colocar essa forma como uma camada alpha:
from PIL import Image, ImageOps
mask = Image.open('mask.png').convert('L')
im = Image.open('image.png')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
Aqui é a máscara que eu usei:
Se você quer o tamanho da miniatura para ser variável que você pode usar ImageDraw
e tirar a máscara:
from PIL import Image, ImageOps, ImageDraw
size = (128, 128)
mask = Image.new('L', size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + size, fill=255)
im = Image.open('image.jpg')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
Se você quiser a saída em GIF, então você precisa usar a função colar em vez de putalpha
:
from PIL import Image, ImageOps, ImageDraw
size = (128, 128)
mask = Image.new('L', size, 255)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + size, fill=0)
im = Image.open('image.jpg')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.paste(0, mask=mask)
output.convert('P', palette=Image.ADAPTIVE)
output.save('output.gif', transparency=0)
Note que eu fiz as seguintes alterações:
- A máscara é agora invertido. O branco foi substituído com preto e vice-versa.
- Eu estou convertendo em 'P' com uma paleta 'adaptativa'. Caso contrário, PIL só vai usar cores web-safe eo resultado vai ficar mal.
- eu estou adicionando informações de transparência para a imagem.
Por favor nota ??strong>: Existe um grande problema com esta abordagem. Se a imagem GIF continha peças pretas, todas elas se tornarão transparentes também. Você pode contornar isso escolhendo uma outra cor para a transparência. Eu recomendo fortemente que você use o formato PNG para isso. Mas se você não pode, então, que é o melhor que podia fazer.
Outras dicas
Eu gostaria de adicionar à resposta já aceitou uma solução para antialias o círculo resultante, o truque é produzir uma máscara maior e, em seguida, escalá-lo para baixo, usando um filtro AntiAlias: aqui está o código
from PIL import Image, ImageOps, ImageDraw
im = Image.open('image.jpg')
bigsize = (im.size[0] * 3, im.size[1] * 3)
mask = Image.new('L', bigsize, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + bigsize, fill=255)
mask = mask.resize(im.size, Image.ANTIALIAS)
im.putalpha(mask)
Isso produz um resultado muito melhor na minha opinião.