0
votes

I'm currently trying to create a page with dynamically generated images, which are not shapes, drawn into a canvas to create an animation.

The first thing I tried was the following:

//create plenty of those:
var imageArray = ctx.createImageData(0,0,16,8);
//fill them with RGBA values...
//then draw them
ctx.putImageData(imageArray,x,y);

The problem is that the images are overlapping and that putImageData simply... puts the data in the context, with no respect to the alpha channel as specified in the w3c:

pixels in the canvas are replaced wholesale, with no composition, alpha blending, no shadows, etc.

So I thought, well how can I use Images and not ImageDatas?

I tried to find a way to actually put the ImageData object back into an image but it appears it can only be put in a canvas context. So, as a last resort, I tried to use the toDataURL() method of a 16x8 canvas(the size of my images) and to stick the result as src of my ~600 images.

The result was beautiful, but was eating up 100% of my CPU...(which it did not with putImageData, ~5% cpu) My guess is that for some unknown reason the image is re-loaded from the image/png data URI each time it is drawn... but that would be plain weird... no? It also seems to take a lot more RAM than my previous technique.

So, as a result, I have no idea how to achieve my goal.

How can I dynamically create alpha-channelled images in javascript and then draw them at an appreciable speed on a canvas?

Is the only real alternative using a Java applet?

Thanks for your time.

3

3 Answers

3
votes

Not knowing, what you really want to accomplish:

Did you have a look at the drawImage-method of the rendering-context? Basically, it does the composition (as specified by the globalCompositeOperation-property) for you -- and it allows you to pass in a canvas element as the source.

So could probably do something along the lines of:

var offScreenContext = document.getCSSCanvasContext( "2d", "synthImage", width, height);
var pixelBuffer = offScreenContext.createImageData( tileWidth, tileHeight );
// do your image synthesis and put the updated buffer back into the context:
offScreenContext.putImageData( pixelBuffer, 0, 0, tileOriginX, tileOriginY, tileWidth, tileHeight );
// assuming 'ctx' is the context of the canvas that actually gets drawn on screen
ctx.drawImage(
  offScreenContext.canvas,                          // => the synthesized image
  tileOriginX, tileOriginY, tileWidth, tileHeight,  // => frame of offScreenContext that get's drawn
  originX, originY, tileWidth, tileHeight           // => frame of ctx to draw in
);

Assuming that you have an animation you want to loop over, this has the added benefit of only having to generate the frames once into some kind of sprite-map so that in subsequent iterations you'll only ever need to call ctx.drawImage() -- at the expense of an increased memory footprint of course...

0
votes

Why don't you use SVG?

If you have to use canvas, maybe you could implement drawing an image on a canvas yourself?

var red = oldred*(1-alpha)+imagered*alpha

...and so on...

0
votes

getCSSCanvasContext seems to be WebKit only, but you could also create an offscreen canvas like this:

var canvas = document.createElement('canvas')
canvas.setAttribute('width',300);//use whatever you like for width and height
canvas.setAttribute('height',200);

Which you can then draw to and draw onto another canvas with the drawImage method.