【问题标题】:Serving images dynamically via StringIO/BytesIO in Tornado templates通过 Tornado 模板中的 StringIO/BytesIO 动态提供图像
【发布时间】:2014-07-20 14:25:12
【问题描述】:

如何将嵌入 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')

模板:


<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>

龙卷风:

#!/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' codec can't decode byte 0xff in position 0: invalid start byte

【问题讨论】:

  • 预期输出是什么?为什么要将 JPEG 数据和 HTML 与image/jpg MIME 类型结合起来?
  • 预期输出是带有其他页面内容的图像,例如用户名等。我犯了这些愚蠢的错误是因为我不熟悉 Web 开发——我倾向于坚持后端开发。

标签: python tornado jinja2


【解决方案1】:

在不同的处理程序中渲染图像。喜欢:

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://stackoverflow.com/a/4502403/207791),但很少这样做,并且浏览器缓存性能会受到影响。

顺便说一句,您可能会从异步图像 i/o 中受益。

【讨论】:

  • 不知道为什么这被投了赞成票。它看起来很有趣,但不起作用。例如对于模板调用,filename= 为空!?
  • 我相信原因是,除了明显的错字,它起作用了。
  • 如果我能重现它会很棒。是否可以更改代码示例?
猜你喜欢
  • 1970-01-01
  • 2023-04-11
  • 1970-01-01
  • 2016-07-10
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多