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

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

This question is related to python image python-imaging-library thumbnails

The answer is


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

Have updated the answer above by "tomvon"

from PIL import Image

img = Image.open(image_path)

width, height = img.size[:2]

if height > width:
    baseheight = 64
    hpercent = (baseheight/float(img.size[1]))
    wsize = int((float(img.size[0])*float(hpercent)))
    img = img.resize((wsize, baseheight), Image.ANTIALIAS)
    img.save('resized.jpg')
else:
    basewidth = 64
    wpercent = (basewidth/float(img.size[0]))
    hsize = int((float(img.size[1])*float(wpercent)))
    img = img.resize((basewidth,hsize), Image.ANTIALIAS)
    img.save('resized.jpg')

from PIL import Image
from resizeimage import resizeimage

def resize_file(in_file, out_file, size):
    with open(in_file) as fd:
        image = resizeimage.resize_thumbnail(Image.open(fd), size)
    image.save(out_file)
    image.close()

resize_file('foo.tif', 'foo_small.jpg', (256, 256))

I use this library:

pip install python-resize-image

If you are trying to maintain the same aspect ratio, then wouldn't you resize by some percentage of the original size?

For example, half the original size

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

Have updated the answer above by "tomvon"

from PIL import Image

img = Image.open(image_path)

width, height = img.size[:2]

if height > width:
    baseheight = 64
    hpercent = (baseheight/float(img.size[1]))
    wsize = int((float(img.size[0])*float(hpercent)))
    img = img.resize((wsize, baseheight), Image.ANTIALIAS)
    img.save('resized.jpg')
else:
    basewidth = 64
    wpercent = (basewidth/float(img.size[0]))
    hsize = int((float(img.size[1])*float(wpercent)))
    img = img.resize((basewidth,hsize), Image.ANTIALIAS)
    img.save('resized.jpg')

I was trying to resize some images for a slideshow video and because of that, I wanted not just one max dimension, but a max width and a max height (the size of the video frame).
And there was always the possibility of a portrait video...
The Image.thumbnail method was promising, but I could not make it upscale a smaller image.

So after I couldn't find an obvious way to do that here (or at some other places), I wrote this function and put it here for the ones to come:

from PIL import Image

def get_resized_img(img_path, video_size):
    img = Image.open(img_path)
    width, height = video_size  # these are the MAX dimensions
    video_ratio = width / height
    img_ratio = img.size[0] / img.size[1]
    if video_ratio >= 1:  # the video is wide
        if img_ratio <= video_ratio:  # image is not wide enough
            width_new = int(height * img_ratio)
            size_new = width_new, height
        else:  # image is wider than video
            height_new = int(width / img_ratio)
            size_new = width, height_new
    else:  # the video is tall
        if img_ratio >= video_ratio:  # image is not tall enough
            height_new = int(width / img_ratio)
            size_new = width, height_new
        else:  # image is taller than video
            width_new = int(height * img_ratio)
            size_new = width_new, height
    return img.resize(size_new, resample=Image.LANCZOS)

I resizeed the image in such a way and it's working very well

from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
import os, sys
from PIL import Image


def imageResize(image):
    outputIoStream = BytesIO()
    imageTemproaryResized = imageTemproary.resize( (1920,1080), Image.ANTIALIAS) 
    imageTemproaryResized.save(outputIoStream , format='PNG', quality='10') 
    outputIoStream.seek(0)
    uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" % image.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)

    ## For upload local folder
    fs = FileSystemStorage()
    filename = fs.save(uploadedImage.name, uploadedImage)

If you don't want / don't have a need to open image with Pillow, use this:

from PIL import Image

new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))

If you are trying to maintain the same aspect ratio, then wouldn't you resize by some percentage of the original size?

For example, half the original size

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

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)

Open your image file

from PIL import Image
im = Image.open("image.png")

Use PIL Image.resize(size, resample=0) method, where you substitute (width, height) of your image for the size 2-tuple.

This will display your image at original size:

display(im.resize((int(im.size[0]),int(im.size[1])), 0) )

This will display your image at 1/2 the size:

display(im.resize((int(im.size[0]/2),int(im.size[1]/2)), 0) )

This will display your image at 1/3 the size:

display(im.resize((int(im.size[0]/3),int(im.size[1]/3)), 0) )

This will display your image at 1/4 the size:

display(im.resize((int(im.size[0]/4),int(im.size[1]/4)), 0) )

etc etc


