PIL:从POST HTTP请求打开图像

时间:2015-08-18 12:29:05

标签: python http post python-imaging-library

我想处理上传到SimpleHTTPServer的图片。

我尝试直接向rfile提供Image.open(),但这不起作用。

import SimpleHTTPServer
import SocketServer
from PIL import Image

class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):                    
    def do_POST(self):
        img = Image.open(self.rfile)
        # resize, crop, etc.

httpd = SocketServer.TCPServer(("", PORT), Handler)
httpd.serve_forever()

我可以将图像保存到磁盘并使用PIL正常打开,但它听起来不是最快/最干净的方式。

1 个答案:

答案 0 :(得分:3)

self.rfilesocket对象周围的简单文件包装器(请参阅生成此文件对象的socket.makefile() function)。包装器不支持搜索,因为只有一个数据流提供此对象,而不是磁盘上的随机访问区域。

PIL另一方面,需要随机访问整个文件(通过搜索),因为大多数图像格式使用文件中的不同部分来存储PIL对象在不同时需要访问的不同信息次。

您唯一的选择是将数据从self.rfile复制到支持搜索的文件对象。我建议您使用tempfile.SpooledTemporaryFile(),因为它会在将数据移动到磁盘之前将数据存储在内存中,直到达到阈值。

您需要注意的是,您只能将Content-Length标头字节仅复制到本地文件中;发送比这更少或更多的字节是错误的。如果您不是通过发送比磁盘空间可以处理的更大的POST请求而轻易地使您的服务器瘫痪。

也许使用while循环来复制缓冲区,直到达到Content-Length个字节,或者套接字不再返回数据:

from tempfile import SpooledTemporaryFile

def do_POST(self):
    try:
        length = int(self.headers.get('content-length'))
    except (TypeError, ValueError):
        # no Content-Length or not a number
        # return error
    if length > SOME_MAXIMUM_LENGTH:
        # return error

    with SpooledTemporaryFile() as imgfile:
        read = 0
        while read < length:
            buffer = self.rfile.read(1024)
            if not buffer:
                # too short, return error
            imgfile.write(buffer)
            read += len(buffer)
        if read > length or self.rfile.read(1):
            # too long, return error

        img_file.seek(0)
        img = Image.open(img_file)

如果您接受使用此处理程序的multipart/form-data请求,您实际上必须以不同方式解析该特定请求类型。使用cgi.FieldStorage() class来处理解析,它会将文件直接放入TemporaryFile个对象,直接到磁盘:

from cgi import FieldStorage

def do_POST(self):
    if self.headers.get('content-type', '').lower() == 'multipart/form-data':
        fields = FieldStorage(self.rfile, self.headers, environ={'METHOD': 'POST'})
        imgfile = fields['image_file']  # or whatever exact field name you expect