Tuesday, April 24, 2012

Access Cross Origin Images from WebGL/Three.js



Screen capture of WebGL/Three.js demo showing images hosted on cross origin server
Demo: http://theo-armour.github.com/threo.js/cube-demos/webgl-cubed/index.html
Source Code: https://github.com/theo-armour/threo.js/tree/gh-pages/cube-demos/webgl-cubed

One of the beautiful things about an HTML web page is that the page can can grab images, style sheets and JavaScript from just about any server on the web. The cross-origin feature enables third-party ads to be displayed, visitor statistics to be monitored, jQuery code to be updated automatically and much much more.


Since the beginning of the web all the abilities to access data from origins that were on different servers or had different host names was also available to developers. Quite recently, however, it began to be clear that malicious code could be embedded in images. Therefore in recent months the developers of the major browsers have been adding updates to prevent program access to cross origin images. These safeguards have been added to Ajax (XMLHttpRequest), the Canvas tag, dynamic loading and more. Whatever method you used to do to bring in images to a web page using JavaScript probably no longer works today.

Except for one.

[ Otherwise we wouldn't have a post, would we? ]

Even if a JavaScript program cannot call and download remote binary images, it can still call for remote JavaScript code to be sent to the current web page.

The almost self-evident and brilliant answer is therefore to turn images into JavaScript - to re-encode the binary image data as ASCII strings in base64 format. This process is used on a regular basis: The MIME protocol turns images into ASCII every time an image is sent by email.

The process for re-encoding images is very simple. There are a number of web sites that will do the re-encoding for you.

http://dataurl.net/#dataurlmaker
This site allows you to drag and drop an image and then displays the ASCII text nearly immediately.

http://www.greywyvern.com/code/php/binary2base64
This site allows you to paste in an URL. It also provides examples as to how you can embed the code in a web page or program.

Here's what the code to an embedded image looks like:

<img alt="Embedded Image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA..."> 

When you look at the demo, you will note that it loads fast - after all all the code is in a single file rather than in a seven files: http://ta.capnix.com/webgl-cubed/webgl-cubed.js

Also, if you are familiar with JavaScript, you will see that the code is quite simple. There's not a lot to learn. 

Currently it will take you a few two or three extra steps to prepare base64 encoded images. My guess is that in the near future there will be routines that will grab images off a remote web site - such as Flickr - and re-encode the images dynamically. In the mean time, I hope that I have provided you with with a nice way to prevent the loss of your good image...

Update 1 ~ 2012-04-25
>> in the near future there will be routines that will grab images off a remote web site
>>- such as Flickr - and re-encode the images dynamically

Nihilogic explains how to read binary images and extract JavaScript in near-real-time here:
http://blog.nihilogic.dk/2008/05/compression-using-canvas-and-png.html

Similar code could be used to read binary image data and re-encode it to base64.

Update 2 ~ 2012-04-28
PatrickH points out that this post does not mention Cross-Origin Resource Sharing - an industry standard which enables truly open access across domain-boundaries.

My bad.

For example, Picasa is one web service that already supports CORS

I plan on writing a post that covers the aspects of when CORS is best, when embedding is best and when some type of 'hot-linking' might be suitable. .