HTML5 Canvas Rotate Image
Solution 1
You can use canvas’ context.translate & context.rotate to do rotate your image
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);
Max William Vitorino
Updated on May 31, 2021Comments
-
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); });
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 about 10 yearsso what about putImageData( ) ? It doesn't seem to work
-
markE about 10 yearsWell, 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 almost 10 yearsAppears 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 almost 10 years@SteveFarthing No typo...when rotated 90 degrees, the width becomes the height and the height becomes the width. ;-)
-
Steve Farthing almost 10 yearsThis 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 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 almost 10 yearsok. Heres an example where the canvas fits to the image and parts of the image are not lost: jsfiddle.net/6ZsCz/804 .
-
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 over 8 years@markE : for the 3rd time this month you helped me out :-D
-
deathangel908 almost 7 yearsPlease 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 over 6 yearsGreat job as always Mark! Updated JSFiddle with working image: jsfiddle.net/6ZsCz/3455
-
T4NK3R over 5 yearsThank you - I'm happy - How fast is my computer is !?!
-
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 over 5 years@zumek
spr.xr
andyr
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 almost 4 yearsThis is underrated.
-
Aleskei Sakharov over 3 yearsYou are the best! I don't know how much time you spent on this. I really appreciate this.
-
oldboy over 3 yearsis there any way to rotate
drawImage
without rotating thecanvas
? -
oldboy over 3 yearsis there any way to rotate the
drawImage
element without rotating thecanvas
itself? -
oldboy over 3 yearsis there any way to rotate the
drawImage
element without rotating thecanvas
itself? -
oldboy over 3 yearsis there any way to rotate the
drawImage
element without rotating thecanvas
itself? issave restore
really the only way? -
oldboy over 3 yearshow do you rotate a
drawImage
element without rotating the whole canvas itself? -
oldboy over 3 yearsrotate the
drawImage
directly* -
aleha over 3 years@oldboy canvas isnt rotated here. Rotation is applied to context which works inside canvas
-
oldboy over 3 years@aleha so then, is there any way to rotate the
drawImage
element directly without rotating thectx
itself? -
oldboy over 3 yearsin this answer, the
ctx
is being rotated instead of thedrawImage
element, right? is there any way to rotate thedrawImage
element directly without having to rotate thectx
and then unrotate it, etc? -
aleha over 3 years@oldboy I think you misunderstood the concept. ctxs.drawImage only draws.
-
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 over 3 yearsso 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 over 3 yearsyes, 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 over 3 yearsi 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) ofdrawImage
. consider my Q in the context of the following metaphor whereby the canvas/context is a piece of a paper on a desk anddrawImage
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 over 3 yearsok. the way canvas goes about it is so much more confusing than vanilla CSS transforms. thanks for your help.
-
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 over 3 years@mshaffer Yes you can. Just set the axis scales with
ctx.setTransform(scaleX, 0, 0, scaleY, x, y)
wherescaleX
andscaleY
replacescale
in thedrawImage
functions.