Pillow 可以直接处理用户上传的图片文件吗? - V2EX
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 3363 次点击
    这是一个创建于 3286 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在是先把用户上传的图片保存到服务器硬盘,然后用 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     Solana     1327 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 17:00 PVG 01:00 LAX 09:00 JFK 12:00
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86