无通信的图像旋转

图像的旋转是目前的 web 应用程序中比较常见的一种操作。曾经在做这样的程序时,思路比较狭窄,总是认为扔给服务器端处理比较稳妥。这种方法大致的过程是这样的:当用户点击一种旋 转方向,立即发出一个 Ajax 请求,告诉后端要旋转的图像和旋转的角度,再由后端通过一定的工具(如 PHP 的 GD 库)生成新的图像再进行存储并向浏览器返回新的图像地址,这时使用 JavaScript 对图像的 src 属性进行更新即可。这个过程对于前端来说非常的简单,它大概像下面这样:

$.ajax({
	url : 'url.php',
	type : 'GET',
	data : {
		degree : 90,
		imageId : id
	},
	success : function(src){
		image.src = src;
	}
});

尽管可以在前端缓存每个已经旋转过的角度的图像地址,但是当旋转到新的角度时,仍然需要发出 Ajax 请求,用户需要一个等待的过程,服务器也需要对图像进行处理和存储,还要考虑才适当的时候删除掉这些“过程中”的图像,非常的麻烦。事实上,利用 canvas 就可以轻易的实现这样的功能,而对于不支持 canvas 的 IE ,则可以使用滤镜来达到同样的目的,对于这个操作而言,IE 的滤镜甚至较 canvas 更为简单。最重要的是,由于是纯前端的行为,用户几乎无需等待就可以看到效果,也没有建立任何 HTTP 请求,不会对服务器端产生任何影响。

下面我们就来一步步实现纯前端方式的图像旋转,首先是 IE,在 IE 中通过 BasicImage 滤镜 的 rotate 属性值来设置图像的旋转角度,根据微软的文档,这个值只能设置为 0、1、2、3,分别表示 0度,90度,180度和270度四个角度的旋转,假定我们已经获取到了图像对象为 image,旋转的角度为 degree,那么具体的代码就非常简单了:

image.style.filter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree/90+')';

其他浏览器中的情况要稍微复杂一点,需要借助于 Canvas,使用其 rotate 方法旋转 Canvas,使用其 drawImage 方法在 Canvas 上绘制图像。rotate 方法非常简单,它接受一个参数,即旋转的弧度数,注意这里是弧度而不是角度,如果还记得高中数学的话,弧度与角度的转换公式应该并不陌生:

var radian = degree * Math.PI / 180;
/** 弧度 = 角度 * π / 180 **/

drawImage 方法的参数比较多,但我们这里指使用其中前三个参数:图像对象,绘制起点的 x 坐标,绘制起点的 y 坐标。在调用这些方法之前,我们需要为 img 元素 追加一个 canvas:

<img src="img_rotate.jpg" alt="football" id="rotate_demo" />
<canvas id="image_canvas"></canvas>

接下来在 JavaScript 中获取到这两个元素,然后使用刚才介绍的两个方法根据不同的角度对图像和 canvas 进行处理:

var image = document.getElementById("rotate_demo");
var canvas = document.getElementById("image_canvas");
var ctx = canvas.getContext('2d');
var width = image.width, height = image.height, x = 0, y = 0;
switch(degree){
     case 90:
          width = image.height;
          height = image.width;
          y = image.height * (-1);
          break;
     case 180:
          x = image.width * (-1);
          y = image.height * (-1);
          break;
     case 270:
          width = image.height;
          height = image.width;
          x = image.width * (-1);
          break;
}

canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
ctx.rotate(degree * Math.PI / 180);
ctx.drawImage(image, x, y);
image.style.display = "none";

上面的代码看起来比较多,实际上核心方法只有刚才讲到的 rotate 和 drawImage,但是需要注意的,当画布旋转的时候,画布的宽高可能会发生反转,绘制的坐标也可能会反转,所以我们对 degree 进行了 switch ,具体处理在不同的角度下的反转情况,最后将原始图像隐藏,使用绘制好的 canvas 来显示。

纯前端旋转图像的主要过程就是这样的,剩下的问题是通过下面的函数来判断具体让浏览器使用 canvas 还是使用滤镜:

function supportCanvas(){
	return !!document.createElement('canvas').getContext;
}

将上面的代码套在一个函数中,并稍加改造,在外面加上一个按钮,即可循环旋转图像,下面是本文 Demo 的完整代码。html:

<p><input type="button" value="旋转" id="rorate_button"/></p>
<img src="img_rotate.jpg" alt="football" id="rotate_demo"/>
<canvas id="image_canvas"></canvas>

JavaScript:

// canvas 能力检测
var supportCanvas = !!document.createElement('canvas').getContext;

// 主函数
function imageRotate(degree,image,canvasId){
	if(!supportCanvas){
		image.style.filter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree/90+')';
	}else{
		var canvas = document.getElementById(canvasId);
		var ctx = canvas.getContext('2d');
		var width = image.width, height = image.height, x = 0, y = 0;
		switch(degree){
		     case 90:
		          width = image.height;
		          height = image.width;
		          y = image.height * (-1);
		          break;
		     case 180:
		          x = image.width * (-1);
		          y = image.height * (-1);
		          break;
		     case 270:
		          width = image.height;
		          height = image.width;
		          x = image.width * (-1);
		          break;
		}
		canvas.setAttribute('width', width);
		canvas.setAttribute('height', height);
		ctx.rotate(degree * Math.PI / 180);
		ctx.drawImage(image, x, y);
		image.style.display = "none";
	}
}

// 初始角度与事件绑定
var degree = 0;
var image = document.getElementById("rotate_demo");
document.getElementById("rorate_button").onclick = function(){
	degree += 90;
	degree = degree === 360 ? 0 : degree;
	imageRotate(degree,image,'image_canvas');
};

参考资料:

转自:http://www.jsmix.com/javascript/image-rotate-without-correspondence.html

原文地址:https://www.cnblogs.com/myphoebe/p/2226266.html