dean.edwards.name/weblog/2005/06/base64-sexy/

Base64 Encoded Images for Internet Explorer (sexy version)

As promised here is the sexier version of yesterday’s Base64 solution for Internet Explorer.

I have a function which I need to apply to image elements in the page:

function fixBase64(img) {
	if (BASE64_DATA.test(img.src)) {
	    img.src = base64Path + "?" + img.src.slice(5);
	}
};

The obvious solution is to add the following onload event handler:

onload = function() {
	for (var i = 0; i < document.images.length; i++) {
	    fixBase64(document.images[i]);
	}
};

There’s nothing wrong with this. You’d have to do some browser sniffing of course. You only want this to apply on Internet Explorer. Also, this is not a dynamic fix, any new images would need to be fixed as well. Here is an alternative way of fixing the image using CSS:

img {behavior: expression(fixBase64(this));}

This works. The CSS behavior property is nonstandard so we’ll abuse it for the sake of this fix. Internet Explorer supports dynamic CSS expressions, so we abuse these too. There is one downside. Expressions are evaluated every time an event occurs on the page (even mouse moves). So we need to “turn off” the expression. We do that by amending the fixBase64 function:

function fixBase64(img) {
	// stop the CSS expression from being endlessly evaluated
	img.runtimeStyle.behavior = "none";
	// apply the fix
	if (BASE64_DATA.test(img.src)) {
	    img.src = base64Path + "?" + img.src.slice(5);
	}
};

Setting runtimeStyle.behavior to “none” effectively turns off the expression.

Now we have an IE-only solution that is applied dynamically. If new images are added using DOM methods then they will automatically be fixed. This technique can be used in other IE-only solutions. It is fast, dynamic and does not require any JavaScript browser sniffing.

If you are feeling really ambitious you can wrap up all the JavaScript code into a single expression:

img{behavior:expression((this.runtimeStyle.behavior="none")&&(/^data:.*;base64/i.test(this.src))&&(this.src="/my/base64.php?"+this.src.slice(5)))}

Examples:

Comments (36)

Leave a comment