import cv2
from skimage import data 
import matplotlib.pyplot as plt
from skimage.util import img_as_ubyte
from skimage import io
filename='abc.png'
image=plt.imread(filename)
im=cv2.imread('abc.png')
print(im.shape)
im.resize(300,300)
print(im.shape)
plt.imshow(image)

If you don't want / don't have a need to open image with Pillow, use this:

from PIL import Image

new_img_arr = numpy.array(Image.fromarray(img_arr).resize((new_width, new_height), Image.ANTIALIAS))

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

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.


My ugly example.

Function get file like: "pic[0-9a-z].[extension]", resize them to 120x120, moves section to center and save to "ico[0-9a-z].[extension]", works with portrait and landscape:

def imageResize(filepath):
    from PIL import Image
    file_dir=os.path.split(filepath)
    img = Image.open(filepath)

    if img.size[0] > img.size[1]:
        aspect = img.size[1]/120
        new_size = (img.size[0]/aspect, 120)
    else:
        aspect = img.size[0]/120
        new_size = (120, img.size[1]/aspect)
    img.resize(new_size).save(file_dir[0]+'/ico'+file_dir[1][3:])
    img = Image.open(file_dir[0]+'/ico'+file_dir[1][3:])

    if img.size[0] > img.size[1]:
        new_img = img.crop( (
            (((img.size[0])-120)/2),
            0,
            120+(((img.size[0])-120)/2),
            120
        ) )
    else:
        new_img = img.crop( (
            0,
            (((img.size[1])-120)/2),
            120,
            120+(((img.size[1])-120)/2)
        ) )

    new_img.save(file_dir[0]+'/ico'+file_dir[1][3:])

You can resize image by below code:

From PIL import Image
img=Image.open('Filename.jpg') # paste image in python folder
print(img.size())
new_img=img.resize((400,400))
new_img.save('new_filename.jpg')

You can combine PIL's Image.thumbnail with sys.maxsize if your resize limit is only on one dimension (width or height).

For instance, if you want to resize an image so that its height is no more than 100px, while keeping aspect ratio, you can do something like this:

import sys
from PIL import Image

image.thumbnail([sys.maxsize, 100], Image.ANTIALIAS)

Keep in mind that Image.thumbnail will resize the image in place, which is different from Image.resize that instead returns the resized image without changing the original one.


PIL already has the option to crop an image

img = ImageOps.fit(img, size, Image.ANTIALIAS)

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

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)

You can resize image by below code:

From PIL import Image
img=Image.open('Filename.jpg') # paste image in python folder
print(img.size())
new_img=img.resize((400,400))
new_img.save('new_filename.jpg')

I was trying to resize some images for a slideshow video and because of that, I wanted not just one max dimension, but a max width and a max height (the size of the video frame).
And there was always the possibility of a portrait video...
The Image.thumbnail method was promising, but I could not make it upscale a smaller image.

So after I couldn't find an obvious way to do that here (or at some other places), I wrote this function and put it here for the ones to come:

from PIL import Image

def get_resized_img(img_path, video_size):
    img = Image.open(img_path)
    width, height = video_size  # these are the MAX dimensions
    video_ratio = width / height
    img_ratio = img.size[0] / img.size[1]
    if video_ratio >= 1:  # the video is wide
        if img_ratio <= video_ratio:  # image is not wide enough
            width_new = int(height * img_ratio)
            size_new = width_new, height
        else:  # image is wider than video
            height_new = int(width / img_ratio)
            size_new = width, height_new
    else:  # the video is tall
        if img_ratio >= video_ratio:  # image is not tall enough
            height_new = int(width / img_ratio)
            size_new = width, height_new
        else:  # image is taller than video
            width_new = int(height * img_ratio)
            size_new = width_new, height
    return img.resize(size_new, resample=Image.LANCZOS)

I will also add a version of the resize that keeps the aspect ratio fixed. In this case, it will adjust the height to match the width of the new image, based on the initial aspect ratio, asp_rat, which is float (!). But, to adjust the width to the height, instead, you just need to comment one line and uncomment the other in the else loop. You will see, where.

You do not need the semicolons (;), I keep them just to remind myself of syntax of languages I use more often.

from PIL import Image

img_path = "filename.png";
img = Image.open(img_path);     # puts our image to the buffer of the PIL.Image object

width, height = img.size;
asp_rat = width/height;

# Enter new width (in pixels)
new_width = 50;

# Enter new height (in pixels)
new_height = 54;

