89
votes

I have a form that allows a user to upload an image.

Once the image is loaded, we perform some scaling on it in order to reduce its filesize before we pass it back to the server.

To do this, we place it on the canvas and manipulate it there.

This code will render the scaled image on the canvas, with the canvas of size 320 x 240px:

ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

... where canvas.width and canvas.height is the image height and width x a scaling factor based on the size of the original image.

But when I go to use the code:

ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height

... I only get part of the image on the canvas, in this case the top left corner. I need the whole image 'scaled' to fit on the canvas, despite the actual image size being larger than the 320x240 canvas size.

So for the code above, the width and heights are 1142x856, as that is the final image size. I need to maintain that size to pass beck to the server when the form is submitted, but only want a smaller view of it to appear in the canvas for the user.

What am I missing here? Can anyone point me in the right direction please?

Many thanks in advance.

2

2 Answers

147
votes

Provide the source image (img) size as the first rectangle:

ctx.drawImage(img, 0, 0, img.width,    img.height,     // source rectangle
                   0, 0, canvas.width, canvas.height); // destination rectangle

The second rectangle will be the destination size (what source rectangle will be scaled to).

Update 2016/6: For aspect ratio and positioning (ala CSS' "cover" method), check out:
Simulation background-size: cover in canvas

155
votes

You made the error, for the second call, to set the size of source to the size of the target.
Anyway i bet that you want the same aspect ratio for the scaled image, so you need to compute it :

var hRatio = canvas.width / img.width    ;
var vRatio = canvas.height / img.height  ;
var ratio  = Math.min ( hRatio, vRatio );
ctx.drawImage(img, 0,0, img.width, img.height, 0,0,img.width*ratio, img.height*ratio);

i also suppose you want to center the image, so the code would be :

function drawImageScaled(img, ctx) {
   var canvas = ctx.canvas ;
   var hRatio = canvas.width  / img.width    ;
   var vRatio =  canvas.height / img.height  ;
   var ratio  = Math.min ( hRatio, vRatio );
   var centerShift_x = ( canvas.width - img.width*ratio ) / 2;
   var centerShift_y = ( canvas.height - img.height*ratio ) / 2;  
   ctx.clearRect(0,0,canvas.width, canvas.height);
   ctx.drawImage(img, 0,0, img.width, img.height,
                      centerShift_x,centerShift_y,img.width*ratio, img.height*ratio);  
}

you can see it in a jsbin here : http://jsbin.com/funewofu/1/edit?js,output