StackSlave
StackSlave

Reputation: 10627

How do I rotate the entire canvas and an image drawn into the canvas at the same time?

First, upload a tiny image that is wider than it is tall using the following code.

//<![CDATA[
/* js/external.js */
var doc, M, I;
addEventListener('load', function(){
doc = document;
M = function(tag){
  return doc.createElement(tag);
}
I = function(id){
  return doc.getElementById(id);
}
var canvas = I('canvas'), ctx;
I('upload').onchange = function(){
  var files = this.files, file, fr, img;
  if(files.length){
    file = files[0]; fr = new FileReader; img = M('img');
    fr.onload = function(){
      img.onload = function(){
        canvas.width = this.width; canvas.height = this.height;
        ctx = canvas.getContext('2d'); ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
      }
      img.src = this.result;
    }
    fr.readAsDataURL(file);
  }
}
});
//]]>
/* css/external.css */
*{
  float:left; clear:left;
}
#canvas{
  margin-top:10px;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
    <title>canvas rotate</title>
    <link type='text/css' rel='stylesheet' href='css/external.css' />
    <script type='text/javascript' src='js/external.js'></script>
  </head>
<body>
  <input id='upload' type='file' accept='image/*' />
  <canvas id='canvas' width='0' height='0'></canvas>
</body>
</html>

You can see that the image displays in the canvas correctly. That is not my problem, though. I'm really trying to rotate the entire canvas dimensions along with the canvas contents at the same time. If it was a square it would be no problem because I could take half of the height and the width like: ctx.save(); cxt.translate(halfImageWidth, halfImageHeight); ctx.rotate(Math.PI*90/180); ctx.translate(-halfImageWidth, -halfImageHeight); ctx.drawImage(imageContext, 0, 0, imageWidth, imageHeight);.

Here is what I thought would work, but does not:

//<![CDATA[
/* js/external.js */
var doc, M, I;
addEventListener('load', function(){
doc = document;
M = function(tag){
  return doc.createElement(tag);
}
I = function(id){
  return doc.getElementById(id);
}
var canvas = I('canvas'), ctx;
I('upload').onchange = function(){
  var files = this.files, file, fr, img;
  if(files.length){
    file = files[0]; fr = new FileReader; img = M('img');
    fr.onload = function(){
      img.onload = function(){
        canvas.width = this.height; canvas.height = this.width;
        ctx = canvas.getContext('2d'); ctx.save(); ctx.rotate(Math.PI*90/180);
        ctx.translate(-canvas.width, 0); ctx.drawImage(this, 0, 0, canvas.width, canvas.height); ctx.restore();
      }
      img.src = this.result;
    }
    fr.readAsDataURL(file);
  }
}
});
//]]>
/* css/external.css */
*{
  float:left; clear:left;
}
#canvas{
  margin-top:10px;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
    <title>canvas rotate</title>
    <link type='text/css' rel='stylesheet' href='css/external.css' />
    <script type='text/javascript' src='js/external.js'></script>
  </head>
<body>
  <input id='upload' type='file' accept='image/*' />
  <canvas id='canvas' width='0' height='0'></canvas>
</body>
</html>

I figured that by not translating before rotation, my origin is top left corner, so I should just be able to set negative origin after rotation, but that doesn't work. If someone could show and explain how to do this correctly I would be most appreciated.

PS

I already thought about a CSS rotation, but since I'm really using the data this won't be a solution for me.

Upvotes: 1

Views: 192

Answers (1)

Kaiido
Kaiido

Reputation: 136986

If as you stated, you only need to rotate by 90deg, then it's quite simple.

Your image's width will become your canvas' height, and its height will become the canvas' width.

From there you just have to apply the usual

translate(target-center-x, target-center-y)
rotate(angle)
drawImage(img, -transform-origin, -transform-origin)

fileinput.onchange = e => {
  const img = new Image();
  img.onload = e => draw(img);
  img.src = URL.createObjectURL(fileinput.files[0]);
};

function draw(img) {
  const ctx = canvas.getContext('2d');
  canvas.width = img.height;
  canvas.height = img.width;
  // move to center of the canvas
  ctx.translate(canvas.width / 2, canvas.height / 2);
  ctx.rotate(Math.PI / 2);
  // set the transform origin at center of the image
  ctx.drawImage(img, -img.width / 2, -img.height / 2);
}
<input type="file" id="fileinput">
<canvas id="canvas"></canvas>

Upvotes: 2

Related Questions