Pillow 可以直接处理用户上传的图片文件吗?

2016-12-27 11:18:33 +08:00
 rogwan

现在是先把用户上传的图片保存到服务器硬盘,然后用 Pillow 打开已保存的图片再做压缩处理。

Pillow 可以直接处理表单上传的图片文件吗?(就是在保存到硬盘之前先做压缩处理,原始图片文件不需要保存到服务器硬盘)。
说明:对用户上传的文件后缀类型做了判断,确实是 Pillow 可以处理的图片格式。不知道 Pillow 能否直接在内存里就处理 Filestorage 这种类型的数据?还是可以通过 Python 的 BytesIO 数据类型来处理?

2881 次点击
所在节点    Python
18 条回复
wyntergreg
2016-12-27 11:26:39 +08:00
这跟 pil 无关...
yjmade
2016-12-27 11:35:44 +08:00
我都是直接往 StringIO 里面一塞就送给 pil 的,不保存临时文件
neoblackcap
2016-12-27 11:36:00 +08:00
可以
rogwan
2016-12-27 12:49:21 +08:00
@yjmade @neoblackcap 这是什么错误的?用 StringIO 说是 bytes ;用 BytesIO 说不能识别 image 文件:

im = Image.open(StringIO(form.img.data.read()))
出错: TypeError: initial_value must be str or None, not bytes

im = Image.open(BytesIO(form.img.data.read()))
出错: OSError: cannot identify image file <_io.BytesIO object at 0x03A83B90>
ox180
2016-12-27 13:08:22 +08:00
顺便问一下,图片处理了以后还要保存一下,但是同样也不想保存在自己服务器上,怎么处理?
neoblackcap
2016-12-27 16:49:47 +08:00
@rogwan 请看文档,请用 PIL.Image.frombuffer


@ox180 不想保存?那么要直接用流返回吗?我是不建议这样做,定期删除就好了。一般都是写在磁盘,用户访问就让 nginx 直接返回该文件。
ox180
2016-12-27 18:14:25 +08:00
@neoblackcap 上传图片,处理,但是最终是保存在 cdn 上,所以这个地方不知道怎么处理
rogwan
2016-12-27 21:37:18 +08:00
@neoblackcap 谢谢,看了下 Image.frombuffer 感觉有点绕,舍近求远的感觉,试了一下也没行 *-*

我从 img_url 上取图片文件,然后可以用 BytesIO 直接处理:
r = requests.get(img_url)
img = Image.open(BytesIO(r.content))

Image.frombuffer 官方文档也特别提到,如果能获得 entire image file ,可以用 BytesIO ,没必要用 frombuffer 。
如果能从 Form 表单上传的文件中,直接能像 requests.get(img_url)取到图片,就不用饶一道弯用 frombuffer 专门处理 pixel data 。
试了各种方法,现在就是没能从上传的文件中成功取到图片格式的文件。。。不知道是我方法不对,还是根本没有这个方法(前提是不保存到硬盘)?
pimin
2016-12-27 21:49:58 +08:00
我比较建议根据 hash 值存到临时文件夹,定期清理,这样做的好处很多, 1 防止用户重复上传, 2 对比直接处理文件流,遇到异常情况不需要重新上传, 3 如果短时间内重复文件较多可以节省带宽,提升用户体验。
如果写文件权限受限当我没说。
rogerchen
2016-12-27 21:53:33 +08:00
@rogwan
先检查一下 form.img.data.read() 的类型,再 dump 一下 form.img.data.read() 的内容,和直接 get 的做一下对比。
neoblackcap
2016-12-27 22:14:27 +08:00
@rogwan 的确是那样也可以,我也没细看文档。一般我用 BytesIO 就是当 buffer 用,因此查文档都是查 buffer 相关的。用 open 肯定是可以的,毕竟官方文档也是这样说,但是现在就出现了个问题,你本身图片已经是载入内存了,Image.open 又产生了一个副本,若是内存紧张的话要注意一下。

@ox180 上传图片处理完之后你就写磁盘,然后再而外用 rsync 或者你们 cdn 提供的客户端上传不就好了?上传完就删掉磁盘的文件,文件删除还是很快的嘛。
rogerchen
2016-12-27 22:28:14 +08:00
@rogwan
又在 SO 上逛了一圈。
两点建议吧,
1. seek(0) 试试。
2. 检查原始数据,可能 form 过来的 data 就是有问题。
rogwan
2016-12-27 23:20:51 +08:00
@rogerchen form 过来的 data 一直就是 filestorage ,各种方式去取,就是无法得到原始的 upload.jpg 这样的文件格式。这个才是核心故障 。 就是因为这个问题还没有直接解决,才绕弯找其它格式做桥接。

我也比较疑惑,这个用户 upload 到服务器内存里的文件到底是个什么编码格式(出错提示 __io.buffer )?怎么就没有方法还原出上传之前的文件呢?
rogerchen
2016-12-28 09:02:01 +08:00
@rogwan
是 flask 么
filestorage 本身就是个文件的啊,试试直接 Image.open(form.img.data)

这显然不是 Pillow 的问题,仔细读读 API 吧。
rogwan
2016-12-28 09:32:13 +08:00
@rogerchen 是 flask , image.open(form.img.data)是本能反应,你有打开过的经验吗?
rogwan
2016-12-28 10:07:03 +08:00
谢谢,我再检查下上传的文件类型看看,是不是在当前 pillow 版本支持处理的格式
ox180
2016-12-28 15:43:36 +08:00
flask:
f = request.files["upload"]
img_obj = Image.open(f)
region = (x,y,w,h)
crop_img = img_obj.crop(region)
crop_img.save(addr)

关键我不想保存至本地,而是直接上传到其他服务器上,各个大神们,你们怎么处理??
rogwan
2016-12-28 17:20:44 +08:00
@ox180 对于其他服务器等于是再 POST 一次,如果是局域网内的服务好弄,如果是走互联网,还是通过 TCP/IP 来传。这个转存,也没有具体实际跑过的经验呐。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/330434

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX