How to inline your sparklines/images in PHP with data: URIs · 3. Mai 2005, 14:45

During the last couple of days you may have seen a link going around to an article over at bitworking that explained how you can (very easily) inline your sparkline images into your html pages with a python library. Of course this is not bound to the language, so here is how you can do this in PHP.

Hold on – what are sparklines?

Good thing you asked, because you are really missing out on something! Take some time and read the article Edward Tufte has written about sparklines. In short, sparklines are data-intense wordlike graphics, that have the intensity of visual distinctions comparable to words and letters. They can convey lots of information in little time and little space. Here is a great example from Tufte’s site:

Ok, so what are those data: URIs?

Usually an image has a Link in the src-attribute, so when a user loads the html page, the browser sees there are references to image-files, and fetches those images with further requests to the server. data: URIs allow you to embed the encoded image file right into your html page and the browser will recognize and display them, without any further requests. Let’s look at an example:


Regular:
<img src="/images/21.png" alt="sparkline" />
data: URI
<img src="data:image/png;base64,iVBORw0KGgoAAAANS
UhEUgAAAFwAAAAWCAIAAADCTmwFAAAA3ElEQVR4nO2YwQ3DIAxFfysGKdM
wRmfLGJ2GjtJDqhyKAzYBB1K/UxA2Nh/HSNxifAEA4JcAID6/w3/mfnYCI
3KOKH4Ja2GOiVUKgYlCYKIQmCgE7UXp10TV2jMhCif24NfHQZpVypVkYol
St2FNr1buK9ZoCUwUgpwoU3fcI4lNUCkKZ/Pj7h4+AHhH1ouByDj1St05U
6IFOcbFoG4bby8pmQ+RceZpRjQlWpBjXAzq9ux6kB6ptOgqvDLGe/moiiK
Cs/M6TYu4TutK0UyjGGuC20cf2e+j0AJG4AOYG4/WPzawWgAAAABJRU5Er
kJggg==" alt="sparkline" />

Here is the regular image: and here is the embedded one: sparkline. And some of you already see the biggest problem with data: URIs – they don’t work in Inter Explorer. But they do work in Mozilla-based browsers (for at least ~2 years), in Opera (since 7.20), and in Safari (starting with 1.2). Given that RFC2397 is from 1998 it’s about time we start using them. (Give me some credit, I am trying hard to refrain from making snide remarks about outdated browsers here.)

Sparklines & data: URIs are a perfect match

Sparklines & data: URIs are a perfect match, for several reasons:

  1. sparklines are “wordlike” and therefore really belong to the text. When pages get saved or emailed, it is often easier to handle a single document, than several different ones.
  2. sparklines are small in size. Some browsers limit the maximum possible size of attributes to a few kb.
  3. sparklines in data: URIs save the overhead of multiple HTTP requests for the images. The request- and response-headers for my image above are about 1147 bytes – for an image that itself is only 277 bytes in size. You do the math. And this is not even counting what’s happening server-side, where you may save db-queries and processing time.

Now, how do I do that in PHP?

The good news is, somebody already did most of the work. You can find a php-library for a set of sparklines illustrated with a couple of code-examples on sparkline.org (you will need GD-support in PHP). I won’t go into how to use the libraries, because the provided examples really do a good job of that. The library currently only supports output to the browser and to a file, so I’ll show you how to get that image into a php $variable so we can put it into a data: URI. We will use output buffering to achieve that. If you open sparkline.php from the library, you will see there is a function:


function OutputToFile($file) {
$this->Output($file);
} // function OutputToFile

Below that add this new code (explanation follows below):


function OutputToDataURI() {
ob_start(NULL,4096);
$this->Output();
header('Content-type: text/html');
return "data:image/png;base64,".base64_encode(ob_get_clean());  
} // function OutputToDataURI

Line 1: We initialize an output-buffer, and bypass the need to assign the (optional) callback-handler by passing NULL. We do this, so we can pass the second parameter, which assigns the buffer-size, i.e. how much memory will be reserved for the output. If this value is too large (defaults to ~40kb), then your script will use a lot more memory than necessary, if it is too little, your script will automatically flush the buffer to the browser, so you won’t get your image and your users will see garbled output and funny characters. For my purposes 4kb was plenty. Line 3: We have to reset the header, otherwise the browser will exepct a png-graphic rather than an html page. This is a bit of a hack, take a look at the Output function and you will see a better way of doing this, but for demonstration purposes this will suffice. Finally the function returns a string that can be used in the src-attribute of an image-tag as is.

So to use this in, say the baseball-example from the library you would replace


$sparkline->Output();

with this line:


echo '<html><body>See: <img src="'.$sparkline->OutputToDataURI().'">';

That’s it. Happy sparkline-data:URIing now (yes, it’s in the dictionary, look it up;) ).

Addendum

If you have a heart for users of outdated and crappy browsers (there, now I did it, SCNR), you will want to sniff for the browser, and only serve the data: URIs to browsers of today. The way I currently do it is with this:


if (

preg_match('#Opera [789]#', $_SERVER['HTTP_USER_AGENT']) || preg_match('#AppleWebKit/[1-9][0-9][0-9]#', $_SERVER['HTTP_USER_AGENT']) || preg_match('#Gecko/200[4-9]#', $_SERVER['HTTP_USER_AGENT']) ) { ... // inline data: URIs rfc2397 } else { ... // hello IE }

And a heads up for commenters: textpattern may eat parts of your comment if you try to post code. Please either “escape”/transform code snippets manually by watching the preview function, or link to a code-snippet elsewhere. Sorry for the inconvenience.

Further Reading:


|