Search code examples
python-3.xpython-imaging-librarytornado

In-memory generated image is not displayed in tornado web server


with that code I try to generate an image, and store it in a template reply of tornado webserver

python3 code looks like that

import io
from PIL import Image, ImageDraw
import tornado.ioloop
import tornado.web

class ImageHandler(tornado.web.RequestHandler):
    def get(self, filename):
        #open image
        f = Image.open('img/' + filename)

        #generate Image
        image = Image.new("RGB", (300, 50))
        draw = ImageDraw.Draw(image)
        draw.text((0, 0), "create_images ")
        o = io.BytesIO()
        image.save(o, 'JPEG')

        #store image in reply
        o.seek(0)
        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(tornado.web.RequestHandler):
    def get(self):
        self.render('image.html', filename='test.jpg')

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

if __name__ == "__main__":
    app = Application()
    port = 8080
    print('start server at port ' + str(port))
    app.listen(port)
    tornado.ioloop.IOLoop.current().start()

the image.html looks like

<html>
   <body>
     <p>{{ escape(filename) }}</p>
     <img src="/img/{{ escape(filename) }}" style="width:50px;height:50px;"/>
   </body>
 </html>

an the page renders fine. The paragraph text shops actually test.jpeg but the image is not loaded. How would I correctly generate and reply an image from the memory ? Version Python 3.6.5, Tornado 5.0.2 is used


Solution

  • This solution should work for you:

    import io
    from PIL import Image, ImageDraw
    import tornado.ioloop
    import tornado.web
    
    class ImageHandler(tornado.web.RequestHandler):
        def get(self, filename):
            # create buffer
            o = io.BytesIO()
    
            #generate Image
            img = Image.new('RGB', (100, 30), color = (73, 109, 137))
            d = ImageDraw.Draw(img)
            d.text((10,10), "Hello world", fill=(255, 255, 0))
            o.seek(0)
            img.save(o, format="JPEG")
    
            #store image in reply
            s = o.getvalue()
            print(s)
            self.set_header('Content-type', 'image/jpeg')
            self.set_header('Content-length', len(s))
            self.write(s)
    
    
    class PageHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('image.html', filename='test.jpg')
    
    class Application(tornado.web.Application):
        def __init__(self):
            handlers=[
                (r'/', PageHandler),
                (r'/img/(?P<filename>.+\.jpg)?', ImageHandler),
            ]
            tornado.web.Application.__init__(self, handlers)
    
    if __name__ == "__main__":
        app = Application()
        port = 8080
        print('start server at port ' + str(port))
        app.listen(port)
        tornado.ioloop.IOLoop.current().start()
    

    The error I ended up with: there was no img/test.jpg relative to the directory on which I started the tornado websocket server. This solution now generates the image instead of loading some image from disk and sends it to the client via GET.

    Output I get:

    enter image description here

    Hope this helps!