I recently had the requirement, to open
base64 encoded images in a new window. "
Easy task" I said to myself, and just passed in the
base64 encoded image source to
window.open(). This works, since the
.open() method can handle pretty much everything a browser can display. See
MDC Doc Center.
However, this approach has a major downside. All the image data information goes right into the
browsers address bar!
Whaeerrhhg, not only this looks terrible, it will also
slow down the action if you try to open some "big"
base64 encoded images with this technique.
Example:
(You can execute a code snippet, by right-clicking it)
window.open("data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D", "large");
So that was not an option, because I had to deal with lots of big images.
My idea was,
not to pass an image data-uri directly, but to pass a
data:text/html; string into
window.open(), to magically create a little
DOM tree in the newly created window. Looks like:
var largeprev = window.open('data:text/html;charset=utf-8,' + escape('Hello, I was created through a data uri
'), 'large');
As we all know,
window.open() returns a
DOMWindow object. This reference can be used to
access / modify the contents of that window (only restriction, the
SOP (
Same Origin Policy) will take effect here!)
So my plan was to do something like this:
jQuery('
', {
src: "data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D",
click: function() {
var largeprev = window.open('data:text/html;charset=utf-8,' + escape(''), 'large'),
that = this;
largeprev.addEventListener('DOMContentLoaded', function(e) {
largeprev.document.querySelectorAll('div')[0].appendChild(that);
}, false);
}
}).prependTo(document.body);
I could not wait to test the code. Opened Firefox (3.6.x.) and executed.. it worked great!
Woohoo! Test it yourself
here
I was pretty confident that this will work cross browser (at least, in all browsers that support Data-URIs), but to my shock neither
Chrome(
9) nor
Safari (
5) were able to run the above code.
The problem is,
Webkit seems to treat the returned
DOMWindow, like a foreign domain document. In other words,
Chrome and
Safari apply the SOP restrictions to a window, that was created with a Data-URI. AFAIK, a
data: resource should inherit the "
document.domain" from the environment in which it was encountered. I've sent a request for clarification to the
whatwg already.
For now, the only working cross-browser solution, is to invoke
document.write() like so:
jQuery('
', {
src: "data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D",
click: function() {
var virtualdom = '
',
prev = window.open('', 'large');
prev.document.open();
prev.document.write(virtualdom);
prev.document.close();
}
}).prependTo(document.body);
The above code does not get rendered correctly. The
virtualdom variable looks different, see the code in
Action.
---
Update:
I was just informed by a whatwg member, that there is an open ticket for Chrome at least:
http://code.google.com/p/chromium/issues/detail?id=58999
So, I guess this will get fixed in future versions.