Is there an obvious way to do this that I’m missing? I’m just trying to make thumbnails.
python – How do I resize an image using PIL and maintain its aspect ratio?
The Question :
- 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/…
- I have created a small library for resizing images, it can be of any help : github.com/charlesthk/python-resize-image
- 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.
The Answer 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
The Answer 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')
The Answer 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.
The Answer 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)
The Answer 5
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] )
The Answer 6
PIL already has the option to crop an image
img = ImageOps.fit(img, size, Image.ANTIALIAS)
The Answer 7
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
The Answer 8
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
The Answer 9
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))
The Answer 10
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.
The Answer 11
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)
The Answer 12
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!
The Answer 13
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 Answer 14
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')
The Answer 15
My ugly example.
Function get file like: “pic[0-9a-z].[extension]”, resize them to 120×120, 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:])
The Answer 16
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)
The Answer 17
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
The Answer 18
The following script creates nice thumbnails of all JPEG images preserving aspect ratios with 128×128 max resolution.
from PIL import Image img = Image.open("D:\\Pictures\\John.jpg") img.thumbnail((680,680)) img.save("D:\\Pictures\\John_resize.jpg")
The Answer 19
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)
The Answer 20
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')