利用canvas裁切图片,可任意缩放旋转图片进行裁切,裁切预览,代码注释清晰,可根据需求自己二次开发。
canvas无线图片裁切功能,支持图片上传,裁切预览,图片任意角度旋转缩放裁切,异步上传图片。代码注释清晰。
1.只需要关注位移,并非图片左上角的坐标,而是图片左右上下滑动的距离,后面缩放会将图片正常话。
2.图片初始时左上角与裁剪框对齐(方便计算初始偏移量值)。
3.图片旋转始终以图片中心做旋转,以图片中心点计算图片旋转是的左上角偏移量。(以其他点旋转也可以,但要始终以同一个点,不然计算偏移量很麻烦)。
4.图片缩放已图片左上角为中心缩放,旋转后的缩放也要以原始左上角缩放。(通过控制图片宽高可以实现始终以原始左上角做缩放)(以其他点缩放要始终保持一个点,不然偏移量计算会有问题)。
5.canvas不要绘制一整张等高等宽的图片,会比较耗时(即:画布宽高,图片宽高,canvas宽高一样,绘制整张高清图)。图片操作用样式控制,最后裁切,在canvas的上下文环境也就是画布中绘制整张图片没性能问题,只要在canvas标签中显示的图片是整张图片的部分就不会太耗性能。
6.canvas 的toBlob方法要做兼容处理。 搜索上传为实现,实现方式与本地图片类似,代码中有注释说明,页面的样式风格是项目中用到的样式风格。具体样式可自行设计。字体样式文件也是本项目用到的字体图标,与图片裁切功能关系不大。静态页中的裁剪框,可以用canvas画布画出一个,减少页面样式布局的复杂度(可参考alloy_finger项目中的图片裁切示例。)
getSkewXY: function() { //获取画布需要的偏移量方法
var _this = this;
//保证图片的缩放是已左上角为中心点,此处的缩放是通过控制图片的width值进行的,可以保证以左上角为中心的。
//缩放操作可以用scale,在手势插件中的scalex进行控制时,缩放的中心点是不定的,根据手势的变化而变化,无法进行计算,
//如果此处的样式可以自己控制中心点,也可以用css中的scale进行缩放控制。
//暂时用了width属性进行了缩放控制(重点是要获取图片左上角相对于裁剪区的坐标位置)
//图片缩放后的偏移量计算
var tempW = _this.naturalWidth * _this.initScale,
tempH = _this.naturalHeight * _this.initScale,
diagonal = Math.sqrt(tempW * tempW + tempH * tempH) / 2, //对角线长度的一半
//此处计算的是按照初始宽高计算旋转后的偏移量
tempX = tempW / 2 - Math.cos((_this.initRotate + _this.countRotate) * Math.PI / 180) * diagonal,
tempY = tempH / 2 - Math.sin((_this.initRotate + _this.countRotate) * Math.PI / 180) * diagonal;
return {
x: _this.x + tempX,
y: _this.y + tempY
};
}
clipImg: function() {//裁切图片方法
var _this = this;
if (!_this.imgObj) return;
//canvas的宽高与裁剪框保持一致
var canvas = $('<canvas width="' + _this.clipWith + '" height="' + _this.clipHeight + '"></canvas>')[0],
context = canvas.getContext('2d');
// 计算图片旋转时,左上角坐标相对画布圆点的偏移量
var temp = _this.getSkewXY();
//先平移在旋转
//canvas对象不变,画布平移,使得画布的左上角与图片位于同一个点,然后旋转画布,达到裁剪看中看到的图片部分与canvas绘制的部分一致
context.translate(temp.x, temp.y);
//图片的旋转是按照图片中心点旋转,而画布旋转是基于左上角旋转,所以需要先计算偏移量,在旋转
//最终的结果要使得隐藏canvas窗口中的图片部分与页面中可视的裁剪框可见的图片部分保持一致,才能得到正确的裁剪图片
context.rotate(_this.countRotate * Math.PI / 180);
//此处绘图,绘制图片起始点0,0,因为上面画布已经做了便宜,此处不需在处理。将图像绘制在调整后的画布上
context.drawImage(_this.imgObj, 0, 0, _this.naturalWidth * _this.initScale, _this.naturalHeight * _this.initScale);
//预览裁切后的图像
$('#temp')[0].src = canvas.toDataURL();
// 将canvas裁切的图片已大对象的形式通过异步请求传给后台保存,与后台自行配合实现
//canvas.toBlob(function(blob){//canvas转换成大对象,作为文件存储
// var formData = new FormData();
// formData.append('pic', blob);
// formData.append('lemmaId', _this.getQueryItem('lemmaId'));
// formData.append('width', _this.clipWith);
// formData.append('height',_this.clipHeight);
// $.ajax({
// type: 'POST',
// url: '/baike/wireless/edit',
// data: formData,
// dataType: 'json',
// contentType: false,
// processData: false,
// cache: false,
// success: function(data){
// },
// complete: function(){
// }
// });
// }, 'image/jpeg', 0.85);
}
alloy_finger.js移动端小巧的手势库(代码库中有一个腾讯应用的图片上传示例,不过不支持图片旋转)
tansform.js与手势库在同一个项目下