Can this technique also be used to create the 1×1 transparent gifs required for PNG to work in IE? The old XBM worked great but got broked in SP2:(

  • Comment by: Jon B
  • Posted:

Same question as above ? Microsoft has broken the XBM in SP2 !

  • Comment by: rickman
  • Posted:

Rickman/Jon – The answer is yes. It requires a call to the server for IE but works as expected for modern browsers. See the previous post for full details.

  • Comment by: -dean
  • Posted:

Weirdly, the image appears for an instant in Safari 1.3, and then is replaced with the missing-image icon. No clue as to why yet, but I’m keen to find out– once it’s made cross-browser friendly, adding this ability could be a huge improvement to S5. (And yes, I know I could script to not run the routine in browsers that don’t need the fix, but I’d still like to find out why it acts the way it does in Safari.)

  • Comment by: Eric Meyer
  • Posted:

If I read this correctly, you’ve moved the content of the image to the HTML file, but you still have to go back to the server to fetch the actual image. Correct (base64.php)?

Eric, I don’t have access to Safari 1.3. Are you saying that it does not support Base64? Or that this solution is breaking Safari somehow?

  • Comment by: -dean
  • Posted:

If I read this correctly, you’ve moved the content of the image to the HTML file, but you still have to go back to the server to fetch the actual image. Correct (base64.php)?

Not quite. He’s moved the content of the image to the HTML document, and that is all that modern browsers need. Internet Explorer is retarded in this respect, so we need to give it a short bus (base64.php) to ride on. So Internet Explorer will go back to the server to get the image, but the other browsers already have all they need, so they don’t need to go back to the server for anything.

  • Comment by: Jim
  • Posted:

The second and third demo URI worked fine on Safari 1.3 on my side; the first one (/my/base64-ie.html) had the same problem as described by Eric.

No errors in the Javascript console, the activity window reports the image as loaded.

  • Comment by: Philippe
  • Posted:

Phillipe, thanks for checking this out. The demos work as expected. The first example does not do any browser sniffing so it will break on all non-IE browsers. The other two examples should work on most platforms.

  • Comment by: -dean
  • Posted:

Some guys are saying that this feature isn’t useful at all, or that its advantages aren’t very clear. Under some circumstances I would agree with them, but I have a case where I do need this feature to work on IE as in Firefox:

I have a web application that stores information about products. You can attach a photo to a product, using an <input type=file> control. But my app allows to insert more photos, so when you insert one, you haven’t saved the changes yet to the product. When this happens, I have to show the submitted photo with this method (inline) because I don’t want to store it into de DB yet, and I don’t like to use sessions or temp directories on my server. Another <input type=file> control is shown to allow insert more photos, and when the user is done, he will click apply…

I am expecting the new release of IE7 that allows to do this client side, it will be very useful.

Regards,

knocte

  • Comment by: knocte
  • Posted:

Another case where this feature is very usefull :

If you store some information containing image to XML. For example imagine an <article><title>A title</title><image type=”image/png”>KJFD445F4DFD53F1D…</image></article>

You can transform it with a single XSLT to HTML as <h1>A title</h1> <img src=”data:image/png;KJFD445F4DFD53F1D…” />

Otherwise you must use several XSLT with complicated infrastructe in the server side.

However i’m wonder if this trick support large base64 data ? I believed that there was a limited size for a GET request ?

  • Comment by: Guillaume Bort
  • Posted:

I believed that there was a limited size for a GET request ?

I’m certain there is. This solution is probably good only for icons and the like.

  • Comment by: -dean
  • Posted:

Dean, Is there a way to decode the base64 using javascript so that a totally JS solution can be made?

Also, I’ve tried “sexy” with other base64 images and can’t get them to display in IE. Is there a limit to the size of the image (length of the base64 string)?

Lastly, can anyone recommend a web-based tool for converting images to base64?

  • Comment by: AlanH
  • Posted:

Dean,

I like this work-around. I’m implementing it into the agoracart.cgi script to display images on certain pages that will not allow image links.

My problem is that I am not able to get the php script you have posted on the previous page to work on my site. (The majority of my site is php…)

I created the base64.php in the root folder using the php script you posted on the previous page.

Also in the root folder is test.html (http://www.radiorax.com/test.html) which is a copy of your /my/base64-sordid.html source. test.html works great in IE when I link to base64.php on your site, but not mine.

Do I have all of the php script? What am I doing wrong?

Thanks, Mark

  • Comment by: Mark
  • Posted:

Hi Mark,

if you didn’t solve your problem so far (I had this one too)…here is a possible solution:
It depends on the server configuration if you are allowed to get access to the value $_SERVER['REDIRECT_QUERY_STRING'] or not. You can replace
$data = split(';', $_SERVER['REDIRECT_QUERY_STRING']);
with
$data = split(';',substr($_SERVER['QUERY_STRING'],strpos($_SERVER['QUERY_STRING'],'?')));
if you are allowed to use this variable. No idea if this helps you, but it worked for me.

Many thanks to Dean for this nice workaround… :o)

  • Comment by: strayer
  • Posted:

Hello,

I created a workaround converting the HTML page in a Mime Multipart MHTML. Please, send me a feedback.

http://www.lsc.ufsc.br/~luizd/base64-to-mhtml/workaround.html

Ok – this one annoys me.

If the all standards all the time browsers actually supported all the standards, like MHT, then this would not even be an issue. IE has supported MHT for as long as I can remember.

Open up IE, open up any webpage on the net (that doesnt call in content dynamicallly), go to File, Save As – change the ext to MHT.

Take your computer offline – go find that file you just saved. Move it to new folder on a different drive.

Open it.

…..and its all there.

So while IE may not have an image tag support for what you want, they do indeed, and have for a long time, support base64 in the page. To use it on the web though, since IE is the only one that supports the standard on it, is put in a sniffer up front, and serve your html to the non standard compliant browsers like Firefox, and serve up the MHT to IE.

(yea, and I just wanted to be able to say that last sentence – not looking for a my browser is bigger than your browser thing)

  • Comment by: Zach
  • Posted:

One other note – I meant doesnt call in content dynamically, like xmlhttp or using javascript to append new js to the header – it will include all normally linked js, css, Images, etc

  • Comment by: Zach
  • Posted:

Thanks Strayer and Dean!!

That workaround worked perfect for me!!

  • Comment by: Kevin
  • Posted:

Some interesting things:

– Data URL:

We (You) can use this :

var xx=”data:image/png;base64,abcd . . . .” then

img.src=xx; This case we an embed a fairy large image – 60K??

or Javasscript URL

convert the base64 to binary string then

img.src=’javascript:binary’ or

img.src=’javascript:MyFunction()’ this will work only if the second part following the “javascript:” change every time otherwise the image won’t change

Sorry Even IE said they support Javascript:URL But this is not the case. It only works on XBM ???

( If you giud need the source for those I think I can help)

They are working GOOD (but not IE)

However this is IE specific problem (always):

– base64Path + “?” + img.src.slice(5); Only work on small amount of base64 data.

Work-Around for IE

– Put the base64 in a textarea of a form

– convert it into a binary file save it as a temfile at the server

– Set the img.src to that temp file

– One more trip to the server to delete that temp file

If you need furthe info you can email me then I will answer back. (I try)

Phi

  • Comment by: Phi Tran
  • Posted:

One more . . .

There is also another work-around by creating multiple div or table each has its own color.

Theoretically it works.

But: – IE will screw you up when the amount of total element goes more than about 5000s – I do not have a exact number.

– FF works for that amount but it slow you down every time you scroll a page or process an event.

Phi

  • Comment by: Phi Tran
  • Posted:

I’ve tried using VML(v:imagedata) and HTML+TIME(t:img) in IE, but still It doesn’t accept things like data:image or javascript: decode(blah); obviously they use same code to deal with the data src attribute.

I also tried using (client-side) dynamically generated mht file into an iframe, and invoked document.open, document.write and changed the doctype to message/rfc822. It doesn’t work, too; furthermore MSDN tells us document.open can only accept text/html. But I think maybe some hacks can work this around?

Then I looked for some windows native ActiveX that we can play with. Unfortunately I failed to find a good one. There are many,undocumented.

I hope these will be useful information for you.

  • Comment by: tkirby
  • Posted:

hi i want new sexy ptoto

  • Comment by: mohammad
  • Posted:

Mohammad, I assume you mean new “sexy potato”. No problem – just type “sexy potato” into images.google.com and enjoy.

  • Comment by: spike
  • Posted:

The best possible use of base64-coded images is describing images in external CSS sheet (background-image), so it loads only once, reduces cache load, displayes small images (gradients for instance) faster (i omit IE), but this implies using a bit different script and CSS in there

.some_element { background-image: url(data:....) }
* {behavior:expression(XXX)}

where XXX – same as before, but .style.background-image instead of .src

But for my managed site i used a bit simplier solution – conditional comments to overwrite styles of those elements, who’s background image is set as base64 encoded data, by direct urls to normal images

PS my site’s first update is going to include such embedded base64 encoded images inside CSS (already calculated – increase in size of CSS file is ~2Kb for a total of 7 images)

  • Comment by: Platinum
  • Posted:

Hi! i would like to know if there there is any way to make possible IE (version 6) to decode base64 data files. This code it’s very nice, but i think that a lot of people still use the version 6:( I already tried other codes… but notinhg works correctly and i’m starting to be so frustrated! i really would thank you some kind of help.

best regards,

Anabela

  • Comment by: anabela
  • Posted:

To bad this is all not working…. stupid IE

  • Comment by: TheYOSH
  • Posted:

The solution with the many divs / table is very good. It is right that the browser will slow down if there are too much DOM nodes in the page but you can work around this by grouping the elements (divs). For example 100 divs can be pushed into one div which directly is pushed into the page and the next 100 divs in the next one.

I think this is the only solution for this problem at the time.

Regards,

Rögi

  • Comment by: Rögi
  • Posted:

A simple question to ask here. I am using the following code to generate a png.

img src=”data:image/png;base64,$string”

However i am not able to decode the string into the image. I am using php function base64_decode to convert into base64. but for some reason its not showing correctly. Can someone correct the bug for me? Thank you in advance.

  • Comment by: Junwei
  • Posted:

wonderful solution.

but i don’t think it is possible to fix all ie’s error by ourselves, just let ie go to hell.

  • Comment by: ashi
  • Posted:

Hi Dean,

Instead of PHP can we do the same in .NET ? Please reply.

  • Comment by: Bharati
  • Posted:

[…] 不过CSS Expression在patch IE方面其实还可以发挥更大的功用。Dean Edwards首创了一次性执行experssion的模式,巧妙的利用了IE的内建Selector机制,同时又避免了experssion被反复计算的性能问题。这种模式被许多patch所使用。例如Peter Nederlof的hover/active/focus伪类补丁。 […]

[…] 不过CSS Expression在patch IE方面其实还可以发挥更大的功用。Dean Edwards首创了一次性执行experssion的模式,巧妙的利用了IE的内建Selector机制,同时又避免了experssion被反复计算的性能问题。这种模式被许多patch所使用。例如Peter Nederlof的hover/active/focus伪类补丁。 […]

Hi all, It seems that none has answered one question, whether or not can we be able to decode the base64data in javascript itself rather than using the decode php function?. If so, pls mail/publish the code. Thanks, Nagender

  • Comment by: Nagender
  • Posted:

Javascript base64
but i don’t see what u get if u decode the image on the client side … raw image or base64 … IE will still be a problem

  • Comment by: TBog
  • Posted:

[…] 回复: http://dean.edwards.name/weblog/2005/06/base64-sexy/ […]

Comments are closed.