python - Flask Web 服务器在处理和上传到 S3 时损坏图像

标签 python amazon-s3 flask io python-imaging-library

我正在尝试将 Flask Web 服务器上的图像存储在 S3 上。服务器接收图像并对其进行处理以创建两个副本(压缩+缩略图),然后上传所有三个副本。

成像的两个进程接收良好,但原始进程已损坏。该代码不会引发任何错误。

这一切都使用Python 3.6、Flask 1.0.2、Boto3 1.9.88

以下是上传页面代码的摘录:

form = UploadForm()
if form.validate_on_submit():
    photo = form.photo.data

    name, ext = os.path.splitext(form.photo.data.filename)

    photo_comp, photo_thum = get_compressions(photo, 'JPEG')

    pic_set = {}

    pic_set['original'] = photo
    pic_set['compressed'] = photo_comp
    pic_set['thumbs'] = photo_thum

    for pic in pic_set:
        output = upload_to_s3(file=pic_set[pic], username=current_user.username, \
                         filetype = pic, \
                         bucket_name = current_app.config['S3_BUCKET'])

函数“get_compressions()”生成文件的减小尺寸的 .jpeg 以及缩略图(很抱歉缩进格式出现错误):

def get_compressions(file, filetype):
#Creates new compressed and thumbnail copies. Checks for alpha
#channel, removes if present, resaves as compressed .jpeg, then
#wraps into a Werkzeug FileStorage type.

name, ext = os.path.splitext(file.filename)

temp_compress = BytesIO()
temp_thumb = BytesIO()

image = Image.open(file)

if image.mode in ['RGBA', 'LA', 'RGBa']:
    image2 = Image.new('RGB', image.size, '#ffffff')
    image2.paste(image, None, image)
    image = image2.copy()

image.save(temp_compress, format=filetype, quality=85, optimize=True)
image.thumbnail((400,400), Image.ANTIALIAS)
image.save(temp_thumb, format=filetype, optimize=True)  

temp_thumb.seek(0)
temp_compress.seek(0)

file_comp = FileStorage(stream=temp_compress,
                        filename=name + '.' + filetype,
                        content_type='image/jpg',
                        name=file.name,
                        )

file_thum = FileStorage(stream=temp_thumb,
                        filename=name + '.' + filetype,
                        content_type='image/jpg',
                        name=file.name,
                        )

return file_comp, file_thum

最后,“upload_to_s3()”函数在 AWS S3 上的保存相当简单:

def upload_to_s3(file, username, filetype, bucket_name, acl= os.environ.get('AWS_DEFAULT_ACL')):
s3.upload_fileobj(
    Fileobj=file
    , Bucket=bucket_name
    , Key = "{x}/{y}/{z}".format(x=username,y=filetype,z=file.filename)
    , ExtraArgs = {'ContentType': file.content_type}
)
print('Upload successful: ', file.filename)
return file.filename

我认为压缩会影响原始文件对象的上传 - 虽然 PIL image.save() 返回一个新对象,但压缩行为似乎会以某种方式影响原始对象。

在尝试研究这个问题时,我注意到 Flask 是多线程的标准,并且 Python GIL 不适用于 I/O 操作或图像处理 - 不确定这是否相关。

我尝试解决此问题的两个选项是:

  1. 更改代码执行顺序,使其变为原始上传 - 压缩 - 压缩上传,但这导致错误 'ValueError: I/O operation on a closed file'

  2. 在使用 get_compressions() 之前使用 copy.deepcopy() 创建一个新对象,但这会导致 'TypeError: cannot serialize '_io.BufferedRandom' object' .

我不太确定如何继续!可能可以上传原始文件,然后让服务器在后台处理压缩(基于上传的文件),但这对于想要立即检索压缩版本以加载页面的客户端来说是一个问题。

最佳答案

在您的get_compressions函数中,您正在读取原始file,它是一个FileStorage对象,因此您的文件指针最终位于文件的末尾,并且您结束将零字节文件写入 S3。因此,您需要寻找回到文件的开头,就像您对压缩版本所做的那样:

file.seek(0)                                                                
temp_thumb.seek(0)                                                          
temp_compress.seek(0)

关于python - Flask Web 服务器在处理和上传到 S3 时损坏图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54621777/

相关文章:

linux - 如何正确设置 EC2 负载平衡以允许实时文件同步?

python - 如何将字符串列表插入到mongodb数据库中?

python - 将 Spark 与 Flask 和 JDBC 一起使用

python - 从文本行列表中查找字符串

java - 从 S3 读取 Spark 中的 parquet 文件

python - 使用 boto 从 S3 流式传输 .gz 文件时无限循环

templates - 为正在运行的应用程序外部的目录调用 render_template 方法

python - 自定义装饰器不允许在主 Python 中调用函数

python - 传输/切换/更改两列的值,如果一列为 0/NaN

Python 运算符重载 __div__