使用Tornado无文件I/O服务图片
我正在尝试使用Tornado库来提供一个网络摄像头的图像,但我发现的唯一方法是先把图像保存下来,然后再返回图像的名称。
有没有办法可以直接提供图像,而不需要先保存到硬盘上呢?
import tornado.ioloop
import tornado.web
import pygame.camera
import pygame.image
from time import time
from io import StringIO
pygame.camera.init()
cam = pygame.camera.Camera(pygame.camera.list_cameras()[0])
cam.start()
class MainHandler(tornado.web.RequestHandler):
def get(self):
img = cam.get_image()
name = str( round( time() ) )
name = name + '.jpg'
pygame.image.save(img, name)
self.write('<img src="' + name + '">')
application = tornado.web.Application([
(r"/", MainHandler),
(r'/(.*)', tornado.web.StaticFileHandler, {'path': ''})
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
3 个回答
-1
当然!像这样的:
class ImageHandler(tornado.web.RequestHandler):
def get(self):
img = cam.get_image()
self.set_header('Content-Type', 'image/jpg')
self.write(img.contents)
application = tornado.web.Application([
(r"/image.jpg", ImageHandler),
])
我不太清楚怎么把图片的内容转成字节,但你明白我的意思。
1
是的,你可以在不处理文件输入输出的情况下提供图片。我有一个用 python3
写的 应用程序,它通过发送一个1x1像素的图片来追踪用户,使用的是 Tornado
。
我在 源代码 中这样存储图片:
# 1x1 Transparent Pixel in HEX Format
pixel_GIF = [0x47,0x49,0x46,0x38,0x39,0x61,
0x01,0x00,0x01,0x00,0x80,0x00,
0x00,0x00,0x00,0x00,0xff,0xff,
0xff,0x21,0xf9,0x04,0x01,0x00,
0x00,0x00,0x00,0x2c,0x00,0x00,
0x00,0x00,0x01,0x00,0x01,0x00,
0x00,0x02,0x01,0x44,0x00,0x3b]
然后,我使用下面的 函数 将图片从 HEX
格式转换为二进制:
def pack_into_binary(data):
"""Convert given data into binary form"""
packed = str()
for datum in data:
packed += struct.pack('B', datum).decode("ISO-8859-1")
return packed
pixel_binary = pack_into_binary(pixel_GIF)
#1x1 Transparent Tracking Pixel
self.set_header("Content-Length", 42)
self.set_header("Content-Type", "image/gif")
self.set_header("Pragma", "no-cache")
self.set_header("Cache-Control",
"no-store, "
"no-cache=Set-Cookie, "
"proxy-revalidate, "
"max-age=0, "
"post-check=0, pre-check=0"
)
self.set_header("Expires", "Wed, 2 Dec 1837 21:00:12 GMT")
self.write(self.pixel_binary)
这一切都不需要进行任何 文件输入输出
。
注意:如果你手头有图片在内存中,你可以通过将格式转换为二进制并使用 write
方法来提供它。不同之处在于,你的图片不是预先确定的,而是动态生成的。
编辑:下面是从 RGB Surface
转换到 binary
编码的示例。
from StringIO import StringIO
from PIL import Image
data = pygame.image.tostring(cam.get_image(),"RGB")
img = Image.fromstring('RGBA', (100,200), data) # 100 x 200 example surface
zdata = StringIO()
img.save(zdata, 'JPEG')
self.write(zdata.getvalue())
然后你可以使用 Tornado
来提供 image
。
4
看起来pygame不支持直接把图片保存到像文件一样的对象里,所以你不能直接用它。不过,它有一个叫做 tostring
的方法。文档里提到,这个方法可以和其他图片库一起使用:
它会创建一个字符串,可以用其他Python图像库的‘fromstring’方法来传输
所以,你可以用 tostring
把你的图片转换成一个字符串,然后使用另一个支持将图片写入像文件一样对象的Python库,利用它的 fromstring
方法来处理。
下面是一个使用 pillow
作为替代图片库的例子。
import tornado.ioloop
import tornado.web
from PIL import Image
import cStringIO as StringIO
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("<img src='http://localhost:8888/img'>")
class ImgHandler(tornado.web.RequestHandler):
img_name = "bg.jpg"
img = pygame.image.load(img_name)
str_img = pygame.image.tostring(img, "RGB")
size = img.get_size()
fimg = Image.frombytes("RGB", size, str_img, "raw")
fobj = StringIO.StringIO()
fimg.save(fobj, format="png") #jpeg encoder isn't available in my install...
for line in fobj.getvalue():
self.write(line)
self.set_header("Content-type", "image/png")
application = tornado.web.Application([
(r"/", MainHandler),
(r"/img", ImgHandler),
#(r'/(.*)', tornado.web.StaticFileHandler, {'path': ''})
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
访问 localhost:8888
和 localhost:8888/img
都可以显示这张图片。