Вам необходимо правильно обрезать изображение перед его изменением размера. Основная идея состоит в том, чтобы определить наибольшую прямоугольную область исходного изображения, имеющую такое же соотношение сторон (ширину и высоту), что и миниатюрное изображение, а затем обрезать (обрезать) любой излишек вокруг него, прежде чем изменять размеры миниатюр. Вот функция, которая вычислит размер и расположение такой области обрезки:
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))
После определения области обрезки позвоните im.crop(bbox)
и затем вызовите im.thumbnail(...)
на возвращенном изображении.