new_rat = new_width/new_height;

if (new_rat == asp_rat):
    img = img.resize((new_width, new_height), Image.ANTIALIAS); 

# adjusts the height to match the width
# NOTE: if you want to adjust the width to the height, instead -> 
# uncomment the second line (new_width) and comment the first one (new_height)
else:
    new_height = round(new_width / asp_rat);
    #new_width = round(new_height * asp_rat);
    img = img.resize((new_width, new_height), Image.ANTIALIAS);

# usage: resize((x,y), resample)
# resample filter -> PIL.Image.BILINEAR, PIL.Image.NEAREST (default), PIL.Image.BICUBIC, etc..
# https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize

# Enter the name under which you would like to save the new image
img.save("outputname.png");

And, it is done. I tried to document it as much as I can, so it is clear.

I hope it might be helpful to someone out there!


Open your image file

from PIL import Image
im = Image.open("image.png")

Use PIL Image.resize(size, resample=0) method, where you substitute (width, height) of your image for the size 2-tuple.

This will display your image at original size:

display(im.resize((int(im.size[0]),int(im.size[1])), 0) )

This will display your image at 1/2 the size:

display(im.resize((int(im.size[0]/2),int(im.size[1]/2)), 0) )

This will display your image at 1/3 the size:

display(im.resize((int(im.size[0]/3),int(im.size[1]/3)), 0) )

This will display your image at 1/4 the size:

display(im.resize((int(im.size[0]/4),int(im.size[1]/4)), 0) )

etc etc


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

The following script creates nice thumbnails of all JPEG images preserving aspect ratios with 128x128 max resolution.

from PIL import Image
img = Image.open("D:\\Pictures\\John.jpg")
img.thumbnail((680,680))
img.save("D:\\Pictures\\John_resize.jpg")

A simple method for keeping constrained ratios and passing a max width / height. Not the prettiest but gets the job done and is easy to understand:

