旋转后,在正确的位置绘制图像

如您所见,我尝试在canvas中旋转图像: 在此处输入图像描述 https://jsfiddle.net/1a7wpsp8/4/

因为我在[0, image_height]周围旋转了图像[0, image_height]图像信息丢失了。 缺少部分头部,并且“canvas”的高度现在变小,以显示整个旋转图像。

为了解决这个问题,我想我必须将旋转原点更多地向右移动并增加canvas高度。

我添加了一个方法,以特定的角度获取原点周围的旋转点:

 function rotate(x, y, a) { var cos = Math.cos, sin = Math.sin, a = a * Math.PI / 180, xr = x * cos(a) - y * sin(a); yr = x * sin(a) + y * cos(a); return [xr, yr]; } 

有了这个我试图计算新的旋转原点,但失败了。

旋转图像的首选方法是什么? 如何在canvas上显示完整图像,没有红色边框? 谢谢https://jsfiddle.net/1a7wpsp8/4/

这是一个小提琴,代码为您的图像旋转:) http://jsfiddle.net/6ZsCz/1911/

HTML:

 canvas id="canvas" width=300 height=300>

JS:

 var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var width=0; var height=0; var diagonal = 0; var angleInDegrees=0; var image=document.createElement("img"); image.onload=function(){ width = image.naturalWidth; height = image.naturalHeight; diagonal=Math.sqrt(Math.pow(width,2)+Math.pow(height,2)); ctx.canvas.height = diagonal; ctx.canvas.width = diagonal; ctx.clearRect(0,0,canvas.width,canvas.height); ctx.save(); ctx.translate(diagonal/2,diagonal/2); ctx.rotate(0); ctx.drawImage(image,-width/2,-height/2); ctx.restore(); } image.src="http://i.imgur.com/gwlPu.jpg"; $("#clockwise").click(function(){ angleInDegrees+=45; drawRotated(angleInDegrees); }); $("#counterclockwise").click(function(){ angleInDegrees-=45; drawRotated(angleInDegrees); }); function drawRotated(degrees){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.save(); ctx.translate(diagonal/2,diagonal/2); ctx.rotate(degrees*Math.PI/180); ctx.drawImage(image,-width/2,-height/2); ctx.restore(); } 

CSS(用于canvas背景):

 canvas{border:1px solid red; background:red;border-radius:50%} // to see exectly centered :) 

要旋转图像并对其进行缩放,以便在任何时候图像的边缘都不在canvas边界内,您需要锻炼从canvas中心到角落的距离。

 // assuming canvas is the canvas and image is the image. var dist = Math.sqrt(Math.pow(canvas.width/2,2)+Math.pow(canvas.height/2,2)); 

现在你需要找到从图像中心到最近边缘的距离;

 var imgDist = Math.min(image.width,image.height)/2 

因此,现在我们获得了所需的信息,以获得在canvas中心绘制时图像可以始终适合canvas的最小比例。

 var minScale = dist / imgDist; 

现在围绕图像的中心旋转,缩放它并将其定位在canvas的中心

首先计算像素顶边(X轴)的方向和大小

 // ang is the rotation in radians var dx = Math.cos(ang) * minScale; var dy = Math.sin(ang) * minScale; 

然后创建变换矩阵,其中前两个数字是X轴,后两个是从X轴顺时针90度的Y轴,最后两个是从左上角的canvas原点开始的canvas像素坐标中的原点角。

 // ctx is the canvas 2D context ctx.setTransform(dx, dy, -dy, dx, canvas.width / 2, canvas.height / 2); 

现在将图像偏移高度和宽度的一半。

 ctx.drawImage(image,-image.width / 2, - image.height / 2); 

最后一件事就是恢复默认转换

 ctx.setTransform(1,0,0,1,0,0); 

你完成了。

