517
votes

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

21
Since this question is quite old but useful, and pillow is rather preferred, for a pillow-based tutorial take a look at this: pillow.readthedocs.org/en/latest/handbook/…Wtower
I have created a small library for resizing images, it can be of any help : github.com/charlesthk/python-resize-imageCharlesthk
The last release of PIL was in 2006. The pillow packge is the replacement as far as I know. Pillow's latest release was April 2, 2020.David Medinets

21 Answers

541
votes

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
313
votes

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

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.

54
votes

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)
20
votes

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] )
19
votes
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
13
votes

PIL already has the option to crop an image

img = ImageOps.fit(img, size, Image.ANTIALIAS)
7
votes
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
7
votes

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))
4
votes

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.

4
votes

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)
4
votes

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

4
votes

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!

3
votes

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.

3
votes

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

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.

2
votes

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:])
2
votes

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)
0
votes

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")
-1
votes
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)
-2
votes

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