def resize(img_path, max_px_size, output_folder):
    with Image.open(img_path) as img:
        width_0, height_0 = img.size
        out_f_name = os.path.split(img_path)[-1]
        out_f_path = os.path.join(output_folder, out_f_name)

        if max((width_0, height_0)) <= max_px_size:
            print('writing {} to disk (no change from original)'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 > height_0:
            wpercent = max_px_size / float(width_0)
            hsize = int(float(height_0) * float(wpercent))
            img = img.resize((max_px_size, hsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 < height_0:
            hpercent = max_px_size / float(height_0)
            wsize = int(float(width_0) * float(hpercent))
            img = img.resize((max_px_size, wsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

Here's a python script that uses this function to run batch image resizing.


The following script creates nice thumbnails of all JPEG images preserving aspect ratios with 128x128 max resolution.

from PIL import Image
img = Image.open("D:\\Pictures\\John.jpg")
img.thumbnail((680,680))
img.save("D:\\Pictures\\John_resize.jpg")

Just updating this question with a more modern wrapper This library wraps Pillow (a fork of PIL) https://pypi.org/project/python-resize-image/

Allowing you to do something like this :-

from PIL import Image
from resizeimage import resizeimage

fd_img = open('test-image.jpeg', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_width(img, 200)
img.save('test-image-width.jpeg', img.format)
fd_img.close()

Heaps more examples in the above link.


If you are trying to maintain the same aspect ratio, then wouldn't you resize by some percentage of the original size?

For example, half the original size

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

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.


If you are trying to maintain the same aspect ratio, then wouldn't you resize by some percentage of the original size?

For example, half the original size

half = 0.5
out = im.resize( [int(half * s) for s in im.size] )

A simple method for keeping constrained ratios and passing a max width / height. Not the prettiest but gets the job done and is easy to understand:

def resize(img_path, max_px_size, output_folder):
    with Image.open(img_path) as img:
        width_0, height_0 = img.size
        out_f_name = os.path.split(img_path)[-1]
        out_f_path = os.path.join(output_folder, out_f_name)

        if max((width_0, height_0)) <= max_px_size:
            print('writing {} to disk (no change from original)'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 > height_0:
            wpercent = max_px_size / float(width_0)
            hsize = int(float(height_0) * float(wpercent))
            img = img.resize((max_px_size, hsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

        if width_0 < height_0:
            hpercent = max_px_size / float(height_0)
            wsize = int(float(width_0) * float(hpercent))
            img = img.resize((max_px_size, wsize), Image.ANTIALIAS)
            print('writing {} to disk'.format(out_f_path))
            img.save(out_f_path)
            return

Here's a python script that uses this function to run batch image resizing.


Just updating this question with a more modern wrapper This library wraps Pillow (a fork of PIL) https://pypi.org/project/python-resize-image/

Allowing you to do something like this :-

from PIL import Image
from resizeimage import resizeimage

fd_img = open('test-image.jpeg', 'r')
img = Image.open(fd_img)
img = resizeimage.resize_width(img, 200)
img.save('test-image-width.jpeg', img.format)
fd_img.close()

Heaps more examples in the above link.


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

You can combine PIL's Image.thumbnail with sys.maxsize if your resize limit is only on one dimension (width or height).

For instance, if you want to resize an image so that its height is no more than 100px, while keeping aspect ratio, you can do something like this:

import sys
from PIL import Image

image.thumbnail([sys.maxsize, 100], Image.ANTIALIAS)

Keep in mind that Image.thumbnail will resize the image in place, which is different from Image.resize that instead returns the resized image without changing the original one.


import cv2
from skimage import data 
import matplotlib.pyplot as plt
from skimage.util import img_as_ubyte
from skimage import io
filename='abc.png'
image=plt.imread(filename)
im=cv2.imread('abc.png')
print(im.shape)
im.resize(300,300)
print(im.shape)
plt.imshow(image)

My ugly example.

Function get file like: "pic[0-9a-z].[extension]", resize them to 120x120, moves section to center and save to "ico[0-9a-z].[extension]", works with portrait and landscape:

def imageResize(filepath):
    from PIL import Image
    file_dir=os.path.split(filepath)
    img = Image.open(filepath)

    if img.size[0] > img.size[1]:
        aspect = img.size[1]/120
        new_size = (img.size[0]/aspect, 120)
    else:
        aspect = img.size[0]/120
        new_size = (120, img.size[1]/aspect)
    img.resize(new_size).save(file_dir[0]+'/ico'+file_dir[1][3:])
    img = Image.open(file_dir[0]+'/ico'+file_dir[1][3:])

    if img.size[0] > img.size[1]:
        new_img = img.crop( (
            (((img.size[0])-120)/2),
            0,
            120+(((img.size[0])-120)/2),
            120
        ) )
    else:
        new_img = img.crop( (
            0,
            (((img.size[1])-120)/2),
            120,
            120+(((img.size[1])-120)/2)
        ) )

    new_img.save(file_dir[0]+'/ico'+file_dir[1][3:])

from PIL import Image
from resizeimage import resizeimage

def resize_file(in_file, out_file, size):
    with open(in_file) as fd:
        image = resizeimage.resize_thumbnail(Image.open(fd), size)
    image.save(out_file)
    image.close()

resize_file('foo.tif', 'foo_small.jpg', (256, 256))

I use this library:

pip install python-resize-image

I resizeed the image in such a way and it's working very well

from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
import os, sys
from PIL import Image


def imageResize(image):
    outputIoStream = BytesIO()
    imageTemproaryResized = imageTemproary.resize( (1920,1080), Image.ANTIALIAS) 
    imageTemproaryResized.save(outputIoStream , format='PNG', quality='10') 
    outputIoStream.seek(0)
    uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" % image.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)

    ## For upload local folder
    fs = FileSystemStorage()
    filename = fs.save(uploadedImage.name, uploadedImage)

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

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to image

Reading images in python Numpy Resize/Rescale Image Convert np.array of type float64 to type uint8 scaling values Extract a page from a pdf as a jpeg How do I stretch an image to fit the whole background (100% height x 100% width) in Flutter? Angular 4 img src is not found How to make a movie out of images in python Load local images in React.js How to install "ifconfig" command in my ubuntu docker image? How do I display local image in markdown?

Examples related to python-imaging-library

How do I install PIL/Pillow for Python 3.6? TypeError: Image data can not convert to float Combine several images horizontally with Python Generate random colors (RGB) How to show PIL Image in ipython notebook Why can't Python import Image from PIL? Importing images from a directory (Python) to list or dictionary ImportError: No module named Image Installing PIL with pip Image.open() cannot identify image file - Python?

Examples related to thumbnails

Carousel with Thumbnails in Bootstrap 3.0 How to display Woocommerce Category image? Creating a thumbnail from an uploaded image Create thumbnail image Generate preview image from Video file? Get img thumbnails from Vimeo? Facebook Post Link Image How do I resize an image using PIL and maintain its aspect ratio?