Generate client-side PNG files using JavaScript
It was once again one of those nights where I hacked like on drugs with no end in sight. Sure, 5 years ago you had loved me with such a project, but in times of HTML5 with the canvas element it is hard to impress you. So take it as proof of creating client side images without canvas, SVG, or server side rendering and AJAX processing.
But how is this possible? Well, I've implemented a client-side JavaScript library like libpng which creates a PNG data stream. The resulting binary data can be appended to the data URI-scheme using Base64 encoding.
The next step would be implementing shapes and forms to allow an easier image manipulation, but I think this is not necessary. I just wanted to learn the PNG file format, who wants to use the library can implement the rest by himself. At the moment it's only possible to write colors to a certain pixel position. I do not recommend a production use of this lib without input validation. The class is really spartanic, but it works :)
But enough of preface, let's dig a little deeper on how we can use the library. I wrote a little example which looks like this:
The implementation is quite simple, but there is still no setter method to set a pixel. You have to access the internal buffer directly with
obj.buffer[obj.index(X, Y)] = obj.color(r, g, b, a);
The complete source of the above example looks like this:
var p = new PNGlib(200, 200, 256); // construcor takes height, weight and color-depth
var background = p.color(0, 0, 0, 0); // set the background transparent
for (var i = 0, num = 200 / 10; i <= num; i+=.01) {
var x = i * 10;
var y = Math.sin(i) * Math.sin(i) * 50 + 50;
// use a color triad of Microsofts million dollar color
p.buffer[p.index(Math.floor(x), Math.floor(y - 10))] = p.color(0x00, 0x44, 0xcc);
p.buffer[p.index(Math.floor(x), Math.floor(y))] = p.color(0xcc, 0x00, 0x44);
p.buffer[p.index(Math.floor(x), Math.floor(y + 10))] = p.color(0x00, 0xcc, 0x44);
}
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
p.buffer[p.index(i + 90, j + 135)] = p.color(0xcc, 0x00, 0x44);
p.buffer[p.index(i + 80, j + 120)] = p.color(0x00, 0x44, 0xcc);
p.buffer[p.index(i + 100, j + 130)] = p.color(0x00, 0xcc, 0x44);
}
}
document.write('<img src="data:image/png;base64,'+p.getBase64()+'">');
The source of the library is based on the libpng and libgd library as well as the PNG documentation. The implementation is licensed under BSD, so feel free to modify and use it in any way.
17 Responses to "Generate client-side PNG files using JavaScript"
Sorry, comments are closed for this article. Contact me if you want to post an inventive contribution.
i have used it like this
what is x and y ..when i work on pixels i dont need x and y it is necessary to specify x,y ...
var p = new PNGlib(height, width, 256); // construcor takes height, weight and color-depth
var background = p.color(0, 0, 0, 0); // set the background transparent
for (var i = 0, n = data.length; i < n; i += 4) {
var x = i * 10;
var y = Math.sin(i) * Math.sin(i) * 50 + 50;
p.buffer[p.index(Math.floor(x), Math.floor(y))] = p.color(data[i], data[i+1], data[i+2]);
}
return 'data:image/png;base64,'+p.getBase64() ;
http://data-demo.appspot.com/#png
It's definitely clunkier in some ways, and it's probably slower, but it does give you more control over the image type, I think.
like this:
function getCode(a){
...
}
getCode([[[200,0,100]]]);//=data:image/png;base64,iVB...
this.getBase64 = function() {
return window.btoa(this.getDump());
}
gives it a bit of a performance boost (does not work in IE).
I have used this library to create animations as an alternative to canvas as per-pixel manipulation is very slow in canvas. Unfortunately, it is also slow at large sizes with this library :(
As for this project? Effin' brilliant. I've been contemplating doing the very same thing myself - now you've taken all the hard work out of it for me! Thanks!
The right transient for the right element gives great flexibility in UI design, epecially when using mootools or jquery...
As per IE users acting up here...
If you opt for having your eyes removed, do not complain about the dark.
But i tried to set the width or height to be more than 255, like 300, then the picture can not be generated, why?
This is a great project!
Hope IE 9 will have base64