web-dev-qa-db-ja.com

PILで円形のサムネイルを生成するにはどうすればよいですか?

PILを使用して円形の画像サムネイルを生成するにはどうすればよいですか?円の外側のスペースは透明でなければなりません。

スニペットをいただければ幸いです。よろしくお願いします。

42
ohnoes

それを行う最も簡単な方法は、マスクを使用することです。好きな形で白黒のマスクを作成します。 putalphaを使用して、その形状をアルファレイヤーとして配置します。

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')

これが私が使ったマスクです:

alt text


サムネイルのサイズを可変にする場合は、ImageDrawを使用してマスクを描画します。

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')

GIFで出力する場合は、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)

次の変更を行ったことに注意してください。

  • これでマスクが反転しました。白を黒に、またはその逆に置き換えました。
  • 「アダプティブ」パレットで「P」に変換しています。そうしないと、PILはWebセーフカラーのみを使用するため、結果が悪くなります。
  • 画像に透明度情報を追加しています。

注意してください:このアプローチには大きな問題があります。 GIF画像に黒い部分が含まれている場合、それらのすべても透明になります。透明度に別の色を選択することで、これを回避できます。これにはPNG形式を使用することを強くお勧めします。しかし、それができない場合は、それが最善の方法です。

74
Nadia Alramli

私はすでに受け入れられている回答に、結果の円をアンチエイリアスするソリューションを追加したいと思います。トリックは、より大きなマスクを作成し、ANTIALIASフィルターを使用してそれを縮小することです。ここにコードがあります

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)

これは私の意見でははるかに良い結果をもたらします。

29
DRC

すでに透過性のある画像もサポートするための@DRCのソリューションのわずかな変更。彼はアルファチャネルを円の外側で0(非表示)、内側で255(不透明)に設定しているので、マスクのminと元のアルファチャネル(_)を使用するdarkerを使用します( 0-255の間のどこでもかまいません):-)

from PIL import Image, ImageChops, ImageDraw

def crop_to_circle(im):
    bigsize = (im.size[0] * 3, im.size[1] * 3)
    mask = Image.new('L', bigsize, 0)
    ImageDraw.Draw(mask).ellipse((0, 0) + bigsize, fill=255)
    mask = mask.resize(im.size, Image.ANTIALIAS)
    mask = ImageChops.darker(mask, im.split()[-1])
    im.putalpha(mask)

im = Image.open('0.png').convert('RGBA')
crop_to_circle(im)
im.save('cropped.png')
1
xjcl