48

Does PIL resize to the exact dimensions I give it no matter what? Or will it try to keep the aspect ratio if I give it something like the Image.ANTIALIAS argument?

arulmr
  • 8,620
  • 9
  • 54
  • 69
frederix
  • 1,662
  • 5
  • 18
  • 29

10 Answers10

74

Yes it will keep aspect ratio using thumbnail method:

image = Image.open(source_path)
image.thumbnail((500,500), Image.ANTIALIAS)
image.save(dest_path, "JPEG")
Pikamander2
  • 7,332
  • 3
  • 48
  • 69
Maksym Kozlenko
  • 10,273
  • 2
  • 66
  • 55
  • 6
    ANTIALIAS method name update: As of 2.7.0, all resize methods are ANTIALIAS & the real (new) name for the specific ANTIALIAS filter is LANCZOS. (Tho antialias is currently left for backwards compatibility) https://pillow.readthedocs.io/en/3.0.x/releasenotes/2.7.0.html#antialias-renamed-to-lanczos – hbrannan Feb 22 '19 at 04:56
  • 12
    Note thought that the thumbnail method isn't equivalent in other regards - it won't blow up images to larger than they were, and it acts on the image object and doesn't return anything. – kloddant Nov 14 '19 at 22:54
  • 3
    Also note, this function modifies the `Image` object in place. If you need to use the full resolution image as well, apply this method to a `copy()` of the original image, per the [docs](https://pillow.readthedocs.io/en/stable/reference/Image.html#Image.thumbnail). – Salvatore Mar 23 '22 at 18:28
24

How do I resize an image using PIL and maintain its aspect ratio?

Image.resize from PIL will do exactly as told. No behind scenes aspect ratio stuff.

Community
  • 1
  • 1
Kugel
  • 19,354
  • 16
  • 71
  • 103
  • the linked answer uses - im.thumbnail , is this suggested in general? Or just when working with thumbnails – baxx Apr 08 '21 at 10:12
17

Recent Pillow version (since 8.3) have the following method to have an image resized to fit in given box with keeping aspect ratio.

image = ImageOps.contain(image, (2048,2048))
fabien-michel
  • 1,873
  • 19
  • 38
9

No, it does not. But you can do something like the following:

im = PIL.Image.open("email.jpg"))
width, height = im.size
im = im.resize((width//2, height//2))

Here the height and width are divided by the same number, keeping the same aspect ratio.

Lahiru Karunaratne
  • 2,020
  • 16
  • 18
  • 3
    you need to assign the im back. im.resize is not modifying the original image. `im = im.resize((width//2, height//2))` – York Yang Aug 13 '20 at 09:35
7

Okay, so this requires a couple of lines of code to get what you want.

First you find the ratio, then you fix a dimension of the image that you want (height or width). In my case, I wanted height as 100px and let the width adjust accordingly, and finally use that ratio to find new height or new width.

So first find the dimensions:

width, height = logo_img.size
ratio = width / height
      

Then, fix one of the dimension:

new_height = 100

Then find new width for that height:

new_width = int(ratio * new_height)
            
logo_img = logo_img.resize((new_width, new_height))
  • I get an error when I try your solution. I get "_tkinter.TclError: image "" doesn't exist. Any idea? – Robin Feb 23 '22 at 05:06
  • @Robin can you post more information about it? Like how are you loading the image, is the extension or path right? – Shreyas Vedpathak Feb 23 '22 at 13:30
  • @ Shreyas. Thank you. I am not trying to save the file. I want it to load on a canevas. The canevas takes a portion of the monitor, so I cannot have the image pass the border of the frame. Your solution works when I save the file, but not if I want to use the resized file in a canevas. Any idea if it is possible to redirect the resized image to a canevas with our code? – Robin Feb 23 '22 at 22:31
7

Yes. the thumbnail() method is what is needed here... One thing that hasn't been mentioned in this or other posts on the topic is that 'size' must be either a list or tuple. So, to resize to a maximum dimension of 500 pixels, you would call: image.thumbnail((500,500), Image.ANTIALIAS)

See also this post on the subject: How do I resize an image using PIL and maintain its aspect ratio?

Community
  • 1
  • 1
Luke
  • 71
  • 1
  • 1
6

It depends on your demand, if you want you can set a fixed height and width or if you want you can resize it with aspect-ratio.

For the aspect-ratio-wise resize you can try with the below codes :

To make the new image half the width and half the height of the original image:

from PIL import Image
im = Image.open("image.jpg")
resized_im = im.resize((round(im.size[0]*0.5), round(im.size[1]*0.5)))
        
#Save the cropped image
resized_im.save('resizedimage.jpg')

To resize with fixed width and ratio wise dynamic height :

from PIL import Image
new_width = 300
im = Image.open("img/7.jpeg")
concat = int(new_width/float(im.size[0]))
size = int((float(im.size[1])*float(concat)))
resized_im = im.resize((new_width,size), Image.ANTIALIAS)
#Save the cropped image
resized_im.save('resizedimage.jpg')
Ruhul Amin
  • 821
  • 11
  • 14
4

Recent versions of Pillow have some useful methods in PIL.ImageOps.

Depending on exactly what you're trying to achieve, you may be looking for one of these:

  • ImageOps.fit(image, size [, …]) (docs) – resizes your image, maintaining its aspect ratio, and crops it to fit the given size

  • ImageOps.contain(image, size [, …]) (docs) – resizes your image, maintaining its aspect ratio, so that it fits within the given size

talljosh
  • 672
  • 9
  • 21
  • Thanks for sharing. Isn't `ImageOps.fit` the same as `Image.thumbnail`? – Crashalot Nov 16 '22 at 04:03
  • 1
    @Crashalot, `Image.thumbnail` is similar to `ImageOps.contain`. One main difference is that `Image.thumbnail` edits the image in-place whereas `ImageOps.contain` creates a new image. Also, the docs of `Image.thumbnail` says that the resulting thumbnail will be 'no larger than the given size'. I don't know if it's ever actually smaller than specified in practice though. – talljosh Nov 18 '22 at 00:52
1

One complete example:

import PIL.Image


class ImageUtils(object):
    @classmethod
    def resize_image(cls, image: PIL.Image.Image, width=None, height=None) -> PIL.Image.Image:
        if height is None and width is not None:
            height = image.height * width // image.width
        elif width is None and height is not None:
            width = image.width * height // image.height
        elif height is None and width is None:
            raise RuntimeError("At lease one of width and height must be present")
        return image.resize((width, height))


def main():
    ImageUtils.resize_image(PIL.Image.open("old.png"), width=100).save("new.png")


if __name__ == '__main__':
    main()

BaiJiFeiLong
  • 3,716
  • 1
  • 30
  • 28
-1

I think following is the easiest way to do:

Img1 = img.resize((img.size),PIL.Image.ANTIALIAS)
Salahuddin Ahmed
  • 4,854
  • 4
  • 14
  • 35