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
Comment: #1
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: #2
Same question as above ? Microsoft has broken the XBM in SP2 !
Comment: #3
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: #4
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: #5
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)?
Comment: #6
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: #7
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: #8
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: #9
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: #10
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: #11
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: #12
I’m certain there is. This solution is probably good only for icons and the like.
Comment: #13
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: #14
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: #15
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: #16
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
Comment: #17
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: #18
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: #19
Thanks Strayer and Dean!!
That workaround worked perfect for me!!
Comment: #20
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: #21
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: #22
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: #23
hi i want new sexy ptoto
Comment: #24
Mohammad, I assume you mean new “sexy potato”. No problem – just type “sexy potato” into images.google.com and enjoy.
Comment: #25
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: #26
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: #27
To bad this is all not working…. stupid IE
Comment: #28
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: #29
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: #30
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: #31
Hi Dean,
Instead of PHP can we do the same in .NET ? Please reply.
Comment: #32
[…] 不过CSS Expression在patch IE方面其实还可以发挥更大的功用。Dean Edwards首创了一次性执行experssion的模式,巧妙的利用了IE的内建Selector机制,同时又避免了experssion被反复计算的性能问题。这种模式被许多patch所使用。例如Peter Nederlof的hover/active/focus伪类补丁。 […]
Comment: #33
[…] 不过CSS Expression在patch IE方面其实还可以发挥更大的功用。Dean Edwards首创了一次性执行experssion的模式,巧妙的利用了IE的内建Selector机制,同时又避免了experssion被反复计算的性能问题。这种模式被许多patch所使用。例如Peter Nederlof的hover/active/focus伪类补丁。 […]
Comment: #34
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: #35
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: #36
[…] 回复: http://dean.edwards.name/weblog/2005/06/base64-sexy/ […]
Comments are closed.