如何使用 PIL 生成圆形缩略图?

发布于 2024-07-21 07:40:19 字数 69 浏览 5 评论 0原文

如何使用 PIL 生成圆形图像缩略图? 圆圈外的空间应该是透明的。

片段将不胜感激,提前谢谢您。

How do I generate circular image thumbnails using PIL?
The space outside the circle should be transparent.

Snippets would be highly appreciated, thank you in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

呢古 2024-07-28 07:40:19

最简单的方法是使用面具。 创建一个具有任何您想要的形状的黑白蒙版。 并使用 putalpha 将该形状作为 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')

这是我使用的蒙版:

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 code>:

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 将仅使用网络安全颜色,结果看起来会很糟糕。
  • 我正在向图像添加透明度信息。

请注意:这种方法存在一个大问题。 如果 GIF 图像包含黑色部分,则所有黑色部分也会变成透明。 您可以通过选择另一种透明度颜色来解决此问题。
我强烈建议您使用 PNG 格式。 但如果你做不到,那就是你能做的最好的事情了。

The easiest way to do it is by using masks. Create a black and white mask with any shape you want. And use putalpha to put that shape as an alpha layer:

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

Here is the mask I used:

alt text


If you want the thumbnail size to be variable you can use ImageDraw and draw the mask:

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

If you want the output in GIF then you need to use the paste function instead of 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 that I did the following changes:

  • The mask is now inverted. The white
    was replaced with black and vice versa.
  • I'm converting into 'P' with an 'adaptive' palette. Otherwise, PIL will only use web-safe colors and the result will look bad.
  • I'm adding transparency info to the image.

Please note: There is a big issue with this approach. If the GIF image contained black parts, all of them will become transparent as well. You can work around this by choosing another color for the transparency.
I would strongly advise you to use PNG format for this. But if you can't then that is the best you could do.

浮华 2024-07-28 07:40:19

我想在已经接受的答案中添加一个对结果圆进行抗锯齿的解决方案,技巧是生成一个更大的掩模,然后使用抗锯齿过滤器将其缩小:
代码。

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)

在我看来,这是产生更好结果的

I would like to add to the already accepted answer a solution to antialias the resulting circle, the trick is to produce a bigger mask and then scale it down using an ANTIALIAS filter:
here is the code

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)

this produces a far better result in my opinion.

謸气贵蔟 2024-07-28 07:40:19

对@DRC 的解决方案进行轻微修改,以支持已经具有透明度的图像。 他将圆外的 Alpha 通道设置为 0(不可见),将圆内设置为 255(不透明),因此我使用 darker 来获取蒙版和原始 Alpha 的 min频道(可以是 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')

Slight modification on @DRC's solution to also support images which already have transparency. He sets the alpha channel to 0 (invisible) outside the circle and to 255 inside (opaque), so I use darker which takes the min of the mask and the original alpha channel (which can be anywhere betwen 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')
朕就是辣么酷 2024-07-28 07:40:19

非常感谢。 我花了几个小时寻找,你的想法成功了。

与那里的其他脚本一起。
PIL 圆边并添加边框
它非常适合我。

from PIL import Image
from PIL import ImageDraw, ImageChops

def add_corners( im, rad=100):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
    alpha = Image.new('L', im.size, "white")
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))

    alpha = ImageChops.darker(alpha, im.split()[-1])

    im.putalpha(alpha)
    return im

im = Image.open ('AceOfSpades.png').convert('RGBA')

im = add_corners (im, 24)

im.show()
im.save("perfect.png")

将此图像命名为 AceOfSpades.png 用于测试

Thank you very much. I was looking for hours and your idea does the trick.

Together with this other script from there.
PIL round edges and add border
it works perfectly for me.

from PIL import Image
from PIL import ImageDraw, ImageChops

def add_corners( im, rad=100):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
    alpha = Image.new('L', im.size, "white")
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))

    alpha = ImageChops.darker(alpha, im.split()[-1])

    im.putalpha(alpha)
    return im

im = Image.open ('AceOfSpades.png').convert('RGBA')

im = add_corners (im, 24)

im.show()
im.save("perfect.png")

Name this image AceOfSpades.png for testing

凉世弥音 2024-07-28 07:40:19
from PIL import Image, ImageDraw, ImageFont
import requests
import io

# get a random image 
image_response = requests.get('https://source.unsplash.com/random/300x200')
image = Image.open(io.BytesIO(image_response.content))

# decorate the image
padding = 80
border_radius = 15
# get container size
container_size = (image.width + padding, image.height + padding *3)
# create a new image
container = Image.new('RGBA', container_size, (0, 0, 0, 0))

# create a draw object
draw = ImageDraw.Draw(container)
# draw a rounded rectangle
draw.rounded_rectangle((0, 0 ) + container_size, radius=border_radius, fill="green", outline=(0, 0, 0, 0))

# paste image in container at the center
container_width, container_height = container.size
image_width, image_height = image.size
x = (container_width - image_width) // 2
y = 30  # or any desired y-coordinate
container.paste(image,(x,y)) 

# add text
draw = ImageDraw.Draw(container)
text = "This is your #7 drive with RHA."
font = ImageFont.truetype("arial.ttf", 15)
# get text box size
text_box  = draw.textbbox((0, 0), text, font=font)
text_width, text_height = (text_box[2] - text_box[0]), (text_box[3] - text_box[1])
text_position = ((container.width - text_width) / 2, image.height + padding*2)
draw.text(text_position, text, font=font, fill="white", align='center')


# save the image
container.save('rounded_rect.png')
from PIL import Image, ImageDraw, ImageFont
import requests
import io

# get a random image 
image_response = requests.get('https://source.unsplash.com/random/300x200')
image = Image.open(io.BytesIO(image_response.content))

# decorate the image
padding = 80
border_radius = 15
# get container size
container_size = (image.width + padding, image.height + padding *3)
# create a new image
container = Image.new('RGBA', container_size, (0, 0, 0, 0))

# create a draw object
draw = ImageDraw.Draw(container)
# draw a rounded rectangle
draw.rounded_rectangle((0, 0 ) + container_size, radius=border_radius, fill="green", outline=(0, 0, 0, 0))

# paste image in container at the center
container_width, container_height = container.size
image_width, image_height = image.size
x = (container_width - image_width) // 2
y = 30  # or any desired y-coordinate
container.paste(image,(x,y)) 

# add text
draw = ImageDraw.Draw(container)
text = "This is your #7 drive with RHA."
font = ImageFont.truetype("arial.ttf", 15)
# get text box size
text_box  = draw.textbbox((0, 0), text, font=font)
text_width, text_height = (text_box[2] - text_box[0]), (text_box[3] - text_box[1])
text_position = ((container.width - text_width) / 2, image.height + padding*2)
draw.text(text_position, text, font=font, fill="white", align='center')


# save the image
container.save('rounded_rect.png')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文