Large image HTML5 Canvas poor performance on scale

I am trying to scale my (large: 16200x8100) image using the canvas context; ctx.scale(), however I seem to find a very large delay between frames when I start animating with the canvas scaled appropriately to fit the entire image vertically, yet I don't find this problem if I don't start with the canvas scaled at all. Is there some reason for this or solution? Or is it the sheer size of the image?

image.onload = () => {
    //the multiplier by which to scale the canvas context to fit image in canvas vertically
    minScale = (canvas.height/image.height);
    ctx.scale(minScale, minScale);
    leftMostOffset = {x: -image.width, y: 0};
    animate();
}


function animate(){

    requestAnimationFrame(animate);
    ctx.save();

    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0,0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);

    ctx.restore();

    ctx.drawImage(image, rightMostOffset.x, rightMostOffset.y);
    ctx.drawImage(image, leftMostOffset.x, leftMostOffset.y);

}

1 answer

  • answered 2019-10-15 15:43 Blindman67

    The large image will cause RAM to be moved from the CPU to the GPU. This is very slow.

    Create a copy of the image at the resolution of the canvas and draw that when you animate. This will be slow on the first two frame as that memory still needs to be moved. But once done the scaled image should render with no slowdown

    var imageC;
    image.onload = () => {
        //the multiplier by which to scale the canvas context to fit image in canvas vertically
        minScale = (canvas.height/image.height);
    
        leftMostOffset = {x: -image.width, y: 0};
        imageC = document.createElement("canvas");
        imageC.width = ctx,canvas.width;
        imageC.height = ctx.canvas.height;
        imageC.ctx = imageC.getContext("2d");
        imageC.ctx.scale(minScale, minScale);
        // will be slow for first two frames
        imageC.ctx.drawImage(image, rightMostOffset.x, rightMostOffset.y);
        imageC.ctx.drawImage(image, leftMostOffset.x, leftMostOffset.y);
        animate();
    }
    
    
    function animate(){
        requestAnimationFrame(animate);
        ctx.setTransform(1,0,0,1,0,0);
        ctx.clearRect(0,0, ctx.canvas.width, ctx.canvas.height);
        ctx.drawImage(imageC,0,0);
    
    }