开发者

How can I take an image and get a 3x2 ratio image cropped from the center?

开发者 https://www.devze.com 2023-01-23 05:35 出处:网络
Is there an easy way to do this? In Python, I created a script to get a \"square box\" from an image...based on the center.

Is there an easy way to do this? In Python, I created a script to get a "square box" from an image...based on the center.

However, that killed some of my brain cells. Is there an easy way to do this for a 3x2 (3 width, 2 height), based on the center?

This is my "square box" script, but I don't feel like modifying it for the 3x2.

def letterbox(f,thumb_w=None,thumb_h=None):
    try:
        im = Image.open(StringIO(f))
        imagex = int(im.size[0])
        imagey = int(im.size[1])
        thumb_size = (thumb_w,thumb_h) #what if it is too small!?? fix it.
        if imagex > imagey:
            setlen = imagey
            left = (imagex - setlen)/2
            top = 0
            height = setlen
            width = setlen
        if imagey > imagex:
            setlen = imagex
            le开发者_开发百科ft = 0
            top = (imagey - setlen)/2
            heigth = setlen
            width = setlen
        if imagex == imagey:
            left = 0
            top = 0
            height = imagey
            width = imagex
        box = (left,top,left+width,top+height)
        im = im.crop(box)
        #im.thumbnail(thumb_size,Image.ANTIALIAS)
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        pass
    return new_file

Is there a script online that can do what I need?


Use an aspect ratio which is defined as imagex/imagey, so you use 3/2 for 3:2, 16/9 for 16:9 etc.

def letterbox(f,aspect_ratio=1):
    try:
        im = Image.open(StringIO(f))
        imagex = int(im.size[0])
        imagey = int(im.size[1])
        width = min(imagex, imagey*aspect_ratio)
        height = min(imagex/aspect_ratio, imagey)
        left =(imagex - width)/2
        top = (imagey - height)/2
        box = (left,top,left+width,top+height)
        im = im.crop(box)
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        pass
    return new_file

You might want to check for roundoff errors at some point, but otherwise this does it.


First of all, the name of your function is misleading because what it does is not letterbox images (regardless of the specific height/width [aspect ratio] involved) -- so here it's been renamed aspectcrop() to better describe what it does.

def aspectcrop(f, ratio=1.0):
    try:
        im = Image.open(StringIO(f))
        imagewidth,imageheight = im.size

        # determine the dimensions of a crop area
        # which is no wider or taller than the image
        if int(imagewidth*ratio) > imageheight:
            cropheight,cropwidth = imageheight,int(imageheight/ratio)
        else:
            cropwidth,cropheight = imagewidth,int(imagewidth*ratio)

        # center the crop area on the image (dx and/or dy will be zero)
        dx,dy = (imagewidth-cropwidth)/2,(imageheight-cropheight)/2

        # crop, save, and return image data
        im = im.crop((dx,dy,cropwidth+dx,cropheight+dy))
        new_file = StringIO()
        im.save(new_file,'JPEG')
        new_file.seek(0)
    except Exception, e:
        new_file = None # prevent exception on return
        pass
    return new_file

If any aspect ratio argument you pass to it is not naturally a whole number, make sure it's in floating point, as in 3./2. not 3/2. The default (1.0) could have been integer, but I explicitly made it floating point as a reminder. It might be better to pass it in as two separate integers and compute the ratio internally.

Lastly, I noticed that your example script had some visible traces of what looks like an attempt to create a thumbnail of the image, so my answer to the related question What's the simplest way in Python to resize an image to a given bounded area? might also be of interest (and could probably be integrated into this function without too much trouble).

0

精彩评论

暂无评论...
验证码 换一张
取 消