【问题标题】:Image processing after upload with Python Bottle使用 Python Bottle 上传后的图像处理
【发布时间】:2019-08-08 06:42:31
【问题描述】:

上下文

我制作了一个简单的网络应用程序,用于将内容上传到博客。前端向后端发送 AJAX 请求(使用 FormData),后端是在 Python 3.7 上运行的 Bottle。文本内容保存到 MySQL 数据库,图像保存到服务器上的文件夹。一切正常。

图像处理和 PIL/Pillow

现在,我想启用对上传图像的处理以使其标准化(我需要将它们全部调整大小和/或裁剪为 700x400 像素)。

我希望为此使用 Pillow。我的问题是从 Bottle 中的文件对象创建一个 PIL Image 对象。我无法初始化一个有效的 Image 对象。

代码

# AJAX sends request to this route
@post('/update')
def update():
    # Form data
    title = request.forms.get("title")
    body = request.forms.get("body")
    image = request.forms.get("image")
    author = request.forms.get("author")
    
    # Image upload
    file = request.files.get("file")
    if file:
        extension = file.filename.split(".")[-1]
        if extension not in ('png', 'jpg', 'jpeg'):
            return {"result" : 0, "message": "File Format Error"}
        save_path = "my/save/path"
        file.save(save_path)

问题

这一切都按预期工作,但我无法使用pillow 创建有效的Image 对象进行处理。我什至尝试使用保存路径重新加载保存的图像,但这也不起作用。

其他尝试

下面的代码不起作用。它导致了内部服务器错误,尽管我无法设置更详细的 Python 调试。

path = save_path + "/" + file.filename
image_data = open(path, "rb")
image = Image.open(image_data)

当手动记录时,path 是一个有效的相对 URL ("../domain-folder/images"),我已经检查过我确实使用 PIL.PILLOW_VERSION 正确导入了 PIL (Pillow)。

我尝试适应this answer

image = Image.frombytes('RGBA', (128,128), image_data, 'raw')

但是,在创建 Image 对象之前,我不会知道大小。我也尝试过使用io:

image = Image.open(io.BytesIO(image_data))

这也不起作用。在每种情况下,只有尝试初始化 Image 对象的行会导致问题。

总结

Bottle 文档说上传的文件是一个类似文件的对象,但我在创建我可以处理的 Image 对象方面没有取得多大成功。

我应该怎么做?我对保存之前或之后的处理没有偏好。我对处理感到满意,它正在初始化导致问题的 Image 对象。


编辑 - 解决方案

我通过改编eatmeimadanish 的答案来实现这一点。我必须使用 io.BytesIO 对象从 Bottle 保存文件,然后从那里用 Pillow 加载它。处理后,可以正常保存。

obj = io.BytesIO()
file.save(obj) # This saves the file retrieved by Bottle to the BytesIO object
path = save_path + "/" + file.filename

# Image processing
im = Image.open(obj) # Reopen the object with PIL
im = im.resize((700,400))
im.save(path, optimize=True)

我从Pillow documentation 中发现了这个可能也有用的不同功能。

PIL.Image.frombuffer(模式、大小、数据、decoder_name='raw'、*args)

请注意,此函数仅解码像素数据,而不是整个图像。 如果您有一个字符串中的整个图像文件,请将其包装在一个 BytesIO 对象中,然后使用 open() 来加载它。

【问题讨论】:

    标签: python python-3.x image-processing python-imaging-library bottle


    【解决方案1】:

    改用 StringIO。

    From PIL import Image
    try:
        import cStringIO as StringIO
    except ImportError:
        import StringIO
    
    s = StringIO.StringIO()
    #save your in memory file to this instead of a regular file
    file = request.files.get("file")
    if file:
        extension = file.filename.split(".")[-1]
        if extension not in ('png', 'jpg', 'jpeg'):
            return {"result" : 0, "message": "File Format Error"}
        file.save(s)
    im = Image.open(s)
    im.resize((700,400))
    im.save(s, 'png', optimize=True)
    s64 = base64.b64encode(s.getvalue())
    

    【讨论】:

    • 感谢您的回答。它带领我踏上了一段旅程。我使用的是 Python 3.7,所以我不得不改用import ioio.StringIO 不起作用(导致错误),但以这种方式使用 io.BytesIO 不会引发错误。最后一个 base-64 行会导致错误,但到目前为止没有错误。假设这会将调整大小的图像保存回s,那么我如何将s 保存到磁盘?
    • 我在调整您的答案的基础上让它工作 - 谢谢。请参阅我的编辑。我会接受你的回答,因为它把我带到了那里。诀窍是首先将 Bottle 文件上传加载到 BytesIO 对象中。
    【解决方案2】:

    据我了解,您正在尝试在本地保存图像后调整其大小(请注意,您可以在保存之前尝试调整大小)。如果这是您想要在这里实现的,您可以直接使用 Pillow 打开图像,它会为您完成工作(您不必open(path, "rb")

    image = Image.open(path)
    image.resize((700,400)).save(path)
    

    【讨论】:

    • 感谢您的回答。恐怕我在这里仍然会出错。我的应用程序在博客的子域上运行,但服务器文件夹都在我的名下。该路径指向主域中的同级文件夹。我认为这不是问题,因为保存工作正常。我打开了对瓶子友好的错误消息,但只返回了内部服务器错误。我看看能不能找到错误信息。
    猜你喜欢
    • 2021-09-23
    • 2017-07-23
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多