在推送到S3之前,有没有更简洁的方法来旋转通过烧瓶上传的智能手机图像?

时间:2014-06-24 23:17:26

标签: python heroku amazon-s3 flask python-imaging-library

我正在构建一个webapp,它接收上传的图像,将它们存储在Amazon S3上,然后将URL存储在SQLite数据库中。不幸的是,EXIF标签会导致通过智能手机拍摄的图像显示为旋转(因为它们是具有EXIF方向标签的风景图像)。

目前,我的环境从POST数据中获取文件,将其保存到我的静态文件文件夹,使用PIL旋转图像(如果需要),推送到S3并最终删除本地副本。以下是一些涉及的代码:

from PIL import Image
import boto
from boto.s3.connection import S3Connection
from boto.s3.key import Key

def fix_orientation(filename):
    img = Image.open(filename)
    if hasattr(img, '_getexif'):
        exifdata = img._getexif()
        try:
            orientation = exifdata.get(274)
        except:
            # There was no EXIF Orientation Data
            orientation = 1
    else:
        orientation = 1

    if orientation is 1:    # Horizontal (normal)
        pass
    elif orientation is 2:  # Mirrored horizontal
        img = img.transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 3:  # Rotated 180
        img = img.rotate(180)
    elif orientation is 4:  # Mirrored vertical
        img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 5:  # Mirrored horizontal then rotated 90 CCW
        img = img.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 6:  # Rotated 90 CCW
        img = img.rotate(-90)
    elif orientation is 7:  # Mirrored horizontal then rotated 90 CW
        img = img.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 8:  # Rotated 90 CW
        img = img.rotate(90)

    #save the result and overwrite the originally uploaded image
    img.save(filename)

def push_to_s3(**kwargs):
    try:
        conn = S3Connection(app.config["S3_KEY"], app.config["S3_SECRET"])
        buckets = [bucket.name for bucket in conn.get_all_buckets()]
        bucket = conn.get_bucket(app.config["S3_BUCKET"])

        k = Key(bucket)
        k.key = app.config["S3_UPLOAD_DIR"] + kwargs.get("filename")
        k.set_contents_from_filename(kwargs.get("photo"))
        k.make_public()
        return k
except Exception, e:
    abort(500)

这是处理POST数据

# Retrieving Form POST Data
fi = request.files.get("file")

#print "Storing and Rotating File (if needed)"
f = photos.save(fi)
path = photos.path(f)
fix_orientation(path)

#print "Uploading to S3"
img = push_to_s3(photo=path, filename=filename)

#print "Deleting Local Version"
os.remove(path)

上述解决方案适用于Heroku的服务器,但它似乎只是一个解决方案的管道胶带。是否有更清洁的方式来做我正在做的事情。也就是说,取一个上传的文件,从内存中旋转它,然后推送到S3?

我也使用Flask-Uploads来处理上传图片的存储。

1 个答案:

答案 0 :(得分:3)

Pillow支持除文件名之外的其他输入 - 包括bytearraybufferfile-like object。第三个很可能是你正在寻找的,因为从request.files加载的任何东西都只是一个FileStorage文件类对象。这简化了加载和转换代码:

def fix_orientation(file_like_object):
    img = Image.open(filename)

    # ... snip ...

    data = BytesIO()
    img.save(data)
    return data

由于我们要在不使用文件系统的情况下传递数据,我们也可以切换到使用boto.s3.key.Key set_contents_from_file方法而不是set_contents_from_filename:< / p>

def push_to_s3(photo, filename):
    # ... snip ...
    k.set_contents_from_file(photo, rewind=True)
    # ... etc. ...

这简化了最终的实现:

# Retrieving Form POST Data
fi = request.files.get("file")

# print "Rotating File (if needed)"
fi = fix_orientation(fi)

# print "Uploading to S3"
push_to_s3(photo=fi, filename=filename)