在Tornado模板中使用StringIO/BytesIO动态地提供图像。

3

如何在Tornado模板中显示嵌入的图像,而不是将其作为页面呈现在单独的Tornado处理程序中?

我希望通过StringIO/ByesIO提供图像服务,因为最终将在数据库中存储该图像。

很抱歉包含了这么多代码。这可能会使帖子过于本地化,但该代码只是加载一个图像。

将图像编写为新页面

class DemoHandler(BaseHandler):
    @tornado.web.asynchronous
    def get(self):
        f = Image.open('img/cat.jpeg')
        o = io.BytesIO()
        f.save(o, format="JPEG")
        s = o.getvalue()
        self.set_header('Content-type', 'image/jpg')
        self.set_header('Content-length', len(s))   
        self.write(s)   
        self.render('demo.html')

Template:


<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=900">
</head>

<body>
  <div class="row">
        <div class="panel panel-default">
            <div class="panel-heading">User Account</div>
            <div class="panel-body" style="padding:5px">

                <div class="col-xs-3">
                    <img src={{ user['photo'] }} style="width:125px;height:125px;"/>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Tornado:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import division

from base64 import b64encode
from PIL import Image
import tornado
import tornado.ioloop
import tornado.web
import collections
import logging
import re
import os
import io

from tornado.options import define, options
define('port', default=8888, help='Listening port', type=int)

class Application(tornado.web.Application):
    def __init__(self):
        handlers=[
            (r'/\/?', DemoHandler),
        ]
        settings = dict(
            template_path=os.path.dirname(os.path.abspath(__file__)),
            static_path=os.path.dirname(os.path.abspath(__file__)),
            xsrf_cookies=True,
            cookie_secret=b64encode(os.urandom(64)),
            debug=True,
            auto_reload=True,
        )
        tornado.web.Application.__init__(self, handlers, **settings)

        # Configure logging
        options.log_file_max_size = (1024**2)*10
        logging.getLogger().setLevel(logging.INFO)
        tornado.log.enable_pretty_logging()

        print("Listening on port: %d" % options.port)

class BaseHandler(tornado.web.RequestHandler):
    pass

class DemoHandler(BaseHandler):
    @tornado.web.asynchronous
    def get(self):
        f = Image.open('img/cat.jpg')
        o = io.BytesIO()
        f.save(o, format="JPEG")
        s = o.getvalue()    

        user = collections.defaultdict(lambda: collections.defaultdict(dict))
        user['photo']=s

        self.render('demo.html', user=user)

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = Application()
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

UnicodeDecodeError: 'utf-8'编解码器无法解码位置0处的字节0xff:起始字节无效


预期输出是什么?为什么要将JPEG数据和HTML与“image/jpg” MIME类型结合在一起? - Stefano Sanfilippo
预期输出是带有其他页面内容的图像,例如用户的姓名等。我犯了这些愚蠢的错误,因为我不熟悉Web开发 - 我倾向于专注于后端开发。 - user1260503
1个回答

3

将图片在不同的处理程序中呈现。例如:

class ImageHandler(BaseHandler):
    @tornado.web.asynchronous
    def get(self, filename):
        f = Image.open('img/' + filename)
        o = io.BytesIO()
        f.save(o, format="JPEG")
        s = o.getvalue()
        self.set_header('Content-type', 'image/jpg')
        self.set_header('Content-length', len(s))   
        self.write(s)   


class PageHandler(BaseHandler):
    @tornado.web.asynchronous
    def get(self):
        self.render('demo.html', filename=)

class Application(tornado.web.Application):
    def __init__(self):
        handlers=[
            (r'/', PageHandler),
            (r'/img/(?P<filename>.+\.jpg)?', ImageHandler),
        ]

模板:

...
<img src="/img/{{filename}}" style="width:125px;height:125px;"/>
...

当然,您可以将图像嵌入到网页中(例如这里:https://dev59.com/sm855IYBdhLWcg3wKw5Y#4502403),但很少这样做,浏览器缓存性能会受到影响。
顺便说一下,您可能会从将图像 I/O 异步化中受益。

不确定为什么这个被投票了。它看起来很有趣,但是不起作用。例如,模板调用中filename为空!? - user3732793
我相信原因是除了明显的打字错误之外,它能正常运行。 - Victor Sergienko
如果您能更改代码示例,那么我就可以尝试复现它,这将非常棒。 - user3732793

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接