使用 Python Bottle 上传后的图像处理
Image processing after upload with Python Bottle
上下文
我制作了一个简单的网络应用程序,用于将内容上传到博客。前端向 Python 3.7 上的 Bottle 运行 后端发送 AJAX 请求(使用 FormData)。文本内容保存到 MySQL 数据库中,图像保存到服务器上的文件夹中。一切正常。
图像处理和PIL/Pillow
现在,我想启用对上传图像的处理以使其标准化(我需要将它们全部调整大小 and/or 裁剪为 700x400 像素)。
我希望为此使用 Pillow。我的问题是从 Bottle 中的文件对象创建一个 PIL 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"
),我已经检查过我确实使用 [=20= 正确导入了 PIL (Pillow) ].
我试过改编 :
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(mode, size, data, decoder_name='raw', *args)
Note that this function decodes pixel data only, not entire images.
If you have an entire image file in a string, wrap it in a BytesIO object, and use open() to load it.
据我了解,您正在尝试在将图像保存到本地后调整其大小(请注意,您可以尝试在保存之前调整大小)。如果这是你想在这里实现的,你可以直接使用 Pillow 打开图像,它会为你完成工作(你不必 open(path, "rb")
:
image = Image.open(path)
image.resize((700,400)).save(path)
改为使用 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 上的 Bottle 运行 后端发送 AJAX 请求(使用 FormData)。文本内容保存到 MySQL 数据库中,图像保存到服务器上的文件夹中。一切正常。
图像处理和PIL/Pillow
现在,我想启用对上传图像的处理以使其标准化(我需要将它们全部调整大小 and/or 裁剪为 700x400 像素)。
我希望为此使用 Pillow。我的问题是从 Bottle 中的文件对象创建一个 PIL 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"
),我已经检查过我确实使用 [=20= 正确导入了 PIL (Pillow) ].
我试过改编
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(mode, size, data, decoder_name='raw', *args)
Note that this function decodes pixel data only, not entire images. If you have an entire image file in a string, wrap it in a BytesIO object, and use open() to load it.
据我了解,您正在尝试在将图像保存到本地后调整其大小(请注意,您可以尝试在保存之前调整大小)。如果这是你想在这里实现的,你可以直接使用 Pillow 打开图像,它会为你完成工作(你不必 open(path, "rb")
:
image = Image.open(path)
image.resize((700,400)).save(path)
改为使用 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())