0

I am rendering a list of instances, each with a binary blob image, in a template. To render the images, I need to encode them with base64. I'm not sure how to encode each image in a loop, my code below doesn't work. I'm also not sure if passing the list of objects and the list of encoded images to render_template increases network traffic. How do I correctly encode a list of images, and is this efficient?

class A:
    number = ndb.IntegerProperty()
    image = ndb.BlobProperty()
@app.route('/show-all')
def show_all():
    all = A.query().order(A.number).fetch()
    encoded_images = [b64encode(image) for all.image in all]  # Doesn't work
    return make_response(render_template("template.html", title="A", objects=all, images=encoded_images))
davidism
  • 121,510
  • 29
  • 395
  • 339
Tim
  • 2,000
  • 4
  • 27
  • 45
  • why does it not work? something like `encoded_images = [b64encode(objimage) for obj in objs]` should work fine – marcadian Jul 12 '15 at 08:00
  • Ok, I feel really dumb now. It does indeed work... However, that still doesn't solve the second problem :) – Tim Jul 12 '15 at 09:10

2 Answers2

1

You're not sending any "extra data" by sending multiple things to render_template, the only data that is sent over the network is the final rendered template.

It is slightly inefficient to build a list of all the encoded images, since they will all be in memory at once. Instead, you could add a property to the model so that you can just use a.b64_image on each instance as you render it.

class A:
    image = ndb.BlobProperty()

    @property
    def b64_image(self):
        return b64encode(self.image)

Then in the template you can loop over each item in the list of objects and get each item's base64-encoded image.

return render_template('objects.html', objects=objects)
{% for item in objects %}
<div>
    <img src="data:;base64,{{ item.b64_image }}"/>
</div>
{% endfor %}

Side note: you don't have to call make_response, Flask will convert a string (returned from render_template) to a response automatically. Also, make_response and render_template are part of Flask, not Flask-Restful.


As I said in my answer to your previous question, sending the images as data uris is inefficient because they're embeded in the html which is generated and sent every time, rather than being separate files that are cached by the client. The more efficient solution is to store and serve the file separately, and store the path to the file in the database.

Community
  • 1
  • 1
davidism
  • 121,510
  • 29
  • 395
  • 339
0

Starting with the second problem: I'm not sure of your implementation, but your response probably consists of only some kind of web-page, so no python objects will be sent over the Internet, so why exactly do you think calling a python function with different parameters cause you to send additional bytes to end user?

However, after all, you can obviously solve both problems at once. Just pass only A class objects to make_response function, and then inside this function (thus problem 2 solved) you can do (you was quite close with your pseudo-code, actually):

encoded_images = [b64encode(obj.image) for obj in objects]