Robert Eisele
Engineer, Systems Architect and DBA

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()+'">');

Download PNGlib source

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.

You might also be interested in the following

17 Comments on „Generate client-side PNG files using JavaScript”

webos-dev
webos-dev

how to load my pixelarray to this png ?
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() ;

webos-dev
webos-dev

where is the js library ?

Chuck McCallum
Chuck McCallum

Here's another library for PNGs via JS:
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.

LePe
LePe

i am searching a smaller libary (without prototype)
like this:

function getCode(a){
...
}
getCode([[[200,0,100]]]);//=data:image/png;base64,iVB...

Andy
Andy

Using the browsers built-in base64 encode:

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 :(

Josh Marinacci

I love this library. I was wondering if you've made any improvements to it since you first released it. I've noticed it can get slow when the image gets larger, so before I dive into performance optimization I thought I'd ask if you have any updates. Thanks!

blablabla
blablabla

¿Only runs with 256 colors? ¬¬

Matt
Matt

Internet Explorer 8 does support the Data URI scheme, but only for base64 strings < 32KBytes. Than means only small images. Hopefully IE9 will support bigger ones.

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!

Brdavs

This is excellent. It means one can generate transparent transients on the client side...
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.

Leo
Leo

It is a great job, well done!

But i tried to set the width or height to be more than 255, like 300, then the picture can not be generated, why?

Itamar
Itamar

I see some really snarky comments here, which are really uncalled for!
This is a great project!

Canyyyon
Canyyyon

Well done, man. Base64 doesn't works with ie. But i think this would be very useful. Love your job. Thanks ;-)

Ian
Ian

Very impressive.

westworld
westworld

haha, Another mad project :) Works fine on firefox
Hope IE 9 will have base64

Guest User
Guest User

Because the author thinks every asshole out there use non-IE web browsers.

Robert

What browser do you use? The library works pretty well in Firefox and Chrome. Your browser has to support the data URI scheme with Base64.

asas
asas

You know your library is in trouble when your own sample PNG does not diaply in the browser!

 

Sorry, comments are closed for this article. Contact me if you want to leave a note.