推荐:
这一篇文章是早年为了解决图片裁剪的探索性文章,现在已经开放出了falsh版及html5版本的图片裁剪插件,各位有时间可以看看:
上面两个解决方案已经经过几个项目,可以应用于低级浏览器及现代浏览器,ipad,移动设备等。
前言:
手机越来越普遍,利用手机即时拍照裁剪图片的功能需求是存在的。不才目前供职于一家网站,里面也有触屏版需要裁剪图片。
技术难点:
一般难点:
html5对图片的读取处理。
意外难点:
难点1、ios6,7下面对超过2M的图片有一个限制,该限制使得假如你直接将2m的本地图片或者相片绘制到canvas画布上面会出现压扁现象。
难点2、ios拍照会有额外的exif信息(图片信息),该信息包含了拍摄日期,作者,还有一个很关键的orientation(角度),ios拍摄有四个角度,分别为1,3,6,8,里面的代表含义记不清楚,不过就是表示,正拍,左旋90度,右旋90度,旋转180度。由于ios有这个orientation,所以假如用户使用ios的其他角度拍摄,直接绘制到画布上面会出现图片颠倒,并非用户希望的情形。这时候你就要根据角度进行调整了。
三、部分代码,为何这是部分代码?因为涉及到前端后端及样式,我没法提供完整代码,而且,涉及到公司机密,我只能提供一些我在解决bug途中所写的测试代码。
譬如,将图片颠倒缩小在放大,用于用户拖动裁剪框以后,js获得用户拖动的坐标,高度宽度,再根据相片的orientation逆推原本的坐标及正确的高度宽度,然后裁剪出那一部分图像,再根据orientation调整角度,必要时需要颠倒,缩放图像。
<html>
<head>
<title>画布的旋转、缩放等功能。</title>
<script type="text/javascript" src="/static/mobile/lib/zepto.min.js"></script>
</head>
<body>
<h1>选择:<a href="javascript:changeImg(6);">右旋90度图片</a> <a href="javascript:changeImg(3);">旋转180度图片</a> <a href="javascript:changeImg(8);">左旋90度图片</a> <a href="javascript:changeImg(1);">正常图片</a></h1>
<img id="sourceImg" src="images/exif_info_6.jpg" style="max-width: 400px;max-height: 400px;"/>
<fieldset>
<legend>设置需要裁剪的x,y,及裁剪高度及宽度。</legend>
<div>
<table>
<tr><td>x:</td><td><input type="text" id="txt_x" value="600"/></td></tr>
<tr><td>y:</td><td><input type="text" id="txt_y" value="800"/></td></tr>
<tr><td>width:</td><td><input type="text" id="txt_width" value="1480"/></td></tr>
<tr><td>height:</td><td><input type="text" id="txt_height" value="850"/></td></tr>
<tr><td>Orientation:</td><td><input type="text" id="txt_Orientation" value="6"/></td></tr>
<tr><td>画布缩小倍数:</td><td><input type="text" id="txt_scale" value="5"/></td></tr>
<tr><td> </td><td><input type="button" value="裁剪到临时画布" id="btn_saveToTmp"></td></tr>
</table>
</div>
<div>临时画布:</div>
<div style="border: 1px green solid;">
<canvas id="canvas_tmp"></canvas>
</div>
<div>最终画布</div>
<div style="border: 1px red solid;">
<canvas id="canvas_final"></canvas>
<div id="results"></div>
</div>
</fieldset>
</body>
</html>
<script type="text/javascript">
function changeImg(_Orientation){
switch (_Orientation){
case 8:
setX(750);setY(220);setW(1800);setH(1200);setScale(5); setOrientation(8);
_sourceImg.src="images/exif_info_8.jpg";
break;
case 6:
setX(600);setY(800);setW(1480);setH(850);setScale(5); setOrientation(6);
_sourceImg.src="images/exif_info_6.jpg";
break;
case 3:
setX(600);setY(450);setW(2300);setH(1450);setScale(5);setOrientation(3);
_sourceImg.src="images/exif_info_3.jpg";
break;
case 1:
setX(600);setY(450);setW(2300);setH(1450);setScale(5);setOrientation(1);
_sourceImg.src="images/exif_info_1.jpg";
break;
}
}
var _sourceImg=document.getElementById("sourceImg");
var tmpCanvas=document.getElementById("canvas_tmp");
var tmpContext=tmpCanvas.getContext("2d");
var finalCanvas=document.getElementById("canvas_final");
var finalContext=finalCanvas.getContext("2d");
function getX(){
return parseInt($("#txt_x").val());
}
function getY(){
return parseInt($("#txt_y").val());
}
function getW(){
return parseInt($("#txt_width").val());
}
function getH(){
return parseInt($("#txt_height").val());
}
function getScale(){
return parseFloat($("#txt_scale").val());
}
function getOrientatin(){
return parseFloat($("#txt_Orientation").val());
}
function setX(x){
$("#txt_x").val(x);
}
function setY(x){
$("#txt_y").val(x);
}
function setW(x){
$("#txt_width").val(x);
}
function setH(x){
$("#txt_height").val(x);
}
function setScale(x){
$("#txt_scale").val(x);
}
function setOrientation(x){
$("#txt_Orientation").val(x);
}
function drawToTmpCanvas(x,y,w,h){
tmpContext.clearRect(0,0,tmpCanvas.width,tmpCanvas.height) ;
var _cW=parseFloat(w/getScale());
var _cH=parseFloat(h/getScale());
tmpCanvas.width=_cW;
tmpCanvas.height=_cH;
tmpContext.drawImage(_sourceImg,x,y,w,h,0,0,_cW,_cH);
}
$("#btn_saveToTmp").click(function(){
drawToTmpCanvas(getX(),getY(),getW(),getH());
var _cW=parseFloat(getW()/getScale());
var _cH=parseFloat(getH()/getScale());
$("#results").html("");
var newCanvas=document.createElement("canvas");
var newContext=newCanvas.getContext("2d");
$("#results").append(newCanvas);
drawToFinal(tmpCanvas,newCanvas,newContext,_cW,_cH,getOrientatin());
});
function drawToFinal(_sourceCanvas,_drawCanvas,_drawContext,_sw,_sh,_Orientation){
switch(_Orientation){
case 8:
// 90 rotate left --需要90度向左旋转。。那么,这个 PixelYDimension就是宽度了,PixelXDimension就是高度了。
_drawCanvas.width=_sh;
_drawCanvas.height=_sw;
var tSetting={
dx:0,
dy:0,
dw:0,
dh:0,
transX:0,
transY:0
};
tSetting.dw=_sh;
var scale2=_sw/_sh;
tSetting.dh=parseFloat(tSetting.dw/scale2);
tSetting.dy=(_sw-tSetting.dh)/2;
tSetting.transY=_sw/2;
tSetting.transX=_sh/2;
_drawContext.translate(tSetting.transX,tSetting.transY);
_drawContext.rotate(-0.5*Math.PI);
_drawContext.scale(scale2,scale2);
_drawContext.drawImage(_sourceCanvas,0,0,_sw,_sh,tSetting.dx-tSetting.transX,tSetting.dy-tSetting.transY,tSetting.dw,tSetting.dh);
break;
case 3:
//180向左旋转 (右旋转也可以。)
_drawCanvas.width=_sw;
_drawCanvas.height=_sh;
var tSetting={
dx:0,
dy:0,
dw:0,
dh:0,
transX:0,
transY:0
};
tSetting.dw=_sw;
tSetting.dh=_sh;
tSetting.transY=_sh/2;
tSetting.transX=_sw/2;
_drawContext.translate(tSetting.transX,tSetting.transY);
_drawContext.rotate(1*Math.PI);
//_drawContext.scale(scale2,scale2);
_drawContext.drawImage(_sourceCanvas,0,0,_sw,_sh,tSetting.dx-tSetting.transX,tSetting.dy-tSetting.transY,tSetting.dw,tSetting.dh);
break;
case 6:
//90 rotate right 需要向右旋转90度,PixelYDimension就是宽度了,PixelXDimension就是高度了。
_drawCanvas.width=_sh;
_drawCanvas.height=_sw;
var tSetting={
dx:0,
dy:0,
dw:0,
dh:0,
transX:0,
transY:0
};
tSetting.dw=_sh;
var scale2=_sw/_sh;
tSetting.dh=parseFloat(tSetting.dw/scale2);
tSetting.dy=(_sw-tSetting.dh)/2;
tSetting.transY=_sw/2;
tSetting.transX=_sh/2;
_drawContext.translate(tSetting.transX,tSetting.transY);
_drawContext.rotate(0.5*Math.PI);
_drawContext.scale(scale2,scale2);
_drawContext.drawImage(_sourceCanvas,0,0,_sw,_sh,tSetting.dx-tSetting.transX,tSetting.dy-tSetting.transY,tSetting.dw,tSetting.dh);
break;
case 1:
//正常状态。
_drawCanvas.width=_sw;
_drawCanvas.height=_sh;
var tSetting={
dx:0,
dy:0,
dw:0,
dh:0,
transX:0,
transY:0
};
tSetting.dw=_sw;
tSetting.dh=_sh;
tSetting.transY=_sh/2;
tSetting.transX=_sw/2;
_drawContext.translate(tSetting.transX,tSetting.transY);
//_drawContext.rotate(1*Math.PI);
//_drawContext.scale(scale2,scale2);
_drawContext.drawImage(_sourceCanvas,0,0,_sw,_sh,tSetting.dx-tSetting.transX,tSetting.dy-tSetting.transY,tSetting.dw,tSetting.dh);
break;
break;
}
}
</script>
测试用结果如下:
而实际上线的效果如下:
打开图片裁剪页面:
点击头像,然后读取本地图片:
拖动裁剪框及下面的拖动条以调整裁剪框大小及位置,最后得到:
保存裁剪结果:
done。