Base64 Encode Images With Django

L

ately, having spent a good deal of time in the mobile web realm, I have increasingly become more of a performance freak. For mobile websites one of the biggest performance killers is doing HTTP requests. It takes a lot of time to setup / tear down the connection. The transfer rates tend to be rather terrible and they chew up battery life. I noticed that images were the biggest culprit of excessive HTTP traffic. Not only from the HTML itself, but CSS background images, which many web developer tend to forget about, can really slow things down. One easy solution around this is to Base64 encode the images and either deliver them in the style sheets or HTML itself.

So I thought to myself - You could probably do this pretty easily with Python & Django for any website and make load times faster. Here is how you might go about doing that. First lets set up a simple Django Model for handling the image it self.

from django.db import models
class Photo( models.Model ):
    title = models.CharField( max_length=255 )
    image = models.ImageField( upload_to="photos/", max_length=255)

Simple enough. It doesn't do much, but it doesn't really need to. The only thing left is to add a single method that will return a URI for display in a web browser. It might look a little something like this:

@property
def image_url( self ):
    try:
        img = open( self.image.path, "rb")
        data = img.read()
        return "data:image/jpg;base64,%s" % img.encode('base64')
   
    except IOError:
        return self.image.url

Ya, That's it! Python strings have an encode function that accept one of a number of encoding types. One of which is "base64". Python does all the heavy lifting and all you need to do is build a string that looks like a data URI. We want to wrap it in a try block because if anything goes wrong in that step, you will still want to fall back to the default Django behavior so something shows up and your users won't be presented with a 500 Error page. Here is what it looks like in it's entirety:

from django.db import models
class Photo( models.Model ):
    title = models.CharField( max_length=255 )
    image = models.ImageField( upload_to="photos/", max_length=255)
    @property
    def image_url( self ):
        try:
            img = open( self.image.path, "rb")
            data = img.read()
            return "data:image/jpg;base64,%s" % data.encode('base64')
    
        except IOError:
            return self.image.url

Using it in your Django templates is even easier. You just access it as a property off of the Photo object in the template, and you are good to go

<img src="{{ photo.image_url }}" />

It couldn't get any easier. And anything goes wrong during the encoding step, it will still output the actual image url. This, of course is an over simplified example, and you may want to use this method with image thumbnails and of your own custom logic. I would also reccomend looking into Justin Driscoll's awesome Django project ImageKit, which is the successor to the Photologue project.