¿Cómo redimensiono una imagen usando PIL y mantengo su relación de aspecto?

¿Hay una manera obvia de hacer esto que me estoy perdiendo? Solo estoy tratando de hacer miniaturas.

Definir un tamaño máximo. Luego, calcule una relación de cambio de tamaño tomando min(maxwidth/width, maxheight/height) .

El tamaño adecuado es de tamaño oldsize*ratio .

Por supuesto, también hay un método de biblioteca para hacer esto: el método Image.thumbnail .
A continuación se muestra un ejemplo (editado) de la documentación de PIL .

 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 

Este script cambiará el tamaño de una imagen (somepic.jpg) utilizando PIL (Python Imaging Library) a un ancho de 300 píxeles y una altura proporcional al nuevo ancho. Lo hace determinando qué porcentaje de 300 píxeles tiene el ancho original (img.size [0]) y luego multiplicando la altura original (img.size [1]) por ese porcentaje. Cambie “basewidth” a cualquier otro número para cambiar el ancho predeterminado de sus imágenes.

 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('sompic.jpg') 

También recomiendo usar el método de miniaturas de PIL, ya que elimina todos los problemas de relación de ti.

Una pista importante, sin embargo: reemplazar

 im.thumbnail(size) 

con

 im.thumbnail(size,Image.ANTIALIAS) 

de forma predeterminada, PIL utiliza el filtro Image.NEAREST para cambiar el tamaño, lo que da como resultado un buen rendimiento pero una calidad deficiente.

Basado en @tomvon, terminé de usar lo siguiente:

Ancho de redimensionamiento:

 new_width = 680 new_height = new_width * height / width 

Altura de redimensionamiento:

 new_height = 680 new_width = new_height * width / height 

Entonces solo

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

PIL ya tiene la opción de recortar una imagen.

 img = ImageOps.fit(img, size, Image.ANTIALIAS) 
 from PIL import Image img = Image.open('/your iamge 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 u want ,*.png,*jpg,*.gif 

Si está tratando de mantener la misma relación de aspecto, ¿no cambiaría el tamaño en algún porcentaje del tamaño original?

Por ejemplo, la mitad del tamaño original.

 half = 0.5 out = im.resize( [int(half * s) for s in im.size] ) 
 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)) 

Yo uso esta biblioteca:

 pip install python-resize-image 

Mi ejemplo feo.

La función obtiene el archivo como: “pic [0-9a-z]. [Extensión]”, cambia su tamaño a 120×120, mueve la sección al centro y guarda a “ico [0-9a-z]. [Extensión]”, funciona con el retrato y el paisaje:

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

Un método simple para mantener relaciones restringidas y pasar un ancho / alto máximo. No es el más bonito, pero hace el trabajo y es fácil de entender:

 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 

Aquí hay un script de Python que utiliza esta función para ejecutar el cambio de tamaño de la imagen por lotes.

Estaba tratando de cambiar el tamaño de algunas imágenes para un video de presentación de diapositivas y debido a eso, no solo quería una dimensión máxima, sino un ancho máximo y una altura máxima (el tamaño del cuadro de video).
Y siempre existía la posibilidad de un video de retrato …
El método Image.thumbnail era prometedor, pero no podía hacer que fuera una imagen más pequeña.

Entonces, después de que no pude encontrar una manera obvia de hacerlo aquí (o en algún otro lugar), escribí esta función y la puse aquí para que venga:

 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) 

Si no desea o no necesita abrir la imagen con la almohada, use esto:

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

Solo actualizando esta pregunta con un envoltorio más moderno Esta biblioteca envuelve la Almohada (una bifurcación de PIL) https://pypi.org/project/python-resize-image/

Permitiéndote hacer algo como esto:

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

Montones de más ejemplos en el enlace de arriba.

Cambié el tamaño de la imagen de tal manera y está funcionando muy bien.

 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)