PIL: Thumbnail and end up with a square image
Asked Answered
E

7

57

Calling

image = Image.open(data)
image.thumbnail((36,36), Image.NEAREST)

will maintain the aspect ratio. But I need to end up displaying the image like this:

<img src="/media/image.png" style="height:36px; width:36px" />

Can I have a letterbox style with either transparent or white around the image?

Edris answered 6/9, 2009 at 18:33 Comment(0)
N
83

Paste the image into a transparent image with the right size as a background

from PIL import Image
size = (36, 36)
image = Image.open(data)
image.thumbnail(size, Image.LANCZOS)
background = Image.new('RGBA', size, (255, 255, 255, 0))
background.paste(
    image, (int((size[0] - image.size[0]) / 2), int((size[1] - image.size[1]) / 2))
)
background.save("output.png")

EDIT: fixed syntax error

Ninnyhammer answered 6/9, 2009 at 18:45 Comment(4)
UPDATE: use Image.ANTIALIAS instead of Image.NEAREST to get more quality and compressed image.Cap
NOTE: Be sure to use background.save() and not image.save()Letti
For Python 3 replace "/" with "//"Javelin
@Babu: Image.ANTIALIAS was deprecated in favor of Image.LANCZOS (#76616542). I updated the answers but cannot edit your comment.Ung
K
168

PIL already has a function to do exactly that:

from PIL import Image, ImageOps
thumb = ImageOps.fit(image, size, Image.LANCZOS)
Kylstra answered 12/12, 2011 at 4:25 Comment(8)
It was 2 years later... ;) This is a good answer for the question, the older answer is good to have too, in case you want to do something similar but not quite the sameNavigate
Sorry for the double post. For the sake of completeness: the first line above should read "from PIL import Image, ImageOps". (Assuming no other relevant imports elsewhere in the code.)Navigate
This method somehow cropping my image to fit into the resolution.Cap
That method does not apply transparency in my case. Is there any way to fix this?Generous
Using this method does NOT produce a square image with transparent padding.Letti
Why so many upvotes? This doesn't answer the question at all.Squamosal
it gets lots of upvotes because this question comes up high in a Google search for python pil resize and crop and this is an elegant solution for that, its irrelevance to the OP notwithstanding.Endosmosis
Or python PIL center image square, but this seem to crop it, indeed.Parasiticide
N
83

Paste the image into a transparent image with the right size as a background

from PIL import Image
size = (36, 36)
image = Image.open(data)
image.thumbnail(size, Image.LANCZOS)
background = Image.new('RGBA', size, (255, 255, 255, 0))
background.paste(
    image, (int((size[0] - image.size[0]) / 2), int((size[1] - image.size[1]) / 2))
)
background.save("output.png")

EDIT: fixed syntax error

Ninnyhammer answered 6/9, 2009 at 18:45 Comment(4)
UPDATE: use Image.ANTIALIAS instead of Image.NEAREST to get more quality and compressed image.Cap
NOTE: Be sure to use background.save() and not image.save()Letti
For Python 3 replace "/" with "//"Javelin
@Babu: Image.ANTIALIAS was deprecated in favor of Image.LANCZOS (#76616542). I updated the answers but cannot edit your comment.Ung
M
2
from PIL import Image

import StringIO

def thumbnail_image():
    image = Image.open("image.png")
    image.thumbnail((300, 200))
    thumb_buffer = StringIO.StringIO()
    image.save(thumb_buffer, format=image.format)
    fp = open("thumbnail.png", "w")
    fp.write(thumb_buffer.getvalue())
    fp.close()
Musil answered 28/7, 2016 at 8:30 Comment(1)
thumbnail won't force a square image. And what is the point of using StringIO?Whereas
E
2

Update of Cesar Canassa's answer.

This will create a thumbnail of image.jpg as image_thumb.jpg:

from PIL import Image, ImageOps
fname = 'image.jpg'
size = (48,48)
thumb = ImageOps.fit(Image.open(fname), size, Image.LANCZOS)
thumb.save('{}_thumb.jpg'.format(fname[:fname.rfind('.')]), "JPEG")
Elwira answered 24/10, 2019 at 8:47 Comment(0)
E
1

Or this, maybe... (forgive spaghetti)

from PIL import Image

def process_image(image, size):
    if image.size[0] > size[0] or image.size[1] > size[1]:
        #preserve original
        thumb = image.copy()
        thumb.thumbnail(size,Image.LANCZOS)
        img = thumb.copy()
    img_padded = Image.new("RGBA",size)
    img_padded.paste(image,(int((size[0]-image.size[0])/2),int((size[1]-image.size[1])/2)))
    return img_padded
Extremist answered 31/1, 2015 at 2:26 Comment(0)
B
0

you can wrap Nadia's answer in this function, which gives you control over size and background.

def make_square(im, min_size=36, fill_color=(255, 255, 255, 0)):
    x, y = im.size
    size = min(min_size, x, y)
    new_im = Image.new('RGBA', (size, size), fill_color)
    im.thumbnail((256, 256))
    new_im.paste(im, (int((x - size) / 2), int((y -size) / 2))
    return new_im
Bevel answered 20/11, 2018 at 3:32 Comment(0)
S
0

Why not simply use the resize method ?

from PIL import Image
image = Image.open('/path/to/img.png')
image = image.resize((36,36), Image.LANCZOS)

See recommendations for image resizing in this release note: https://pillow.readthedocs.io/en/stable/releasenotes/5.3.0.html

Subtangent answered 10/12, 2019 at 15:28 Comment(1)
Because it squishes the image.Whereas

© 2022 - 2024 — McMap. All rights reserved.