作为一个function

 // ctx is canvas 2D context // angle is rotation in radians // image is the image to draw function drawToFitRotated(ctx, angle, image){ var dist = Math.sqrt(Math.pow(ctx.canvas.width /2, 2 ) + Math.pow(ctx.canvas.height / 2, 2)); var imgDist = Math.min(image.width, image.height) / 2; var minScale = dist / imgDist; var dx = Math.cos(angle) * minScale; var dy = Math.sin(angle) * minScale; ctx.setTransform(dx, dy, -dy, dx, ctx.canvas.width / 2, ctx.canvas.height / 2); ctx.drawImage(image, -image.width / 2, - image.height / 2); ctx.setTransform(1, 0, 0, 1, 0, 0); } 

更新由于这是一个有趣的问题,我看看是否可以找出如何最好地适应旋转的图像,确保图像始终填充canvas,而且还显示了尽可能多的图像。 解决方案意味着当图像旋转时,刻度发生变化,并且由于侧面到达角落,刻度有4个点,突然停止缩小并再次开始增长。 然而,这对于旋转但需要填充canvas的静态图像是有益的。

描述这个的最好方法是用图片 在此处输入图像描述 图像为绿色,canvas为红色。 图像的旋转是角度R我们需要找到线CE和CF的长度。 Ih和Iw是图像高度和宽度的一半。

从canvas中我们计算出线CB的长度,它是canvas高度(ch)和宽度(cw)平方的一半之和的平方根。

然后我们需要角度A,它是(ch)/长度线CB的acos

现在我们有角度A,我们可以计算出角度A1和A2。 现在我们有一个长度CB和角度A1,A2我们可以解决CE和CF的直角三角形CEB和CFB。 其中CE =长度CB * cos(A1)和CF =长度CB * cos(A2)

然后得到图像高度的标度,长度CE除以Ih,CE除以Iw。 由于图像方面可能与我们需要拟合的矩形不匹配,我们需要保持两个比例的最大值。

所以我们最终得到一个适合的尺度。

还有一个问题。 数学在0到90度的角度下工作正常,但其余部分则失败。 幸运的是,每个象限的问题都是对称的。 对于> 180°的角度,我们镜面并向后旋转180°然后对于> 90°<180°的角度,我们反转并向后旋转90度。 我在演示中以弧度完成所有操作。 我们还确保给定的角度始终在0 - 360(0到Math.PI * 2)的范围内。

然后它只是创建矩阵和绘制图像的问题。

在演示中,我添加了两个Boxes。 红色蓝色是帆布轮廓的半尺寸副本, 蓝色红色是半尺寸的图像。 我这样做,你可以看到为什么图像缩放在旋转时不平滑。

我会为自己保留这个function,也是一个方便的function。

