¿Cuál es la forma más sencilla de cambiar el tamaño de una imagen a un área delimitada?

Me gustaría crear una función, como:

def generateThumbnail(self, width, height): """ Generates thumbnails for an image """ im = Image.open(self._file) im.thumbnail((width, height), Image.ANTIALIAS) im.save(self._path + str(width) + 'x' + str(height) + '-' + self._filename, "JPEG") 

Donde un archivo puede ser dado y redimensionado.

La función actual funciona muy bien, excepto que no se corta cuando es necesario.

En el caso de que se proporcione una imagen rectangular y se requiera un cambio de tamaño cuadrado (ancho = altura), se deberá realizar un recorte ponderado en el centro.

Es necesario recortar la imagen correctamente antes de cambiar su tamaño. La idea básica es determinar el área rectangular más grande de la imagen de origen que tiene la misma relación de aspecto (ancho a alto) que la imagen en miniatura y luego recortar (recortar) cualquier exceso alrededor de ella antes de cambiar el tamaño a las dimensiones de la miniatura. Aquí hay una función que calculará el tamaño y la ubicación de tal área de recorte:

 def cropbbox(imagewidth,imageheight, thumbwidth,thumbheight): """ cropbbox(imagewidth,imageheight, thumbwidth,thumbheight) Compute a centered image crop area for making thumbnail images. imagewidth,imageheight are source image dimensions thumbwidth,thumbheight are thumbnail image dimensions Returns bounding box pixel coordinates of the cropping area in this order (left,upper, right,lower). """ # determine scale factor fx = float(imagewidth)/thumbwidth fy = float(imageheight)/thumbheight f = fx if fx < fy else fy # calculate size of crop area cropheight,cropwidth = int(thumbheight*f),int(thumbwidth*f) # for centering use half the size difference of the image and the crop area dx = (imagewidth-cropwidth)/2 dy = (imageheight-cropheight)/2 # return bounding box of centered crop area on source image return dx,dy, cropwidth+dx,cropheight+dy if __name__=='__main__': print("===") bbox = cropbbox(1024,768, 128,128) print("cropbbox(1024,768, 128,128): {}".format(bbox)) print("===") bbox = cropbbox(768,1024, 128,128) print("cropbbox(768,1024, 128,128): {}".format(bbox)) print("===") bbox = cropbbox(1024,1024, 96,128) print("cropbbox(1024,1024, 96,128): {}".format(bbox)) print("===") bbox = cropbbox(1024,1024, 128,96) print("cropbbox(1024,1024, 128,96): {}".format(bbox)) 

Después de determinar el área de recorte, llame a im.crop(bbox) y luego llame a im.thumbnail(...) en la imagen devuelta.