Mark Gilbert's Blog

Science and technology, served light and fluffy.

An image is worth a thousand bytes: Images and Data URIs

One of my current projects involves handling images generated from within Flash.  Early on, I made an architectural decision to store those images in the database rather than on the file system of the web server.  Since I was interfacing with Flash, I wrote a series of FluorineFX Web services to save and retrieve the images and associated data.  Data from Flash would come in as a FluorineFx.AMF3.ByteArray and get converted to a .NET Byte array for storage; retrieval would reverse the process.

Everything was just peachy-keen until I had to display those same images in a .NET DataGrid.  My business layer already had the functionality to return galleries of images in one fell swoop.  All I was trying to do was bind that output to the DataGrid, but I wasn’t sure how to bind a Byte array to something that would allow it to render as an image in the browser.

Doing some searching on the internets turned up a very interesting mechanism with the <img /> tag.  Normally, this tag’s “src” attribute needed to point to a URL of some sort.  If nothing else worked, I could always create a handler (GetImage.ashx, or something similar) that would take an ID of the image I wanted to show, retrieve it from the database, and then write it out to the browser.  This handler would become the URL for “src”.  But that would mean the page would have to make multiple requests to the web server, one for each image.  I already had all of the image data pulled together, and wanted a more direct way to render them – as images – to the page.

The interesting find for “src” was that several browsers support inline images, which allow me to set the data for the image (as a Base 64 string) as the value for “src”.  That allowed me to do this in my DataGrid:

<img src="data:<%#DataBinder.Eval(Container.DataItem, "MimeType")%>; 
base64, 
<%# Convert.ToBase64String(DataBinder.Eval(Container.DataItem, "ImageBytes"))%>" />

(The additional carriage returns are presented here for clarity only.)

The “src” tag here breaks down into three parts:

  1. The “data:” directive, which tells the browser that there is a string of bytes coming down, rather than a URI.
  2. The MIME type for the image to be displayed, followed by a semi-colon.  I store this alongside the image data in the database, so this was just another field in my business object to be bound here.
  3. The keyword “base64”, followed by a comma and the string of bytes itself.  The latter is the Byte array returned from the database, converted to a Base64 String.

The feature goes by the more formal name of “data URI”, and has been supported by most browsers for a good long time (see this forum post from 2004, which is what got me going down this road to begin with: http://www.velocityreviews.com/forums/t89692-how-to-display-in-memory-image.html). 

I say “most” because Internet Explorer prior to version 8 does not support this at all.  Version 8 supports it in a limited way – only certain tags, and a limit of 32k for the file size (see http://www.websiteoptimization.com/speed/tweak/inline-images/ or http://en.wikipedia.org/wiki/Data_URI_scheme).  Internet Explorer 9 reportedly removes many of those restrictions (again, see http://en.wikipedia.org/wiki/Data_URI_scheme).

The advantage here is that I don’t have to write a handler page just to retrieve the image – I can directly drop these into the DataGrid.  That means fewer requests to the server to get the images down to the browser.  However, one of the disadvantages is that the images can no longer be cached by the browser – the image data has to be sent down with every request.  That didn’t really affect my particular scenario – I was building an admin tool for a community manager to review images submitted by the users, and each image would only likely be viewed once (during the actual review) by that one person – but this may not be a good approach for a public facing site getting lots of visits. 

Some of the articles I was reading suggested using this technique for very small images – images where the amount of data being sent is so small that it makes it more cost effective to just send the data down with the rest of the markup and save an additional request to the server.  With larger images, like photos, it probably makes more sense to map a unique URI to each image so the browser (or a CDN) can cache it.

At any rate, while this was not new for the web in general, it was new to me and I was so impressed with how easy this feature made my job that day that I wanted to share.

Advertisements

January 24, 2011 - Posted by | Visual Studio/.NET

Sorry, the comment form is closed at this time.

%d bloggers like this: