当前位置: 首页 > Web前端 > HTML5

Canvas(一)手机拍照调整

时间:2023-04-05 19:16:21 HTML5

之前在做手机拍照调整的时候遇到了一些问题。下面我整理一下,总结一下。如果有什么问题,请告诉我。问题一:移动画面时画面卡住。问题2:图片旋转时的角度问题(这道题知道不难,不知道就难了,这也是我新学的一个知识点,所以说一下).问题三:画iphone图片的canvas旋转了。解决方案一:避免直接改变元素的left和top,这样会导致页面重绘,造成卡顿。可以使用translate解决2:使用向量叉乘,先定义两个手指的起点和终点,调整数据和图片的默认样式,选择图片后显示imgPosition,根据需要设置//手指AfingerA:{startX:0,startY:0,endX:0,endY:0},//手指BfingerB:{startX:0,startY:0,endX:0,endY:0},//调整数据移动:{x:0,y:0,temX:0,temY:0,scale:1,temScale:1,allDeg:0,temDeg:0},//默认样式imgPosition:{left:0,top:0,width:0,height:0},由于使用了translate和scale,所以本次调整后的数据必须加到上一次(temX,temY,temScale,temDeg的属性用来暂存上次的数据进行累加)并分别开始计算和最后两个手指的向量:公式函数Vector(x1,y1,x2,y2){this.x=x2-x1this.y=y2-y1}//的向量开头的两个手指varvector1=newVector(this.fingerA.startX,this.fingerA.startY,this.fingerB.startX,this.fingerB.startY)//结尾的两个手指的向量varvector2=newVector(this.fingerA.endX,this.fingerA.endY,this.fingerB.endX,this.fingerB.endY)计算两个向量的夹角:varcos=calculateVM(vector1,vector2)varangle=Math.acos(cos)*180/Math.PIfunctioncalculateVM(vector1,vector2){/**矢量角公式:cosθ=矢量a×矢量b/|矢量a|×|矢量b|*设置向量a=(x1,y1),向量b=(x2,y2)*然后cosθ=向量a.向量b/|向量a|×|向量b|=(x1x2+y1y2)/[√(x12+y12)*√(x22+y22)]*/return(vector1.x*vector2.x+vector1.y*vector2.y)/(Math.sqrt(vector1.x*vector1.x+vector1.y*vector1.y)*Math.sqrt(vector2.x*vector2.x+vector2.y*vector2.y))}然后计算方向:vardirection=calculateVC(vector1,vector2)functioncalculateVC(vector1,vector2){//叉积公式return(vector1.x*vector2.y-vector2.x*vector1.y)>0?1:-1}得到最终的旋转角度this.move.allDeg=direction*angle+this.move.temDeg附上部分代码://AdjuststartadjustStart:function(e){letevent=e.targetTouchesthis.fingerA.startX=event[0].pageXthis.fingerA.startY=event[0].pageY//移动if(event.length===1){this.isDrag=truethis.isScale=false//scale}elseif(event.length===2){this.isScale=truethis.isDrag=falsethis.fingerB.startX=event[1].pageXthis.fingerB.startY=event[1].pageY}},//调整、移动或缩放adjustIng:function(e){letevent=e.targetTouchesthis.fingerA.endX=event[0].pageXthis.fingerA.endY=event[0].pageY//移动if(this.isDrag){//本次移动的距离应该加上上一次的移动距离this.move.x=this.fingerA.endX-this.fingerA.startX+this.move.temXthis.move.y=this.fingerA.endY-this.fingerA.startY+this.move.temY}elseif(this.isScale){//缩放this.fingerB.endX=event[1].pageXthis.fingerB.endY=event[1].pageY//两个手指之间的距离letdistanceStart=Math.sqrt(Math.pow(this.fingerA.startX-this.fingerB.startX,2)+Math.pow(this.fingerA.startY-this.fingerB.startY,2))让distanceEnd=Math.sqrt(Math.pow(this.fingerA.endX-this.fingerB.endX,2)+Math.pow(this.fingerA.endY-this.fingerB.endY,2))this.move.scale=distanceEnd/distanceStart*this.move.temScale//向量叉积,求旋转方向和角度//两根手指的向量var开头vector1=newVector(this.fingerA.startX,this.fingerA.startY,this.fingerB.startX,this.fingerB.startY)//末尾两个手指的向量varvector2=newVector(this.fingerA.endX,this.fingerA.endY,this.fingerB.endX,this.fingerB.endY)varcos=calculateVM(vector1,vector2)varangle=Math.acos(cos)*180/Math.PIvardirection=calculateVC(vector1,vector2)this.move.allDeg=direction*angle+this.move.temDeg}},//调整结束adjustEnd:function(e){this.move.temX=this.move.xthis.move.temY=this.move.ythis.move.temScale=this.move.scalethis.move.temDeg=this.move.allDegthis.isDrag=falsethis.isScale=false},方案三:图片的调整数据已经获取,开始canvas绘制。这里有两种方式,可以将this.move.scale转换成left和top,也可以直接使用canvas的scale。这里我使用第二种方法,一般情况下直接从图库中选择图片。不会有默认轮换的问题。直接画就可以了ctxTemp.save()ctxTemp.translate(cx,cy)ctxTemp.rotate(Math.PI/180*move.allDeg)ctxTemp.scale(move.scale,move.scale)ctxTemp.translate(-cx,-cy)ctxTemp.drawImage(fileData.image,moveLeft,moveTop,drawWidth,drawHeight)ctxTemp.restore()注意:我拿到的调整数据是基于图片中心点的,所以旋转的时候也要设置中心以及缩放画布的Point,也就是上面代码中的(cx,cy),通过(left+w/2,top+h/2)得到,下面解决图片默认旋转的情况,思路:先修正照片的默认角度,再按照普通图片进行处理。这里使用插件exif-js.js获取图片的默认信息(默认要旋转的角度)。这里我们以90°为例。如图:一张图片应该是虚线一样的,但实际上旋转成了实线,直接旋转了canvas。最后,我们看到的是什么都看不到,因为它超出了可见范围。画布的左边缘,画布的默认源点是坐标系的左上角。注意图片。现在我们使用drawImage来绘制图片。里面的参数是left和top,w和h互换。再让图片绘制可见区域,像没有旋转一样,y方向应该变成负的,也就是-l,drawImage(img,t,-l,h,w),解决默认旋转后,中心点为也相应改变:ctxTemp.save()ctxTemp.rotate(Math.PI/180*90)//注意正负坐标系变化ctxTemp.translate(cy,-cx)ctxTemp.rotate(Math.PI/180*move.allDeg)ctxTemp.scale(move.scale,move.scale)ctxTemp.translate(-cy,cx)ctxTemp.drawImage(fileData.image,moveTop,-(moveLeft+drawWidth),drawHeight,drawWidth)之前ctxTemp.restore()原来是(cx,cy),现在是(cy,-cx)(90°以外的情况相应修改)部分代码:/**@imgPosition:imageinformation*@orient:system旋转角度识别*@move:调整数据*@fileData:文件信息*@clip:裁剪帧信息*@fun:回调*/functiondrawImg(imgPosition,orient,move,fileData,clip,fun){if(fileData.image){varcanvasTemp=document.createElement('canvas')varctxTemp=canvasTemp.getContext('2d')//画布宽度varw=480//裁剪框与画布的比例varratio=w/clip.clipWidth//画布高度varh=ratio*clip.clipHeightcanvasTemp.height=hcanvasTemp.width=w//中心点varcx=(imgPosition.left+move.x+imgPosition.width/2)*ratiovarcy=(imgPosition.top+move.y+imgPosition.height/2)*ratio//图片相对于左边canvasletmoveLeft=(imgPosition.left+move.x)*ratio//图片相对于画布的顶部letmoveTop=(imgPosition.top+move.y)*ratio//图片的比例宽度和canvasletdrawWidth=imgPosition.width*ratio//图片和画布的比例高度letdrawHeight=imgPosition.height*ratio//90°if(orient===6){ctxTemp.save()ctxTemp.rotate(Math.PI/180*90)//坐标注意正负系统变化ctxTemp.translate(cy,-cx)ctxTemp.rotate(Math.PI/180*move.allDeg)ctxTemp.scale(move.scale,move.scale)//恢复坐标系ctxTemp.translate(-cy,cx)ctxTemp.drawImage(fileData.image,moveTop,-(moveLeft+drawWidth),drawHeight,drawWidth)ctxTemp.restore()}else{ctxTemp.save()ctxTemp.translate(cx,cy)ctxTemp.rotate(数学.PI/180*move.allDeg)ctxTemp.scale(move.scale,move.scale)//恢复坐标系ctxTemp.translate(-cx,-cy)ctxTemp.drawImage(fileData.image,moveLeft,moveTop,drawWidth,drawHeight)ctxTemp.restore()}varbase64=canvasTemp.toDataURL('image/jpeg',0.8)//console.log(base64)fun(base64)}写错了还是不好,希望大家赐教demo地址