从css3和canvas的旋转说起

之前遇到的一个老问题啦,突然发现又傻傻分不清楚啦。。。来总结一下吧,哈哈。先来说一下,为什么要把这两者放在一起说,先上需求:如何把反着的一张图片弄正,并输出出来呢?也就是我们的目标如图:

这个需求来源于,手机照相机照出的图片其实存起来的时候对于程序显示来说不都是正的,我们自己在手机上浏览看起来是正的是因为手机的程序帮我们搞定啦,可是当我们拿到手机原始图片的时候想展示的时候发现,矣?怎么有的反着的,其实照相机照相的时候会留下照片的方向信息,根据这些方向信息我们就可以把照片调正过来,然后再存到服务器或者展示出来,关于照片里的方向信息大家可以去参考EXIF.js这个库,我总结的信息如下:(EXIF信息有1 8 3 6)

  • 1: 正向
  • 8: 需要逆时针旋转90
  • 3: 需要旋转180度
  • 6: 需要顺时针旋转90

好了,有了这些信息我们来看看怎么去做呢?
比如有张图是需要旋转90度才能扶正的,那写css3的rotate的不就行了么?是啊,我最初也是这种感觉,可是这样有诸多限制,比如,如果你想把图片存在服务端,下次别人用的时候图片就是正的了,就不用再做特殊处理了啊,那得图像处理下,前端怎么弄呢?canvas应该可以吧!本以为可以像css3那样两行搞定:

transform: rotate(90deg);
transform-origin: center;

可是绕了很久才发现不行啊,发现两者是有区别的:

  • css3是基于图形自身的位置为坐标系进行变换的
  • canvas有画布的概念,是基于画布坐标系进行变换的

额。。我说完也觉得一脸懵逼,其实我觉得很多概念和感觉对于普通开发者来讲都不是灵感带来的,都是不断试验和思考带来的,所以如果我做不了特斯拉,那我向爱迪生靠近些也是好的,那么动手吧!

例子如下:其中用了三种不同的方式解决,每种方式都可以达到效果,但其实是不一样的,可以注意下每种方式最后留下的坐标系原点在哪里,是的,条条大路通罗马。例子中请按button得先后顺序点击实验,要不然会乱的,因为对顺序有依赖额。。觉得内嵌看得太小的话,可以点击这里 $$点我$$
特别注意的就是:css3都是基于自身位置的变换,而canvas变换的是坐标系

关键源码如下:

var canvas = document.getElementById('canvas');
var img = new Image();
img.src = './test.jpeg';
img.onload = function() {
    var cts = canvas.getContext("2d");
        canvas.width = this.naturalHeight;
        canvas.height = this.naturalWidth;
        cts.clearRect(0, 0, canvas.width, canvas.height);
        cts.fillStyle = "#000";
        cts.fillRect(0, 0, canvas.width, canvas.height);
//坐标系变换
        cts.translate(canvas.width/2, canvas.height/2);
        cts.rotate(90*Math.PI/180);

//@way1, 移动坐标系的原点
    cts.translate(-canvas.height/2, -canvas.width/2);
    cts.drawImage(img, 0, 0);

//@way2,改变图的开始取值点
//cts.drawImage(img, -canvas.height/2, -canvas.width/2);

/** 还有什么办法吗? **/
//cts.rotate(90*Math.PI/180);
//cts.drawImage(img, 0, -canvas.width);
}

这样你就可以得到正确绘制的图片的canvas了,把它转换成图片或者base64,就可以上传至服务器了,下次从服务器下载下来你就能看到正确方向的图片啦,至于需要旋转-90,180和-180这些角度,原理同上,大家可以动手试试看哈~~