V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
rogwan
V2EX  ›  Python

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

  •  
  •   rogwan · 2016-12-27 11:18:33 +08:00 · 2746 次点击
    这是一个创建于 2679 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    18 条回复    2016-12-28 17:20:44 +08:00
    wyntergreg
        1
    wyntergreg  
       2016-12-27 11:26:39 +08:00
    这跟 pil 无关...
    yjmade
        2
    yjmade  
       2016-12-27 11:35:44 +08:00
    我都是直接往 StringIO 里面一塞就送给 pil 的,不保存临时文件
    neoblackcap
        3
    neoblackcap  
       2016-12-27 11:36:00 +08:00
    可以
    rogwan
        4
    rogwan  
    OP
       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
        5
    ox180  
       2016-12-27 13:08:22 +08:00
    顺便问一下,图片处理了以后还要保存一下,但是同样也不想保存在自己服务器上,怎么处理?
    neoblackcap
        6
    neoblackcap  
       2016-12-27 16:49:47 +08:00
    @rogwan 请看文档,请用 PIL.Image.frombuffer


    @ox180 不想保存?那么要直接用流返回吗?我是不建议这样做,定期删除就好了。一般都是写在磁盘,用户访问就让 nginx 直接返回该文件。
    ox180
        7
    ox180  
       2016-12-27 18:14:25 +08:00
    @neoblackcap 上传图片,处理,但是最终是保存在 cdn 上,所以这个地方不知道怎么处理
    rogwan
        8
    rogwan  
    OP
       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
        9
    pimin  
       2016-12-27 21:49:58 +08:00 via Android
    我比较建议根据 hash 值存到临时文件夹,定期清理,这样做的好处很多, 1 防止用户重复上传, 2 对比直接处理文件流,遇到异常情况不需要重新上传, 3 如果短时间内重复文件较多可以节省带宽,提升用户体验。
    如果写文件权限受限当我没说。
    rogerchen
        10
    rogerchen  
       2016-12-27 21:53:33 +08:00
    @rogwan
    先检查一下 form.img.data.read() 的类型,再 dump 一下 form.img.data.read() 的内容,和直接 get 的做一下对比。
    neoblackcap
        11
    neoblackcap  
       2016-12-27 22:14:27 +08:00
    @rogwan 的确是那样也可以,我也没细看文档。一般我用 BytesIO 就是当 buffer 用,因此查文档都是查 buffer 相关的。用 open 肯定是可以的,毕竟官方文档也是这样说,但是现在就出现了个问题,你本身图片已经是载入内存了,Image.open 又产生了一个副本,若是内存紧张的话要注意一下。

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

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

    这显然不是 Pillow 的问题,仔细读读 API 吧。
    rogwan
        15
    rogwan  
    OP
       2016-12-28 09:32:13 +08:00 via Android
    @rogerchen 是 flask , image.open(form.img.data)是本能反应,你有打开过的经验吗?
    rogwan
        16
    rogwan  
    OP
       2016-12-28 10:07:03 +08:00
    谢谢,我再检查下上传的文件类型看看,是不是在当前 pillow 版本支持处理的格式
    ox180
        17
    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
        18
    rogwan  
    OP
       2016-12-28 17:20:44 +08:00
    @ox180 对于其他服务器等于是再 POST 一次,如果是局域网内的服务好弄,如果是走互联网,还是通过 TCP/IP 来传。这个转存,也没有具体实际跑过的经验呐。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3225 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:48 · PVG 19:48 · LAX 04:48 · JFK 07:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.