2

I'm trying to rotate an image inside a HTML canvas. The rotating does work, but however, each single rotation time, the corners of the image are cut/clipped off. This is wrong because the whole uploaded image should be intact after rotating.

Some important details:

  • In my specific usecase I do not have access to the image data itself. So the image which is uploaded by the user will be processed and drawn on a HTML canvas. I only can access the HTML canvas element, not the uploaded image itself. This is how the system works.
  • The canvas width and height should be exact the same as the width & height of the uploaded image
  • The canvas itself should maintain its dimensions and should not be rotated, only the image in it should be rotated.
  • No CSS, should only be archieved with JavaScript because the rotated canvas image will be uploaded to the server.

So the problem here is that each time I want to rotate the image 45 degrees, the corners of the image inside the HTML canvas are clipped/cutted off. Obvious this is not correct since the whole image should be rotated. I can't figure out what I did wrong so maybe someone can help me futher?

https://jsfiddle.net/d5zurxq2/

<label>Image File:</label><br/>
<input type="file" id="imageLoader" name="imageLoader"/>
<canvas id="imageCanvas" width=250 height=250></canvas>
<br /><br /><br />
<button type="button" id="rotateLeft">Rotate 45 degrees left</button>


#imageCanvas {
  width: 350px;
  height: 250px;
  background-color: rgba(158, 167, 184, 0.2)
}

var imageLoader = document.getElementById('imageLoader');
    imageLoader.addEventListener('change', handleImage, false);


var canvas  = document.getElementById('imageCanvas');
var ctx     = canvas.getContext("2d");


function handleImage(e){
  var reader            = new FileReader();
  reader.onload         = function(e) {
      var preview       = document.createElement('img');
      preview.onload    = function()
      {
          canvas.width  = preview.width;
          canvas.height = preview.height;
          canvas.getContext('2d').drawImage(preview, 0, 0);
      };

      preview.src = reader.result;
    };

   reader.readAsDataURL(e.target.files[0]);     
}



document.getElementById('rotateLeft').addEventListener('click', rotateImage, 
false);

function rotateImage() {
  var w     = ctx.canvas.width;
  var h     = ctx.canvas.height;
  var ww    = w / 2;
  var hh    = h / 2;

  ctx.save();
  ctx.globalCompositeOperation = "copy";
  ctx.translate(ww, hh);
  ctx.rotate((Math.PI / 180) * 45);
  ctx.drawImage(canvas, -canvas.width/2, -canvas.height/2);
  ctx.restore();
}
Hendrian
  • 23
  • 3

2 Answers2

2

These two statements are contradictory.

The canvas width and height should be exact the same as the width & height of the uploaded image.

The canvas itself should maintain its dimensions and should not be rotated, only the image in it should be rotated.

Increase the size of your canvas. A larger canvas is required if you rotate your image 45 degrees.

For now, you set the canvas size to the image size. However, rotating your image doesn't rotate your canvas, reason why the edges are cut off.

Here is a canvas (in blue), with an image (in yellow) exactly the same size but drawn at a 45 degree angle. The edges of the image that stick out, are not drawn... because they're not on the canvas.

enter image description here

Increase the canvas size to make up for the image rotation. I'd recommend calculating the diagonal length of your image and set that as the width and height of your canvas, this way no matter how you rotate it, it'll fit.

Something like this:

  let diagonalLength = Math.sqrt(
    Math.pow(preview.width,2)+Math.pow(preview.height,2)    
  );
  canvas.width  = diagonalLength;
  canvas.height = diagonalLength;
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • Thats well explained. I do understand and with your code example I was able to get a non-clipped canvas,thats good so thank you for this! However, the canvas width and height are not the same as the original uploaded image. I mean, when a user uploads a image of 250x500 pixels, the canvas have to be in all cases after rotation 250x500. Could this be archieved somehow, in example with scaling the image to fit the canvas size? – Hendrian May 13 '18 at 20:37
  • Yes @Hendrian, you just need to figure out at which scale you'd like to draw it at. https://stackoverflow.com/questions/13903257/html5-canvas-scale-image-after-drawing-it – kemicofa ghost May 14 '18 at 08:48
  • 1
    Thanks, I will play with it. This question is marked a solved. – Hendrian May 17 '18 at 06:03
0

You can do that and more with the Canvate library.

http://www.sakuracode.com/canvate

You can load all the images as you want and trate them as individual clips. You can set the point of rotation too. In this case in the middle.

You need something like that?

function rotateImage() {
        clip.rotation = 45;
        clip.fitInto(canvas.width, canvas.height);
    }

https://codepen.io/EiseiKashi/pen/aGjbWK

For any doubt please let me know!

Eese
  • 1
  • 1
  • Thanks for the suggestion, The result in the codepen is indeed what I want, but I prefer not to use a library for that. However I will take a look so thansk again. – Hendrian May 17 '18 at 06:04