查看新function的演示代码。

 demo = function(){ /** fullScreenCanvas.js begin **/ var canvas = (function(){ var canvas = document.getElementById("canv"); if(canvas !== null){ document.body.removeChild(canvas); } // creates a blank image with 2d context canvas = document.createElement("canvas"); canvas.id = "canv"; canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.style.position = "absolute"; canvas.style.top = "0px"; canvas.style.left = "0px"; canvas.style.zIndex = 1000; canvas.ctx = canvas.getContext("2d"); document.body.appendChild(canvas); return canvas; })(); var ctx = canvas.ctx; var image = new Image(); image.src = "http://i.imgur.com/gwlPu.jpg"; var w = canvas.width; var h = canvas.height; var cw = w / 2; // half canvas width and height var ch = h / 2; // Refer to diagram in answer function drawBestFit(ctx, angle, image){ var iw = image.width / 2; // half image width and height var ih = image.height / 2; // get the length CB var dist = Math.sqrt(Math.pow(cw,2) + Math.pow(ch,2)); // get the angle A var diagAngle = Math.asin(ch/dist); // Do the symmetry on the angle a1 = ((angle % (Math.PI *2))+ Math.PI*4) % (Math.PI * 2); if(a1 > Math.PI){ a1 -= Math.PI; } if(a1 > Math.PI/2 && a1 <= Math.PI){ a1 = (Math.PI/2) - (a1-(Math.PI/2)); } // get angles A1, A2 var ang1 = Math.PI/2 - diagAngle - Math.abs(a1); var ang2 = Math.abs(diagAngle - Math.abs(a1)); // get lenghts CE and CF var dist1 = Math.cos(ang1) * dist; var dist2 = Math.cos(ang2) * dist; // get the max scale var scale = Math.max(dist2/(iw),dist1/(ih)); // create the transform var dx = Math.cos(angle) * scale; var dy = Math.sin(angle) * scale; ctx.setTransform(dx, dy, -dy, dx, cw, ch); ctx.drawImage(image, -iw, - ih); // draw outline of image half size ctx.strokeStyle = "red"; ctx.lineWidth = 2 * (1/scale); ctx.strokeRect(-iw / 2, -ih / 2, iw, ih) // reset the transform ctx.setTransform(1, 0, 0, 1, 0, 0); // draw outline of canvas half size ctx.strokeStyle = "blue"; ctx.lineWidth = 2; ctx.strokeRect(cw - cw / 2, ch - ch / 2, cw, ch) } // Old function function drawToFitRotated(ctx, angle, image){ var dist = Math.sqrt(Math.pow(cw,2) + Math.pow(ch,2)); var imgDist = Math.min(image.width, image.height) / 2; var minScale = dist / imgDist; var dx = Math.cos(angle) * minScale; var dy = Math.sin(angle) * minScale; ctx.setTransform(dx, dy, -dy, dx, cw, ch); ctx.drawImage(image, -image.width / 2, - image.height / 2); ctx.setTransform(1, 0, 0, 1, 0, 0); } var angle = 0; function update(){ // animate the image if(image.complete){ angle += 0.01; drawBestFit(ctx,angle,image); } // animate until resize then stop remove canvas and flag that it has stopped if(!STOP){ requestAnimationFrame(update); }else{ STOP = false; var canv = document.getElementById("canv"); if(canv !== null){ document.body.removeChild(canv); } } } update(); } /** FrameUpdate.js end **/ var STOP = false; // flag to tell demo app to stop // resize Tell demo to stop then wait for it to stop and start it again function resizeEvent(){ var waitForStopped = function(){ if(!STOP){ // wait for stop to return to false demo(); return; } setTimeout(waitForStopped,200); } STOP = true; setTimeout(waitForStopped,100); } // if resize stop demo and restart window.addEventListener("resize",resizeEvent); // start demo demo(); 

旋转图像的首选方法是什么?

将上下文坐标转换为中心,旋转,然后使用负偏移进行绘制,

 ctx.save(); ctx.translate(width/2, height/2); ctx.rotate(-40*Math.PI/180); ctx.drawImage(img, -width/2, -height/2); ctx.restore(); 

如何在canvas上显示完整图像,没有红色边框?

要以任意旋转方式在canvas中拟合图像,您必须同时制作宽度和高度(至少) C ,其中C=sqrt(width^2 + height^2) 。 在两个方向上转换为C/2

要围绕中心旋转,您可以先将其平移到中心点,然后旋转,然后再将其平移。 像这样的东西:

 ctx.translate(width/2, height/2); ctx.rotate(-40*Math.PI/180); ctx.translate(-width/2, -height/2); 
 // Grab the Canvas and Drawing Context var canvas = $('#c'); var ctx = canvas.get(0).getContext('2d'); //rotate point x,y around origin with angle a, get back new point function rotate(x, y, a) { var cos = Math.cos, sin = Math.sin, a = a * Math.PI / 180, xr = x * cos(a) - y * sin(a); yr = x * sin(a) + y * cos(a); return [xr, yr]; } // Create an image element var img = document.createElement('IMG'); // When the image is loaded, draw it img.onload = function() { var width = img.naturalWidth; var height = img.naturalHeight; canvas.attr('width', width); canvas.attr('height', height); //only to show that borders of canvas ctx.rect(0, 0, width, height); ctx.fillStyle = "red"; ctx.fill(); ctx.save(); ctx.translate(width / 2, height / 2); ctx.rotate(-40 * Math.PI / 180); //comment this line out to see orign image ctx.translate(-width / 2, -height / 2); ctx.drawImage(img, 0, 0); ctx.restore(); } // Specify the src to load the image img.src = "http://i.imgur.com/gwlPu.jpg"; 
 body { background: #CEF; } 
   

将旋转中心移动到近似Canvas的中心:请参阅http://wisephoenix.org/html5/Rotation.htm的源代码。这是用html5和javascript编写的。