Question

I am new using canvas element and I have to say I am impressed about its powerful.

I have been reading about the subject and if I am not confused, canvas only knows about pixels. So, when the application executes a code like the following:

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {
    var sco = new Image();
    sco.onload = function() {
        var sup = new Image();
        sup.onload = function() {
            var sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
                ctx.drawImage(sco, 0, 0);

                ctx.globalAlpha = 1;
                ctx.globalCompositeOperation = 'destination-out';
                ctx.drawImage(sup, 0, 0);
                console.log(sup.src + ' LOADED!');

                ctx.globalCompositeOperation = 'source-in';
                ctx.drawImage(sco, 0, 0);
                console.log(sco.src + ' LOADED!');

                ctx.globalCompositeOperation = 'source-over';
                ctx.drawImage(sust, 0, 0);
                console.log(sust.src + ' LOADED!');

                if (colourPath !== '') {
                    jQuery().paintScooter(canvas, ctx, colourPath);
                }
            }
            sust.src = sustPath;
        }
        sup.src = supPath;
    }
    sco.src = scoPath;
}

It is loading the image from server to client, and when it is loaded it is rendered into canvas.

What happens if scoPath is the same image than a previous call? It is served once again from the server or it is automatically taken from the browser cache?

So,

  • if I write a preload function, images will be available when I need to add them to canvas ... ?
  • when the clearRect method is called, previous images loaded from URL are removed from canvas, so render them again implies new image loading form the server?

If you are interested I am working on an application where it is needed to create one image from others by composition, as the same way designers do with photoshop/gimp working with layers mask. So there are always a base image that use to be the same. Images are quite big (some of them could have ~200KB) and this is something I can't change but I need to manage.

The entirely application has now, more than 3000 images and it is planned to use the double or more.

I come into canvas as an alternate solution of creating the images at server side with image libraries as GD, Imagick or so ... because we need to reduce the time of processing the image the most as possible.

I will appreciate your clarifications and tips from youe experience.

Thanks in advance, ·_-

Was it helpful?

Solution

In general the images you are loading through the browser is kept in a memory cache. Unless there is very little memory the images typically stays there, otherwise the browser will have to purge the memory cache (not related to GC which deals with unreferenced objects), or part of it, and reload the image(s) from either the local disk cache (if enabled) or again from server if for some reason the local disk cache is disabled or full causing previous loaded images to be deleted from it (note: this is browser dependent and this describes the method in a simplified way - some browsers have advanced loading systems able to handle thousands of images in a single page such as the recent Firefox).

In any case you won't need to think about setting src again if that is what you mean. The browser will take care of all the loading for you internally. You just need to make sure you handle the first asynchronous loading as you do in the example. If the image has a reference it will be available. That being said you may have to deal with peculiar browsers which do some wacky stuff in this regard (hrm..IE..he).

200 kb says really very little about an image. It could be uncompressed PNG as well as heavily compressed JPEG. What matter is the pixel dimension. As all images loaded in the browser are converted to uncompressed RGBA the memory usage will be (minimum) width x height x 4. Then there is temporary memory used for it and most likely other buffers as well depending on scenario and method of painting etc. (by the browser). But also have in mind more advanced browsers which can handle as said thousands of images in a single page so this may not become such as huge problem after all.

Image loading itself has nothing to do with the canvas element though. What you draw onto canvas is independent on this whether it is an image or a shape that you draw. Canvas do not lock/reference the image in any way except from actually drawing it - after that the image is forgotten from the canvas point of view, but the image will still be available as described in the beginning as long as it has a reference to it. Images are usually resources associated with the DOM and in some cases JavaScript, ie. as typed arrays etc.

Canvas is, as you touch upon, passive so it does not know from where the pixels came from or in what area, order etc. the pixel was drawn in. It just keeps the final resulting pixel blend from these various operations. All tracking and mechanisms needs to be done outside canvas with custom objects etc.

3000 - 6000+ images sounds a bit much for a browser application (IMO) but if there is memory enough on the system it won't be a problem per se - just don't expect the user to have the same specs (or fast connection) as your developer machine so be prepared to handle errors (as always) and inpatient users...

You should probably consider caching compositions of these images and/or make a loading/reference system that loads the images on demand - how efficient this will be depends on the user configuration (cache size, cache enabled, memory, internet connection etc.) but how to do this is beyond the scope here.

Also, if I may, you could use an image loader as my YAIL bulk image loader which at least takes care of the initial image loading.

To avoid GC removes your images you need to make sure you always keep a reference to the image(s). In your example code some of your images' references will run out of scope and GC may remove the image from memory.

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {

    /// this is only available inside reBuildScooter and to the children scopes
    var sco = new Image();
    sco.onload = function() {

        /// sup is only available inside this function and to children
        /// when function returns sup will be lost when sco.onload.. returns
        var sup = new Image();
        sup.onload = function() {

            /// same as with sup...
            var sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
...

In order to keep a reference to the images you either have to move them to global scope or to "root" inside an instance of the object - for example:

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {

    var sup;
    var sust;
    var sco = new Image();

    sco.onload = function() {

        /// sup is now available within the reBuildScooter
        sup = new Image();
        sup.onload = function() {

            /// same as with sup...
            sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
...

As long as your reBuildScooter object lives (which it probably will in this case) the variables inside will also be kept alive and GC won't collect. But the browser can still purge the memory cache but it will be for the most part be transparent (for lower spec'ed systems there may be reduced performance).

Hope this gives some input.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top