HTML5 Canvas Rotate Image

199,479

Solution 1

You can use canvas’ context.translate & context.rotate to do rotate your image

enter image description here

Here’s a function to draw an image that is rotated by the specified degrees:

function drawRotated(degrees){
    context.clearRect(0,0,canvas.width,canvas.height);

    // save the unrotated context of the canvas so we can restore it later
    // the alternative is to untranslate & unrotate after drawing
    context.save();

    // move to the center of the canvas
    context.translate(canvas.width/2,canvas.height/2);

    // rotate the canvas to the specified degrees
    context.rotate(degrees*Math.PI/180);

    // draw the image
    // since the context is rotated, the image will be rotated also
    context.drawImage(image,-image.width/2,-image.width/2);

    // we’re done with the rotating so restore the unrotated context
    context.restore();
}

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/6ZsCz/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

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

    var angleInDegrees=0;

    var image=document.createElement("img");
    image.onload=function(){
        ctx.drawImage(image,canvas.width/2-image.width/2,canvas.height/2-image.width/2);
    }
    image.src="houseicon.png";

    $("#clockwise").click(function(){ 
        angleInDegrees+=30;
        drawRotated(angleInDegrees);
    });

    $("#counterclockwise").click(function(){ 
        angleInDegrees-=30;
        drawRotated(angleInDegrees);
    });

    function drawRotated(degrees){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.translate(canvas.width/2,canvas.height/2);
        ctx.rotate(degrees*Math.PI/180);
        ctx.drawImage(image,-image.width/2,-image.width/2);
        ctx.restore();
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas><br>
    <button id="clockwise">Rotate right</button>
    <button id="counterclockwise">Rotate left</button>
</body>
</html>

Solution 2

Quickest 2D context image rotation method

A general purpose image rotation, position, and scale.

// no need to use save and restore between calls as it sets the transform rather 
// than multiply it like ctx.rotate ctx.translate ctx.scale and ctx.transform
// Also combining the scale and origin into the one call makes it quicker
// x,y position of image center
// scale scale of image
// rotation in radians.
function drawImage(image, x, y, scale, rotation){
    ctx.setTransform(scale, 0, 0, scale, x, y); // sets scale and origin
    ctx.rotate(rotation);
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
} 

If you wish to control the rotation point use the next function

// same as above but cx and cy are the location of the point of rotation
// in image pixel coordinates
function drawImageCenter(image, x, y, cx, cy, scale, rotation){
    ctx.setTransform(scale, 0, 0, scale, x, y); // sets scale and origin
    ctx.rotate(rotation);
    ctx.drawImage(image, -cx, -cy);
} 

To reset the 2D context transform

ctx.setTransform(1,0,0,1,0,0); // which is much quicker than save and restore

Thus to rotate image to the left (anti clockwise) 90 deg

drawImage(image, canvas.width / 2, canvas.height / 2, 1, - Math.PI / 2);

Thus to rotate image to the right (clockwise) 90 deg

drawImage(image, canvas.width / 2, canvas.height / 2, 1, Math.PI / 2);

Example draw 500 images translated rotated scaled

var image = new Image;
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
document.body.appendChild(canvas);
var w,h;
function resize(){ w = canvas.width = innerWidth; h = canvas.height = innerHeight;}
resize();
window.addEventListener("resize",resize);
function rand(min,max){return Math.random() * (max ?(max-min) : min) + (max ? min : 0) }
function DO(count,callback){ while (count--) { callback(count) } }
const sprites = [];
DO(500,()=>{
    sprites.push({
       x : rand(w), y : rand(h),
       xr : 0, yr : 0, // actual position of sprite
       r : rand(Math.PI * 2),
       scale : rand(0.1,0.25),
       dx : rand(-2,2), dy : rand(-2,2),
       dr : rand(-0.2,0.2),
    });
});
function drawImage(image, spr){
    ctx.setTransform(spr.scale, 0, 0, spr.scale, spr.xr, spr.yr); // sets scales and origin
    ctx.rotate(spr.r);
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
function update(){
    var ihM,iwM;
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0,0,w,h);
    if(image.complete){
      var iw = image.width;
      var ih = image.height;
      for(var i = 0; i < sprites.length; i ++){
          var spr = sprites[i];
          spr.x += spr.dx;
          spr.y += spr.dy;
          spr.r += spr.dr;
          iwM = iw * spr.scale * 2 + w;
          ihM = ih * spr.scale * 2 + h;
          spr.xr = ((spr.x % iwM) + iwM) % iwM - iw * spr.scale;
          spr.yr = ((spr.y % ihM) + ihM) % ihM - ih * spr.scale;
          drawImage(image,spr);
      }
    }    
    requestAnimationFrame(update);
}
requestAnimationFrame(update);

Solution 3

The other solution works great for square images. Here is a solution that will work for an image of any dimension. The canvas will always fit the image rather than the other solution which may cause portions of the image to be cropped off.

var canvas;

var angleInDegrees=0;

var image=document.createElement("img");
image.onload=function(){

    drawRotated(0);
}
image.src="http://greekgear.files.wordpress.com/2011/07/bob-barker.jpg";

$("#clockwise").click(function(){ 
    angleInDegrees+=90 % 360;
    drawRotated(angleInDegrees);
});

$("#counterclockwise").click(function(){ 
    if(angleInDegrees == 0)
        angleInDegrees = 270;
    else
        angleInDegrees-=90 % 360;
    drawRotated(angleInDegrees);
});

function drawRotated(degrees){
    if(canvas) document.body.removeChild(canvas);

    canvas = document.createElement("canvas");
    var ctx=canvas.getContext("2d");
    canvas.style.width="20%";

    if(degrees == 90 || degrees == 270) {
        canvas.width = image.height;
        canvas.height = image.width;
    } else {
        canvas.width = image.width;
        canvas.height = image.height;
    }

    ctx.clearRect(0,0,canvas.width,canvas.height);
    if(degrees == 90 || degrees == 270) {
        ctx.translate(image.height/2,image.width/2);
    } else {
        ctx.translate(image.width/2,image.height/2);
   }
    ctx.rotate(degrees*Math.PI/180);
    ctx.drawImage(image,-image.width/2,-image.height/2);

    document.body.appendChild(canvas);
}

http://jsfiddle.net/6ZsCz/1588/

Solution 4

This is the simplest code to draw a rotated and scaled image:

function drawImage(ctx, image, x, y, w, h, degrees){
  ctx.save();
  ctx.translate(x+w/2, y+h/2);
  ctx.rotate(degrees*Math.PI/180.0);
  ctx.translate(-x-w/2, -y-h/2);
  ctx.drawImage(image, x, y, w, h);
  ctx.restore();
}

Solution 5

As @markE mention in his answer

the alternative is to untranslate & unrotate after drawing

It is much faster than context save and restore.

Here is an example

// translate and rotate
this.context.translate(x,y);
this.context.rotate(radians);
this.context.translate(-x,-y);

this.context.drawImage(...);    

// untranslate and unrotate
this.context.translate(x, y);
this.context.rotate(-radians);
this.context.translate(-x,-y);
Share:
199,479
Max William Vitorino
Author by

Max William Vitorino

Updated on May 31, 2021

Comments

  • Max William Vitorino
    Max William Vitorino almost 3 years
    jQuery('#carregar').click(function() {
      var canvas    = document.getElementById('canvas');
      var image   = document.getElementById('image');
      var element = canvas.getContext("2d");
      element.clearRect(0, 0, canvas.width, canvas.height);
      element.drawImage(image, 0, 0, 300, 300);
    });
    

    jsfiddle.net/braziel/nWyDE/

    I have a problem to rotate an image 90 ° to the right or to the left.

    I use an image on the canvas, the same screen will have several canvas equal to that of the example, but I left it as close as possible to the project.

    I ask, how do I rotate the image 90 ° to the left or right when I click "Rotate Left" and "Rotate Right"?

    I tried several codes on the internet but none worked.

  • TheRealChx101
    TheRealChx101 about 10 years
    so what about putImageData( ) ? It doesn't seem to work
  • markE
    markE about 10 years
    Well, putImageData would work, but it's a much more expensive operation to do the same thing--so putImageData is not called for here! ;-)
  • Steve Farthing
    Steve Farthing almost 10 years
    Appears you have a typo: ctx.drawImage(image,-image.width/2,-image.width/2); should be ctx.drawImage(image,-image.width/2,-image.height/2);
  • markE
    markE almost 10 years
    @SteveFarthing No typo...when rotated 90 degrees, the width becomes the height and the height becomes the width. ;-)
  • Steve Farthing
    Steve Farthing almost 10 years
    This code works perfectly for square images. For rectangle images the image is cropped incorrectly (see jsfiddle.net/6ZsCz/803 ). If you change ctx.drawImage(image,-image.width/2,-image.width/2); to be ctx.drawImage(image,-image.width/2,-image.height/2) then it works for all size images.
  • markE
    markE almost 10 years
    @SteveFarthing. Cropping is not "incorrect", it's just a design option--like overflow:hidden. :-) If your own design requires displaying the full rectangular image you could (1) increase the size of the canvas (2) decrease the size of your image when rotated at 90 or 270. Cheers!
  • Steve Farthing
    Steve Farthing almost 10 years
    ok. Heres an example where the canvas fits to the image and parts of the image are not lost: jsfiddle.net/6ZsCz/804 .
  • nicholaswmin
    nicholaswmin about 9 years
    @SteveFarthing can you put this as an answer? It works flawlessly and I'm positive that anyone who looks for this functionality needs your 'corrected' solution
  • Dr. Gianluigi Zane Zanettini
    Dr. Gianluigi Zane Zanettini over 8 years
    @markE : for the 3rd time this month you helped me out :-D
  • deathangel908
    deathangel908 almost 7 years
    Please check you fiddle, it doesn't work: Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
  • Ohad Schneider
    Ohad Schneider over 6 years
    Great job as always Mark! Updated JSFiddle with working image: jsfiddle.net/6ZsCz/3455
  • T4NK3R
    T4NK3R over 5 years
    Thank you - I'm happy - How fast is my computer is !?!
  • zumek
    zumek over 5 years
    @Blindman67 Thanks for the great solution! Would you please kindly explain what's being done in the following lines? I suck at the math part :/ - iwM = iw * spr.scale * 2 + w; ihM = ih * spr.scale * 2 + h; spr.xr = ((spr.x % iwM) + iwM) % iwM - iw * spr.scale; spr.yr = ((spr.y % ihM) + ihM) % ihM - ih * spr.scale;
  • Blindman67
    Blindman67 over 5 years
    @zumek spr.xr and yr represent the rendered coordinate of the sprite. The first two lines get the width/height of image (canvas) with margins that allow sprite to move off the canvas (on all side). Next two get the position offsetting by margin size up and left. The % cycles position (like asteroids move off left appear on right) The margins ensure that you don't see the sprite disappear and then reappear on opposite side.
  • Andrew Shi
    Andrew Shi almost 4 years
    This is underrated.
  • Aleskei Sakharov
    Aleskei Sakharov over 3 years
    You are the best! I don't know how much time you spent on this. I really appreciate this.
  • oldboy
    oldboy over 3 years
    is there any way to rotate drawImage without rotating the canvas?
  • oldboy
    oldboy over 3 years
    is there any way to rotate the drawImage element without rotating the canvas itself?
  • oldboy
    oldboy over 3 years
    is there any way to rotate the drawImage element without rotating the canvas itself?
  • oldboy
    oldboy over 3 years
    is there any way to rotate the drawImage element without rotating the canvas itself? is save restore really the only way?
  • oldboy
    oldboy over 3 years
    how do you rotate a drawImage element without rotating the whole canvas itself?
  • oldboy
    oldboy over 3 years
    rotate the drawImage directly*
  • aleha
    aleha over 3 years
    @oldboy canvas isnt rotated here. Rotation is applied to context which works inside canvas
  • oldboy
    oldboy over 3 years
    @aleha so then, is there any way to rotate the drawImage element directly without rotating the ctx itself?
  • oldboy
    oldboy over 3 years
    in this answer, the ctx is being rotated instead of the drawImage element, right? is there any way to rotate the drawImage element directly without having to rotate the ctx and then unrotate it, etc?
  • aleha
    aleha over 3 years
    @oldboy I think you misunderstood the concept. ctxs.drawImage only draws.
  • oldboy
    oldboy over 3 years
    @aleha yes, i know that drawImage only draws. it draws an image onto the canvas or context. i am wondering if it is possible to directly rotate the image itself instead of rotating the canvas or context...?
  • oldboy
    oldboy over 3 years
    so the way in the answer that i linked is slower than setTransform, rotate, drawImage? ok, but is there any way to rotate the "pen" instead of rotating the "canvas"?
  • oldboy
    oldboy over 3 years
    yes, i know rotation ultimately takes place via a transform, but the transform is applied to the canvas/context. what am i not understanding? youre confusing me
  • oldboy
    oldboy over 3 years
    i now see whence the confusion was arising. i wasnt asking whether or not we can rotate the function drawImage (i know that would make zero sense), but rather the element or "output/application/etc" (perhaps a poor choice of words) of drawImage. consider my Q in the context of the following metaphor whereby the canvas/context is a piece of a paper on a desk and drawImage is the pen/pencil. right now, we are rotating the piece of paper, then drawing on it, then unrotating the paper. is it possible to instead rotate the pen or hand (similar to how CSS transforms are applied to eles)?
  • oldboy
    oldboy over 3 years
    ok. the way canvas goes about it is so much more confusing than vanilla CSS transforms. thanks for your help.
  • mshaffer
    mshaffer over 3 years
    @Blindman67 this is a nice solution, is there a non-square solution, e.g., scale.x and scale.y are different? Suppose I had an image originally of size 1800x1800 but I want to place it as 180x120 and I want to rotate it?
  • Blindman67
    Blindman67 over 3 years
    @mshaffer Yes you can. Just set the axis scales with ctx.setTransform(scaleX, 0, 0, scaleY, x, y) where scaleX and scaleY replace scale in the drawImage functions.