Rotate Rectangular Canvas Image to Fit - javascript

I am attempting to rotate an image that fills a rectangular canvas element. Using the code below, I can rotate it satisfactorily (90 degree increments). However, when the big side is translated to the small side, I cannot figure out how to fill the entire canvas. Instead, I have a compacted image. Any help would be appreciated in solving this. Thanks!
What I have so far:
var degrees = 90;
function drawRotated(degrees){
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
var translateX = (canvas.width)/2;
var translateY = (canvas.height)/2;
ctx.translate(translateX,translateY);
ctx.rotate(degrees*Math.PI/180);
ctx.translate(-translateX,-translateY);
ctx.drawImage(theImage, 0,0, canvas.width, canvas.height);
}

to rotate the image without distorting it, it is important to use the image dimensions to translate the image to 0, 0. this will get the center of the image to the origin. you rotate the matrix around the origin (0, 0). you were rotating around the center of the canvas.
additionally you have to perform some math for one translation so that the image is always in the upper left corner.
function drawRotated(degrees){
var theImage = document.getElementById('image');
var imageWidth = theImage.naturalWidth;
var imageHeight = theImage.naturalHeight;
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var angle = degrees*Math.PI/180;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// this will align your image in the upper left corner when rotating in 90deg increments
ctx.translate(Math.abs(imageWidth/2 * Math.cos(angle) + imageHeight/2 * Math.sin(angle)), Math.abs(imageHeight/2 * Math.cos(angle) + imageWidth/2 * Math.sin(angle)));
ctx.rotate(angle);
ctx.translate(-imageWidth/2, -imageHeight/2);
ctx.drawImage(theImage, 0, 0);
}
see FIDDLE

Related

Image rotation using canvas

I need to rotate an image through canvas and through the cropper.js library I can do the rotation of the image but save the image and condition it with canvas does not save me with the format of the rotation.
In my code what I have is an event that makes me rotating towards 90 or -90 degrees. Then when saving the image I need to be saved with that format.
I need to rotate on the axis of the image so that when the image is saved with rotate canvas it is saved with the correct position. I have seen some ways to do it but it has not worked for me, I do not know that I am losing.
//Events to rotate using cropper Js library
'click #rotateL': function(e, instance){
$('#target').cropper('rotate', -90);
angleInDegrees = angleInDegrees - 90 ;
drawRotated(angleInDegrees);
},
'click #rotateR': function(events, instance){
$('#target').cropper('rotate', 90);
angleInDegrees += 90;
drawRotated(angleInDegrees);
},
function drawRotated(degrees){
var canvas = $("#canvas")[0];
var context = canvas.getContext('2d');
var image = document.createElement("img");
image.src = $('#target').attr("src");
image.onload = function () {
context.drawImage(image,(canvas.width - x1) / 2,
(canvas.height - y1) / 2,x1, y1);
//ctx.drawImage(img, x, y, width, height)
}
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.translate(canvas.width/2,canvas.height/2);
context.rotate(degrees*Math.PI/180);
context.drawImage(image, -x1/2,-y1/2);
context.restore();
var dataURL = canvas.toDataURL("image/jpeg");
Session.set("url", dataURL);
}
// event that saves the changes made when you cut the image or rotate.
'click #Save' : function(e) {
$(".loader").fadeIn("slow");
e.preventDefault();
var photoid = $('#photoid').val();
var dataURL = Session.get("url");
var photo = {
srcData : dataURL,
userid : Meteor.userId(),
photo_id : photoid
}
Meteor.call('updatePhoto',photo,function(err) {
if (!err) {
$('#photos').show();
$('#crops').hide();
canvas.height = 0;
canvas.width = 0;
//page relod is better than
//document.getElementById('target').src="";
FlowRouter.go('/search');
FlowRouter.go('/addphoto');
}
});
},
If you are using cropper.js. You can use build-in method getCroppedCanvas to get edited and cropped new canvas back. There is no bother to write on your own.
var canvas = $ ('# target').cropper ('getCroppedCanvas');
console.log (canvas)
var dataURL = canvas.toDataURL ("image / jpeg");
To rotate 90 deg clockwise on a new canvas.
// assuming that image is a loaded image.
const canvas = document.createElement("canvas");
canvas.width = image.height;
canvas.height = image.width;
const ctx = canvas.getContext("2d");
ctx.setTransform(
0,1, // x axis down the screen
-1,0, // y axis across the screen from right to left
image.height, // x origin is on the right side of the canvas
0 // y origin is at the top
);
ctx.drawImage(image,0,0);
To rotate -90Deg onto a new canvas
const canvas = document.createElement("canvas");
canvas.width = image.height;
canvas.height = image.width;
const ctx = canvas.getContext("2d");
ctx.setTransform(
0,-1, // x axis up the screen
1,0, // y axis across the screen from left to right
0, // x origin is on the left side of the canvas
image.width // y origin is at the bottom
);
ctx.drawImage(image,0,0);
The origins are where the top left corner of the image ends up being after the rotation.

Canvas rotate image which depicts an angled ellipse

