Question

I'd like to create a function, like:

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

Where a file can be given and resized.

The current function works great except it does not crop when necessary.

In the case that a rectangular image is given, and a square resize is required (width = height), some centered-weighted cropping will have to be done.

Was it helpful?

Solution

You need to crop the image properly before resizing it. The basic idea is to determine the largest rectangular area of the source image having the same aspect (width to height) ratio as the thumbnail image and then trim off (crop) any excess around it before resizing to the thumbnail's dimensions). Here's a function which will compute the size and location of such a cropping area:

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

After determining the crop area, call im.crop(bbox) and then call im.thumbnail(...) on the image returned.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top