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

915,210

Solution 1

Define a maximum size. Then, compute a resize ratio by taking min(maxwidth/width, maxheight/height).

The proper size is oldsize*ratio.

There is of course also a library method to do this: the method Image.thumbnail.
Below is an (edited) example from the PIL documentation.

import os, sys
import Image

size = 128, 128

for infile in sys.argv[1:]:
    outfile = os.path.splitext(infile)[0] + ".thumbnail"
    if infile != outfile:
        try:
            im = Image.open(infile)
            im.thumbnail(size, Image.ANTIALIAS)
            im.save(outfile, "JPEG")
        except IOError:
            print "cannot create thumbnail for '%s'" % infile

Solution 2

This script will resize an image (somepic.jpg) using PIL (Python Imaging Library) to a width of 300 pixels and a height proportional to the new width. It does this by determining what percentage 300 pixels is of the original width (img.size[0]) and then multiplying the original height (img.size[1]) by that percentage. Change "basewidth" to any other number to change the default width of your images.

from PIL import Image

basewidth = 300
img = Image.open('somepic.jpg')
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
img.save('somepic.jpg')

Solution 3

I also recommend using PIL's thumbnail method, because it removes all the ratio hassles from you.

One important hint, though: Replace

im.thumbnail(size)

with

im.thumbnail(size,Image.ANTIALIAS)

by default, PIL uses the Image.NEAREST filter for resizing which results in good performance, but poor quality.

Solution 4

Based in @tomvon, I finished using the following (pick your case):

a) Resizing height (I know the new width, so I need the new height)

new_width  = 680
new_height = new_width * height / width 

b) Resizing width (I know the new height, so I need the new width)

new_height = 680
new_width  = new_height * width / height

Then just:

img = img.resize((new_width, new_height), Image.ANTIALIAS)

Solution 5

from PIL import Image

img = Image.open('/your image path/image.jpg') # image extension *.png,*.jpg
new_width  = 200
new_height = 300
img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('output image name.png') # format may what you want *.png, *jpg, *.gif
Share:
915,210
saturdayplace
Author by

saturdayplace

Updated on July 08, 2022

Comments

  • saturdayplace
    saturdayplace almost 2 years

    Is there an obvious way to do this that I'm missing? I'm just trying to make thumbnails.

  • tomvon
    tomvon over 15 years
    If you are using this script in Zope as an External method you will need the line "from PIL import Image" to avoid namespace clashes with Zope's "Image".
  • gnud
    gnud over 12 years
    Like it says, the example was from the pil documentation, and that example (still) doesn't use the antialias flag. Since it's probably what most people would want, though, I added it.
  • eugene
    eugene over 11 years
    PIL sets the height of the new image to the size given(128 here) and calculate the width to keep the aspect ratio. Is there a way to fix the width instead of height? maybe I'll ask this in separate question.
  • gnud
    gnud over 11 years
    @Eugene: try something like s= img.size(); ratio = MAXWIDTH/s[0]; newimg = img.resize((s[0]*ratio, s[1]*ratio), Image.ANTIALIAS)? (that's for floating point division though :)
  • mt88
    mt88 almost 9 years
    Does using the above guarantee that the final saved image will be 128x128?
  • Joshmaker
    Joshmaker over 8 years
    Note that ANTIALIAS is no longer preferred for users of the popular Pillow fork of PIL. pillow.readthedocs.org/en/3.0.x/releasenotes/…
  • Zacharious
    Zacharious over 8 years
    Your variables are all mixed up. Your post says resizing width, and then resizes height. And in the resize call, you are using the new_width for both height and width?
  • Mark
    Mark about 8 years
    To build on that, ANTIALIAS is not needed from Pillow 2.5 and above.
  • Mo Beigi
    Mo Beigi almost 8 years
    Suggested a fix for that @Zachafer
  • So S
    So S over 7 years
    The Python 3 documentation for PIL says that thumbnail only works if the resulting image is smaller than the original one. Because of that I would guess that using resize is the better way.
  • imrek
    imrek over 7 years
    This code gets me a 0 byte output file sompic.jpg. Why does this happen? I'm using Python 3.x
  • imrek
    imrek over 7 years
    – Update: the same happens in Python 2.7.
  • imrek
    imrek over 7 years
    I may have figured out. If you are saving a .jpeg, use img.save('sompic.jpg', 'JPEG').
  • Fred Wu
    Fred Wu about 7 years
    nit: there is no PIL.Image.ANTIALIAS option for resize, should actually be PIL.Image.LANCZOS, although they are both 1 in value, see pillow.readthedocs.io/en/3.1.x/reference/…
  • Jose Luis de la Rosa
    Jose Luis de la Rosa almost 7 years
    The solution provided by @tomvon worked better for me because included how to calculate the ratio
  • Daniel Möller
    Daniel Möller almost 7 years
    Differences between thumbnail and resize?
  • codezjx
    codezjx over 6 years
    By default PIL save() method is poor quality, you can use image.save(file_path, quality=quality_value) to change the quality.
  • Arpit Singh
    Arpit Singh about 6 years
    Can we crop the image in the same way?
  • gnud
    gnud about 6 years
    @ArpitSingh to crop, use the Image.crop method - pillow.readthedocs.io/en/3.1.x/reference/…
  • J'e
    J'e about 6 years
    @FredWu PIL.Image.ANTIALIAS is in PIL version 1.1.7. This comes with Anaconda3 v5.x
  • pnd
    pnd almost 6 years
    the docs say: In Pillow 2.5 the default filter for thumbnail() was changed from NEAREST to ANTIALIAS
  • Marc Maxmeister
    Marc Maxmeister over 5 years
    tested and WORKED with python 2.7.15, and also works with 'PNG' files without need for editing
  • Anytoe
    Anytoe almost 5 years
    resize_contain looks actually quite useful!
  • burny
    burny over 4 years
    This does not keep the aspect ratio of the source image. It forces the image to 200x300 and will result in a squeezed or stretched image.
  • burny
    burny over 4 years
    With this, you can only decrease the size of an image. It is not possible to increase the size with Image.thumbnail.
  • Black Thunder
    Black Thunder over 4 years
    Better convert them to integer
  • AMC
    AMC over 4 years
    This does not answer the question in any way.
  • Ronen Ness
    Ronen Ness over 4 years
    This rotate some images (more info and solution here stackoverflow.com/questions/4228530/…)
  • Anthony
    Anthony about 4 years
    What is display() and where is it located?
  • Qinjie
    Qinjie almost 4 years
    @Anthony, display() is an iPython function and can be used in Jupyter Notebook to display images.
  • max
    max almost 4 years
    Unfortunately, this does not answer to the question, which explicitly addresses the library PIL -- and it does not keep the aspect ratio!. Further, you may provide a sort description of your approach to explain your thoughts
  • Boz
    Boz about 3 years
    Could've just used .thumbnail from PIL, your solution doesn't work on increasing size, just decreasing.
  • Robin
    Robin over 2 years
    Got error : integer argument expected, got float
  • Robin
    Robin over 2 years
    Wrong answer for the op. The question was 'How do I resize an image using PIL and maintain its ASPECT RATIO?"
  • Robin
    Robin over 2 years
    This works fine. Instead of saving the image with a new name, can I pass it directly to a canvas or frame?
  • Robin
    Robin over 2 years
    I like the image.show()