I have an image in my canvas and am trying to rotate it in an unusual way. I have my image rotating but on the wrong origin point.
I want to rotate the image in such a way that the ellipse is shown to be rotating from it's origin point rather than the image itself rotating. There for ultimately the ellipse would be stationary in the canvas and simply rotating.
This is my current code:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var angle;
var toRads = Math.PI/180;
var start = new Date().getTime();
var rotation = 15;
function draw(){
var x = canvas.width/2 - img.width/2;
var y = canvas.height/2 - img.height/2;
var deltaTime = new Date().getTime() - start;
start = new Date().getTime();
angle = (angle || 0) + (deltaTime/1000 * rotation);
if(angle > 360){angle = 0;}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(x,y);
ctx.rotate(angle * toRads);
ctx.drawImage(img,20,20);
ctx.restore();
setTimeout(draw,1);
}
I was wondering if this can be done in 2D or is it only possible via 3D such as webGL stuff?
I created a jsfiddle of what I have got so far:
http://jsfiddle.net/hc0p5e06/
The order of the transformations are important. You are missing a translation to place the origin of the circle at the right point (assuming you want the center)
var w = img.width; // get the image width and height
var h = img.height;
ctx.translate(x,y);
ctx.rotate(angle * toRads);
ctx.drawImage(img,0,0,w,h,-w/2,-h/2,w,h); // draw the image translated half
// its size up and left in the new
// coordinate space

canvas hole in html5 with image not working

I am trying to create a hole in canvas; and loading image in canvas after.
I want this canvas to contain a hole at a top layer.
I just read about counter-clockwise canvas rules and then created hole with counter clockwise position as below-
var c = document.getElementById("canvas-front");
var ctx = c.getContext("2d");
var centerX = c.width / 2;
var centerY = c.offsetTop;
var radius = 30;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI,true);//boolean true to counter-clockwise
ctx.fillStyle = 'black';
ctx.fill();
I have canvas before image in it-
After applying image in this canvas-
Canvas-
<canvas id="canvas-front" width="261" height="506"></canvas>
As you can see from both the images, I can't get this hole in canvas work.
How do I create this arc so that image doesn't overlap this.
I get this issue solved-
What I had to do-
On change of file I did empty to canvas and redrew image and then while image is being loaded
the arc is being created to counter-clockwise position-
Drawing the canvas again on image change-
var canvas = document.getElementById("canvas-front");
canvas.width = canvas.width;//blanks the canvas
var c = canvas.getContext("2d");
Creating image and giving it required src from changed input-
var img = new Image();
img.src = e.target.result;
Loading image and creating arc parallely-
img.onload = function () {
c.drawImage(img, 0, 0);
var centerX = canvas.width / 2;
var centerY = canvas.offsetTop;
var radius = 30;
c.beginPath();
c.arc(centerX, centerY, radius, 0, 2 * Math.PI, true);
c.fillStyle = 'black';
c.fill();
}

Canvas animation pixelated

I want to animate an Arc on Canvas, and it works (with a really basic animation, interval), but the outcome is very pixelated/edgy. On the left side I draw an arc (animated), on the right side without animation (smooth).
JsFiddle: http://jsfiddle.net/C8CXz/2/
function degreesToRadians (degrees) {
return degrees * (Math.PI/180);
}
function radiansToDegrees (radians) {
return radians * (180/Math.PI);
}
var canvas = document.getElementById('circle');
var ctx = canvas.getContext('2d');
var start = 0, end = 0;
var int = setInterval(function(){
end++;
ctx.beginPath();
ctx.arc(80, 80, 50, degreesToRadians(0)-Math.PI/2, degreesToRadians(end)-Math.PI/2, false);
ctx.lineWidth = 10;
ctx.stroke();
if(end >= 360) {
clearInterval(int);
}
}, 10);
ctx.beginPath();
ctx.arc(220, 80, 50, degreesToRadians(0)-Math.PI/2, degreesToRadians(360)-Math.PI/2, false);
ctx.lineWidth = 10;
ctx.stroke();
(raw simple code, dont mind the sloppiness)
You need a:
ctx.clearRect(0, 0, w, h);
In each draw loop.
Basically, you are drawing the same arc over itself hundreds of times. The edge pixels that are only partially black are bing darkened over and over until they are completely black.
Things like this are way nearly all canvas animations clear the canvas and draw fresh for each iteration.
Try clearing the drawing rectangle on every frame
ctx.clearRect(x,y,width,height);
http://jsfiddle.net/C8CXz/3/
I found that I first need the clear the canvas.
ctx.clearRect(0, 0, canvas.width, canvas.height);

How to properly clear a rotated HTML5 canvas context?

I need to clear a rotated rectangle and draw it again on a canvas, either at the same place or elsewhere. The problem is, the cleared part doesn't match the rectangle's bounds, leaving dirty bits behind.
var cvs = document.getElementById('testcanvas');
var ctx = cvs.getContext('2d');
var rectColor = 'green';
var x = 300;
var y = 10;
var width = 200;
var height = 150;
var rotation = 0;
setInterval(animate, 100);
function animate(){
clearRect();
update();
drawRect();
}
function clearRect(){
ctx.save();
ctx.rotate(rotation);
ctx.clearRect(x, y, width, height);
ctx.restore();
}
function update(){
rotation += 0.1;
x++;
}
function drawRect(){
ctx.save();
ctx.fillStyle = rectColor;
ctx.rotate(rotation);
ctx.fillRect(x, y, width, height);
ctx.restore();
}
​
http://jsfiddle.net/MFz2z/15/
Another issue, clearRect() behaves differently on Firefox when the canvas is rotated, by clearing the whole unrotated space used by the rotated rectangle.
http://jsfiddle.net/MFz2z/17/
Is there any workaround to this, other than clearing the whole canvas and drawing everything again ? I use Chrome 22 and Firefox 15.0.1.
It could be due to the anti-aliasing of the pixels that create the extra tidbits.
You could use this http://jsfiddle.net/MFz2z/28/ and basically clear 1 more pixel from each side.

Categories

Resources