Images as Data URI in Drupal

Data URI's is a way to take your external images and put the binaries inside the html document or a css document. Why would you want to do this? The gist of it all is that it's sometimes faster and more scalable to transfer fewer larger files then more smaller files. Let's see if this is true and how we can solve this.

So for sake of purpose this post will be loaded with images. Some might not have that much to do with the subject I'll write, but this is done so you can look in the source code and see what's happening behind the hood. If you right click Matt Damons pretty face you will see that you can't actually download that image. That's because it's loaded via CSS. If you right click on the last animated gifs on this page it will be an even stranger url.


Like it's not enough that I'm stuck on you, now we seem to be stuck together with all those other images.

Data URIs

<img src="/this/is/a/test.jpg" />

So the above example is a normal way of showing an image in a document. In the markup that the user downloads you tell them where they can find the image that they need to download. Data URIs is a basically that you instead of saying "hey, get this image", you give them the image already in the markup. It might look something like this.

<img src="data:image/jpg;base64;fRdafm54DA5sEAdf54ASDF21313fasdfeADSF" />

This might speed up your website since the second call with all it's overhead will not have to be done. So you save one http call.

You can also put this in CSS as well meaning that you can try to find an optimal size of files and split for instance 10 images into 3 files instead of 10 files.


You all seem to forget. I'm not merged with your images, YOU ARE MERGED WITH ME!

How can this be done in Drupal

There are multiple ways to solve this in Drupal, from fixing the theme to writing it directly in the code. But of course for some of you the best way would be if Drupal itself takes care of this. So today there already exists a module that takes care of all images that are stored in CSS - the CSS Embedded Images module. There also exists a base theme that can do this - Sasson

But I wanted to be able to automate the process for images that are placed in articles etc. as well as be able to have pretty broad way of filtering which images should be made into Data URIs, so I created a module for this. The module is still sandboxed, but as soon as I consider it developed enough I will release an alpha version and write a post about how to use it. If you want to test it before that it's your own responsibility, I will not support it until it becomes a full project.


Can't you just please let it go.

Still, why?

So to be honest there is only two reasons why you would want to do this - speed and scalabilty. Which comes from fewer http requests. 

The reasons why not to do this have much greater logic:

  • SEO - Say good-bye to Google Images
  • Heavy - The processing power for PHP to do this is cumbersome. So if you want this it has to be at places where you can cache.
  • IE 6 - As always Internet Explorer 6 can't do anything correct, neither this.
  • Responsive Design - This might just be a temporary bug until i figure it out. But right now the images needs to have fixed width and height since they aren't really images. This brakes responsive design CSS as anyone surfing on a mobile might see.
  • Bigger - The files actually get's a little bit bigger since it's base64 encoded. Gzip helps out with the most of it though.
  • Slow - On mobile devices it takes much longer to render the images because the client needs processing power for it. Not a major issue with the newest phones though.
  • Client cache - If you do inline caching in the actual document instead of in CSS, then the images will not be client cached since the base document usual should not be cached.

So basically you should only implement this on a very specific segment of images on blogs or newspaper sites where everything is cached and where ms count.


​What is truly logic. Who decides reason?

Benchmarks

First of all - creation of the PHP on this page is about 25% slower or 27 ms slower when adding this script. So as written before, do not use this anywhere where you can't cache. If you want to be able to optimize this for non-cachable website please manually use the theme_combinedimages() that is included in the module.

So doing benchmarks on loading time is always hard since there can be so many bumps along the way that invalidates your benchmark, so take this for what it is. I will do a benchmark between loading the images on this actual page using either the normal way or using both css images and inline images. I have tested back and forth with the settings of when images should be inline and when they should be put in CSS to get optimal speed. I will then run JMeter against this page. The first test will run 100 times with 1 concurerent connection to get a average speed. The second test will run 1000 times with 50 concurrent connections startloaded over 10 seconds, to check scalability.

For this test I of course removed all external Javascripts that takes time to load, so it was just internal resources being loaded. Everything was cached. I removed the expiry headers in JMeter so it downloaded all resources over and over. In the case of Data URI images I put all images over 20kb into CSS files, while the once under that is presented directly in the markup of the page. The CSS files splits every 200kb into a new CSS file, since that seemed optimal.

Test 1 - 100 call after each other

SYSTEMSAMPLESAVERAGEMINMAXStD.DEVERROR%THROUGHPUTKB/SECAV.BYTES
Data URI100132910521896265.410%45.1/Min510.71695739.8
Normal Images100143412082330184.180%41.8/Min404.7594691.0
 

Test 2 - 1000 calls with 50 concurrency

SYSTEMSAMPLESAVERAGEMINMAXSTD.DEVERROR%THROUGHPUTKB/SECAV.BYTES
Data URI1000123291863334213976.90%2.9/Sec2076.05693906.8
Normal Images1000128212382289433142.20%2.8/Sec2038.02594691.6
 

Conclussion

Using Data URI images is a little bit faster, but hardly recognizable. Importance is also how the images are loaded in order and pretty much the methods are the same.

During load the difference is also not really measurable - but I actually think I might have capped my internet connection on that one since the KB/sec matches my 16 Mbit :) So this data might be pretty irrelevant. I will probably retest next time I go to my Swedish apartment with it's 1Gbit line, the German Internet sucks balls. 

Anyway the conclussion is - for almost any sites don't use it. For CSS use spritemaps instead. For images make sure they are compressed correctly. Over and out!

And lastly - some cute kittens:

And here comes some small gifs that will be inline content instead of loaded via CSS (check the markup source code):

The top photo above was taken by Dave Walker and is used under the CC 2.0 licence.