How to include binary data into HTML5

… without getting cross-site-scripting problems on local files / server less testing.

For some 3D data representation i needed some MB binary 3D data to be included in the HTML side for further use in threejs. The file should be useful for standalone opening after email-sending – loading data from a fileserver wasn’t a an option though. On the other hand writing 8bit data points into asciitext wasn’t an option either, because such file fast becomes to big to be handled properly: each datapoint 8bit needs to be represented by 1-3bytes plus separator or by 3 bytes fixed length and both would pump up the file size. Another option would be a base64 encoding of the raw binary data which also might be compressed (zipped) before encoding resulting in an about 1.3 larger b64 asciitext, that can be unzipped and parsed to regain the data. This solution is smart but involves „unzipping to get the asciitext“ meaning that there has to be imported/bundled a fast and reliable javascript zip-library.

This is what i finally came up with:
1. write the 8bit binary data into a png file
2. base64 encode the resulting run-length compressed png file
3. use <img src="data:image/png;base64,...."> to include that into the html5 file
4. create a hidden canvas of appropriate dimension and use context.drawImage and context.getImageData to extract the binary data which is now stored in an Uint8ClampedArray
5. calculate the needed Float32Array(s) for threejs from that Uint8ClampedArray

Note on step 1: you’ve the choice to use all 24bit of the pixel matrix in png (four 8bit binary data -> 1 pixel in png) and have some data length information elsewhere in your javascript to manage padding problems that might come up eventually. The lazy way is to encode only 1 Byte per pixel (grayscale png) and rely on the run length compression to deal with the resulting duplications. In the latter case, make sure you extract each forth value from the canvas context.getImageData method result.

This python code will provide you with the base64 encoded png data:


from PIL import Image
import base64

fle = file("testdata.bin") # binary data: 12960000 bytes
im = Image.frombytes('L', (3600,3600), fle.read(12960000))
im.save("testdata.png")

b64 = base64.b64encode(file('testdata.png').read())
b64 = '<img id="dimg" src="data:image/png;base64,%s">'%b64 
file('testdata64.html','wb').write(b64).close()