Neel Basu
Neel Basu

Reputation: 12904

Canvas even Img eating RAM and CPU

I am taking list of files dropped in the area. and then getting their dataUrl and putting them in an Img. and then putting that image in canvas using drawImage. I do appropriate scaling of images according to their size. Its functioning properly. But the problem is even after the operation is complete. e.g. long after Canvas's have been appended to the dom CPU and memory usage goes high. just to show the canvas's it takes high CPU and memory.

Code inside drop event:

    e.preventDefault();
    $("#controller_search").attr('value', '^')
    $("#controller_search").attr('disabled', 'disabled');
    $("#imageList").html('');
    var templateData = "\
        <div class='imageviewer-up'> \
            <div class='curtain'></div> \
            <canvas class='canvas'></canvas> \
            <div class='loading'>0%</div> \
        </div> \
        ";
    for(var i=0;i<event.dataTransfer.files.length;++i){
        var file = event.dataTransfer.files[i];
        var reader = new FileReader();
        reader.onload = (function(file){
            return function(e){
                var template = $(templateData);
                var image = new Image();/*template.find('img')[0];*/
                image.onload = (function(image){
                    return function(){
                        var size = {height: image.height, width: image.width}
                        var rSize = size;
                        if(size.height > 175)
                            rSize = {height: 175, width: (175*size.width)/size.height}
                        else{
                            rSize = {height: 175/(size.width/size.height), width: size.width/(size.width/size.height)}
                        }
                        image.height = rSize.height;
                        image.width = rSize.width;

                        var canvas = template.find('canvas')[0];
                        var context = canvas.getContext("2d");
                        context.mozImageSmoothingEnabled = true;
                        canvas.height = 175+4;
                        canvas.width = image.width+4;
                        context.drawImage(image, (canvas.height-image.height)/2, 2, image.width, image.height);

                        template.css('height', 175+4+0);
                        template.css('width', image.width+0);

                    }
                })(image)
                image.src = e.target.result;
                image.title = file.name;
                console.log(file.name);
                $("#imageList").append(template);
                image = null;
            }

        })(file);
        reader.readAsDataURL(file);
    }

Currently I am testing by dragging 20 Images (sums up to 45 MB) so 20 canvas gets created. Is that too much ?

EDIT

I've even tested using IMG instead of canvas. e.g. using IMG with dataUrls only. But this way too. slows down in the same way. So is there any memory leak in my code ?

Upvotes: 4

Views: 2662

Answers (1)

Neel Basu
Neel Basu

Reputation: 12904

I think It is a problem regarding chrome bug#36412 The data: url is taking up memory but not releasing that. and thats causing the potential problem. I fixed it using window.URL.createObjectURL and window.URL.revokeObjectURL. for webkit its window.webkitURL instead. Now its working fine even with 30+ Images. Current code looks like:

for(var i=0;i<event.dataTransfer.files.length;++i){
    var file = event.dataTransfer.files[i];
    var total = event.dataTransfer.files.length;
    var template = $(templateData);
    var image = new Image();/*template.find('img')[0];*/
    image.onload = (function(image, template, i){               
        return function(e){
            /* Size adjustment */               
            var canvas = template.find('canvas')[0];
            var context = canvas.getContext("2d");
            context.drawImage(image, (canvas.height-image.height)/2, 2, image.width, image.height);             
            window.URL.revokeObjectURL(this.src);
        }
    })(image, template, i)
    image.src = window.URL.createObjectURL(file);
    bong.upload.files.push(file);
    $("#imageList").append(template);
    image = null;
}

Upvotes: 4

Related Questions