工作中需要进行裁剪图片,便百度了一下,我在这里有一个可行的方法,在这里展示出来,下面是代码:
html:
<!DOCTYPE html
>
<
html
lang=
"en"
>
<
head
>
<
meta
charset=
"UTF-8"
>
<
title
>zimu canvas crop
</
title
>
<
script
src=
"jquery.min.js"
>
<
/
script
>
<
style
>
.canvas-box {
width:
300px;
height:
200px;
position:
relative;
-webkit-user-select:
none;
-moz-user-select:
none;
-o-user-select:
none;
user-select:
none
}
.canvas-box .overlay {
position:
absolute;
left:
0;
top:
0;
cursor:
move;
border:
1px
solid
#69f;
}
.canvas-box div,
.canvas-box canvas {
-webkit-user-select:
none;
-moz-user-select:
none;
-o-user-select:
none;
user-select:
none
}
<
/
style
>
</
head
>
<
body
>
<
input
type=
"file"
value=
"select img"
id=
"ipt"
value=
"选择图片"
>
<
div
class=
"canvas-box"
>
</
div
>
<
input
type=
"button"
id=
"save"
value=
"保存"
>
<
div
id=
"base64"
></
div
>
</
body
>
<
script
src=
"zm-canvas-crop.js"
></
script
>
<
script
type=
"text/javascript"
>
function
saveCallBack(
base64) {
$(
'#base64').
html(
base64);
console.
log(
$(
'#base64').
html())
//最终把此base64传给后端
/**
$.ajax({
data: {
base64: base64
}
})
**/
}
var
c =
new
ZmCanvasCrop({
fileInput:
$(
'#ipt')[
0],
saveBtn:
$(
'#save')[
0],
box_width:
300,
//剪裁容器的最大宽度
box_height:
200,
//剪裁容器的最大高度
min_width:
640,
//要剪裁图片的最小宽度
min_height:
640
//要剪裁图片的最小高度
},
saveCallBack);
<
/
script
>
</
html
>
function
ZmCanvasCrop(
opt,
saveCallBack) {
this.
init(
opt);
this.
_option.
crop_box_width =
opt.
box_width;
//剪裁容器的最大宽度
this.
_option.
crop_box_height =
opt.
box_height;
//剪裁容器的最大高度
this.
_option.
crop_min_width =
opt.
min_width;
//要剪裁图片的最小宽度
this.
_option.
crop_min_height =
opt.
min_height;
//要剪裁图片的最小高度
this.
_option.
crop_scale =
opt.
min_width /
opt.
min_height;
//图片会按照最小宽高的比例裁剪
}
ZmCanvasCrop.
prototype = {
_$box:
'',
_$canvasDown:
'',
_$canvasUp:
'',
_input:
'',
_ctxUp:
'',
//裁剪区域canvas
_img:
'',
_img_show: {
width:
'',
height:
'',
scale:
'',
//显示像素除以实际像素
crop_width:
'',
//要裁剪部分显示宽
crop_height:
'',
min_width:
'',
//要裁剪部分显示最小宽度
min_height:
''
},
_option: {
crop_box_width:
'',
//图片操作区域宽限制
crop_box_height:
'',
//图片操作区域高限制
crop_min_width:
'',
//剪裁实际最小像素宽
crop_min_height:
'',
//剪裁实际最小像素高
crop_scale:
''
//宽高比
},
_save: {
left:
'',
top:
'',
width:
'',
height:
''
},
_resize_point: {
color:
'#69f',
size:
8
},
_resize_btn: {},
init
:
function(
opt) {
var
self =
this;
self.
_input =
opt.
fileInput;
//读取文件
self.
_$box =
$(
'.canvas-box');
//背景图片
self.
readFile();
//读取文件
opt.
saveBtn.
addEventListener(
'click',
function() {
self.
save();
//保存图片
});
},
imgTrue
:
function() {
//图片大小判定
if (
this.
_img.
width <
this.
_option.
crop_min_width ||
this.
_img.
height <
this.
_option.
crop_min_height) {
return
false;
}
return
true;
},
readFile
:
function() {
//读取文件
var
self =
this;
if (
typeof
FileReader ===
'undefined') {
//是否支持fileReader
alert(
"抱歉,你的浏览器不支持 FileReader");
input.
setAttribute(
'disabled',
'disabled');
}
else {
this.
_input.
addEventListener(
'change',
readFile,
false);
}
function
readFile() {
var
file =
this.
files[
0];
if (!
/image
\/
\w
+
/.
test(
file.
type)) {
//是否是图片
alert(
"文件必须为图片!");
return
false;
}
var
reader =
new
FileReader();
reader.
readAsDataURL(
file);
reader.
onload =
function(
e) {
//result.innerHTML = '<img src="'+this.result+'" alt=""/>'
self.
drawCavDown(
this.
result);
}
}
},
drawCavDown
:
function(
src) {
//选择要裁剪的图片
var
self =
this;
//清除上一次的
self.
_$box.
html(
'');
self.
_save = {};
self.
_img_show = {};
self.
_img =
new
Image();
self.
_img.
onload =
function() {
if (!
self.
imgTrue()) {
alert(
'图片大小必须大于:' +
self.
_option.
crop_min_width +
'*' +
self.
_option.
crop_min_height);
return;
}
//让宽或者高撑满
self.
setShowImg();
self.
_img_show.
scale =
self.
_img_show.
width /
self.
_img.
width;
//缩放比例
//计算裁剪高亮区域的最小宽高
self.
_img_show.
min_width =
self.
_option.
crop_min_width *
self.
_img_show.
scale;
self.
_img_show.
min_height =
self.
_option.
crop_min_height *
self.
_img_show.
scale;
//初始化显示剪裁框宽高,按照宽或者高(更小)的一半显示,如果一半值小于最小可剪裁值,还是按最小剪裁值显示
var
size;
if (
self.
_img.
width >
self.
_img.
height) {
size =
self.
_img.
height /
2;
if (
size <
self.
_option.
crop_min_height) {
self.
resizeCrop({
width:
self.
_option.
crop_min_width,
height:
self.
_option.
crop_min_height
});
}
else {
self.
resizeCrop({
height:
size,
width:
size *
self.
_option.
crop_scale
});
}
}
else {
size =
self.
_img.
width /
2;
if (
size <
self.
_option.
crop_min_width) {
self.
resizeCrop({
width:
self.
_option.
crop_min_width,
height:
self.
_option.
crop_min_height
});
}
else {
self.
resizeCrop({
height:
size /
self.
_option.
crop_scale,
width:
size
});
}
}
//绘制底层剪裁区域
drawDown();
//载入上层canvas
self.
addUpCanvas();
//绑定松开鼠标事件
$(
document).
on(
'mouseup',
function() {
//在外部松开
$(
document).
off(
'mousemove');
/* $('.resize-point').off('mousedown');
self._$canvasUp.off('mousedown');
self.upCanvasEvent();
self.resizeEvent();*/
});
}
self.
_img.
src =
src;
function
drawDown() {
//绘制底层裁剪区域
var
$canvas =
$(
'<canvas width="' +
self.
_img_show.
width +
'" height="' +
self.
_img_show.
height +
'"></canvas>');
self.
_$box.
append(
$canvas);
var
$ctx =
$canvas[
0].
getContext(
'2d');
$ctx.
drawImage(
self.
_img,
0,
0,
self.
_img_show.
width,
self.
_img_show.
height);
//裁剪区域透明
$ctx.
beginPath();
$ctx.
fillStyle =
"rgba(0,0,0,0.6)";
$ctx.
fillRect(
0,
0,
self.
_img_show.
width,
self.
_img_show.
height);
/*for(var i=1;i<5;i++){
$ctx.moveTo(self._img_show.width/5*i,0);
$ctx.lineTo(self._img_show.width/5*i, self._img_show.height);
$ctx.moveTo(0, self._img_show.height/5*i);
$ctx.lineTo(self._img_show.width, self._img_show.height/5*i);
$ctx.strokeStyle="rgba(255,255,255,0.9)";
$ctx.stroke();
}*/
self.
_$canvasDown =
$canvas;
}
},
setResizePoint
:
function(
direction,
left,
top) {
return
$(
'<div class="resize-point" style="width:' +
this.
_resize_point.
size +
'px;height:' +
this.
_resize_point.
size +
'px;' +
'background: ' +
this.
_resize_point.
color +
';cursor:' +
direction +
';position:absolute;' +
'left:' +
left +
'px;top:' +
top +
'px"></div>');
},
addUpCanvas
:
function() {
//开始裁剪图片前景框
var
self =
this;
self.
addResizeBtn();
//添加放大缩小按钮
self.
_ctxUp =
self.
_$canvasUp[
0].
getContext(
'2d');
self.
_ctxUp.
drawImage(
self.
_img,
0,
0,
self.
_img_show.
crop_width /
self.
_img_show.
scale,
self.
_img_show.
crop_height /
self.
_img_show.
scale,
0,
0,
self.
_img_show.
crop_width,
self.
_img_show.
crop_height);
//初始化实际存储
self.
_save.
left =
0;
self.
_save.
top =
0;
self.
_save.
width =
self.
_img_show.
crop_width /
self.
_img_show.
scale;
self.
_save.
height =
self.
_img_show.
crop_height /
self.
_img_show.
scale;
self.
upCanvasEvent();
},
//绑定鼠标按下事件
upCanvasEvent
:
function() {
var
self =
this;
self.
_$canvasUp.
on(
'mousedown',
cavMouseDown);
function
cavMouseDown(
e) {
var
canv =
this;
//获取到按下时,鼠标和元素的相对位置,相对偏差
var
relativeOffset = {
x:
e.
clientX -
$(
canv).
offset().
left,
y:
e.
clientY -
$(
canv).
offset().
top };
$(
document).
on(
'mousemove',
function(
e) {
//阻止移动出图片区域
if (
countPosition().
left >=
self.
_img_show.
width -
self.
_img_show.
crop_width ||
countPosition().
left <=
0)
relativeOffset.
x =
e.
clientX -
$(
canv).
offset().
left;
if (
countPosition().
top >=
self.
_img_show.
height -
self.
_img_show.
crop_height ||
countPosition().
top <=
0)
relativeOffset.
y =
e.
clientY -
$(
canv).
offset().
top;
$(
canv).
css({
left:
countPosition().
left,
top:
countPosition().
top });
//移动上层canvas
//实际存储
self.
_save.
left =
countPosition().
left /
self.
_img_show.
scale;
self.
_save.
top =
countPosition().
top /
self.
_img_show.
scale;
self.
_save.
width =
self.
_img_show.
crop_width /
self.
_img_show.
scale;
self.
_save.
height =
self.
_img_show.
crop_height /
self.
_img_show.
scale;
//重绘剪裁区域
self.
_ctxUp.
drawImage(
self.
_img,
self.
_save.
left,
self.
_save.
top,
self.
_save.
width,
self.
_save.
height,
0,
0,
self.
_img_show.
crop_width,
self.
_img_show.
crop_height
);
//设置缩放按钮位置
self.
resizePosition();
function
countPosition() {
var
left = (
e.
clientX -
relativeOffset.
x) -
self.
_$canvasDown.
offset().
left;
//还要减去父元素到左边窗口的距离
var
top = (
e.
clientY -
relativeOffset.
y) -
self.
_$canvasDown.
offset().
top;
//还要减去父元素到左边窗口的距离
return {
left:
left,
top:
top }
}
});
}
},
addResizeBtn
:
function() {
var
self =
this;
//载入方向按钮
var
$seResize =
self.
setResizePoint(
'se-resize',
self.
_img_show.
crop_width -
self.
_resize_point.
size /
2,
self.
_img_show.
crop_height -
self.
_resize_point.
size /
2);
var
$swResize =
self.
setResizePoint(
'sw-resize', -
self.
_resize_point.
size /
2,
self.
_img_show.
crop_height -
self.
_resize_point.
size /
2);
var
$neResize =
self.
setResizePoint(
'ne-resize',
self.
_img_show.
crop_width -
self.
_resize_point.
size /
2, -
self.
_resize_point.
size /
2);
var
$nwResize =
self.
setResizePoint(
'nw-resize', -
self.
_resize_point.
size /
2, -
self.
_resize_point.
size /
2);
var
$canvas =
$(
'<canvas class="overlay" width="' +
self.
_img_show.
crop_width +
'" height="' +
self.
_img_show.
crop_height +
'"></canvas>');
self.
_$box.
append(
$canvas);
self.
_$canvasUp =
$canvas;
self.
_$box.
append(
$seResize);
self.
_$box.
append(
$swResize);
self.
_$box.
append(
$neResize);
self.
_$box.
append(
$nwResize);
self.
_resize_btn.
$se =
$seResize;
self.
_resize_btn.
$sw =
$swResize;
self.
_resize_btn.
$ne =
$neResize;
self.
_resize_btn.
$nw =
$nwResize;
self.
resizeEvent();
},
//绑定方向按钮事件
resizeEvent
:
function() {
var
self =
this;
$(
'.resize-point').
on(
'mousedown',
function() {
var
pLeft =
$(
this).
position().
left +
self.
_resize_point.
size /
2,
pTop =
$(
this).
position().
top +
self.
_resize_point.
size /
2;
var
upLeft =
self.
_$canvasUp.
position().
left,
upTop =
self.
_$canvasUp.
position().
top;
var
noChangeX,
noChangeY;
if (
upLeft >=
pLeft)
noChangeX = -(
upLeft +
self.
_img_show.
crop_width);
//为负在右
else
noChangeX =
upLeft;
if (
upTop >=
pTop)
noChangeY = -(
upTop +
self.
_img_show.
crop_height);
//为负在下
else
noChangeY =
upTop;
$(
document).
on(
'mousemove',
function(
e) {
if (
noChangeX >=
0) {
self.
_$canvasUp.
css(
"left",
noChangeX)
}
else {
self.
_$canvasUp.
css(
"left",
Math.
abs(
noChangeX) -
self.
_img_show.
crop_width);
}
if (
noChangeY >=
0) {
self.
_$canvasUp.
css(
"top",
noChangeY)
}
else {
self.
_$canvasUp.
css(
"top",
Math.
abs(
noChangeY) -
self.
_img_show.
crop_height);
}
//阻止移动出图片区域
self.
_img_show.
crop_width =
Math.
abs(
Math.
abs(
noChangeX) -
countPosition().
left);
self.
_img_show.
crop_height =
self.
_img_show.
crop_width /
self.
_option.
crop_scale;
if (
noChangeX >=
0 &&
noChangeX +
self.
_img_show.
crop_width >
self.
_img_show.
width) {
self.
_img_show.
crop_width =
self.
_img_show.
width -
noChangeX;
self.
_img_show.
crop_height =
self.
_img_show.
crop_width /
self.
_option.
crop_scale;
}
else
if (
noChangeX <
0 &&
Math.
abs(
noChangeX) -
self.
_img_show.
crop_width <
0) {
self.
_img_show.
crop_width =
Math.
abs(
noChangeX);
self.
_img_show.
crop_height =
self.
_img_show.
crop_width /
self.
_option.
crop_scale;
}
if (
noChangeY >=
0 &&
noChangeY +
self.
_img_show.
crop_height >
self.
_img_show.
height) {
self.
_img_show.
crop_height =
self.
_img_show.
height -
noChangeY;
self.
_img_show.
crop_width =
self.
_img_show.
crop_height *
self.
_option.
crop_scale;
}
else
if (
noChangeY <
0 &&
Math.
abs(
noChangeY) -
self.
_img_show.
crop_height <
0) {
self.
_img_show.
crop_height =
Math.
abs(
noChangeY);
self.
_img_show.
crop_width =
self.
_img_show.
crop_height *
self.
_option.
crop_scale;
}
//如果宽高小于限制
if (
self.
_img_show.
crop_width <
self.
_img_show.
min_width) {
self.
_img_show.
crop_width =
self.
_img_show.
min_width;
self.
_img_show.
crop_height =
self.
_img_show.
crop_width /
self.
_option.
crop_scale;
}
if (
self.
_img_show.
crop_height <
self.
_img_show.
min_height) {
self.
_img_show.
crop_height =
self.
_img_show.
min_height;
self.
_img_show.
crop_width =
self.
_img_show.
crop_height /
self.
_option.
crop_scale;
}
//实际存储
if (
noChangeX >=
0) {
self.
_save.
left =
noChangeX /
self.
_img_show.
scale;
}
else {
self.
_save.
left = (
Math.
abs(
noChangeX) -
self.
_img_show.
crop_width) /
self.
_img_show.
scale;
}
if (
noChangeY >=
0) {
self.
_save.
top =
noChangeY /
self.
_img_show.
scale;
}
else {
self.
_save.
top = (
Math.
abs(
noChangeY) -
self.
_img_show.
crop_height) /
self.
_img_show.
scale;
}
self.
_save.
width =
self.
_img_show.
crop_width /
self.
_img_show.
scale;
self.
_save.
height =
self.
_img_show.
crop_height /
self.
_img_show.
scale;
//重绘剪裁区域,修改属性宽高,否则无效
self.
_$canvasUp.
attr(
"width",
self.
_img_show.
crop_width);
self.
_$canvasUp.
attr(
"height",
self.
_img_show.
crop_height);
self.
_ctxUp.
drawImage(
self.
_img,
self.
_save.
left,
self.
_save.
top,
self.
_save.
width,
self.
_save.
height,
0,
0,
self.
_img_show.
crop_width,
self.
_img_show.
crop_height
);
self.
resizePosition();
function
countPosition() {
//鼠标在底层canvas的相对位置
var
left =
e.
clientX -
self.
_$canvasDown.
offset().
left;
var
top =
e.
clientY -
self.
_$canvasDown.
offset().
top;
return {
left:
left,
top:
top }
}
});
});
},
resizePosition
:
function() {
var
self =
this;
self.
_resize_btn.
$se.
css({
left:
self.
_$canvasUp.
position().
left +
self.
_img_show.
crop_width -
self.
_resize_point.
size /
2,
top:
self.
_$canvasUp.
position().
top +
self.
_img_show.
crop_height -
self.
_resize_point.
size /
2 });
//加上宽高,减去本身大小
self.
_resize_btn.
$sw.
css({
left:
self.
_$canvasUp.
position().
left -
self.
_resize_point.
size /
2,
top:
self.
_$canvasUp.
position().
top +
self.
_img_show.
crop_height -
self.
_resize_point.
size /
2 });
//加上宽高,减去本身大小
self.
_resize_btn.
$ne.
css({
left:
self.
_$canvasUp.
position().
left +
self.
_img_show.
crop_width -
self.
_resize_point.
size /
2,
top:
self.
_$canvasUp.
position().
top -
self.
_resize_point.
size /
2 });
//加上宽高,减去本身大小
self.
_resize_btn.
$nw.
css({
left:
self.
_$canvasUp.
position().
left -
self.
_resize_point.
size /
2,
top:
self.
_$canvasUp.
position().
top -
self.
_resize_point.
size /
2 });
//加上宽高,减去本身大小
},
parseInt
:
function() {
this.
_save.
width =
parseInt(
this.
_save.
width);
this.
_save.
height =
parseInt(
this.
_save.
height);
this.
_save.
top =
parseInt(
this.
_save.
top);
this.
_save.
left =
parseInt(
this.
_save.
left);
},
//保存
save
:
function() {
this.
parseInt();
//取整,避免出现杂边线条
var
self =
this;
var
$result =
$(
"<canvas width='" +
self.
_save.
width +
"' height='" +
self.
_save.
height +
"'></canvas>");
$(
'body').
append(
$result);
$result[
0].
getContext(
'2d').
drawImage(
self.
_img,
self.
_save.
left,
self.
_save.
top,
self.
_save.
width,
self.
_save.
height,
0,
0,
self.
_save.
width,
self.
_save.
height
);
var
base64Url =
$result[
0].
toDataURL(
'image/jpeg');
saveCallBack &&
saveCallBack(
base64Url);
return
base64Url;
},
//显示的图片大小,三种结果,撑满宽或者高,或者原图大小
setShowImg
:
function() {
if (
this.
_img.
width <=
this.
_option.
crop_box_width &&
this.
_img.
height <=
this.
_option.
crop_box_height) {
this.
_img_show.
width =
this.
_img.
width;
this.
_img_show.
height =
this.
_img.
height;
return;
}
var
weight =
0;
//设置权重
if (
this.
_img.
width >
this.
_option.
crop_box_width)
weight +=
10;
if (
this.
_img.
height >
this.
_option.
crop_box_height)
weight -=
10;
if (
this.
_img.
width /
this.
_img.
height >
this.
_option.
crop_box_width /
this.
_option.
crop_box_height)
weight +=
5;
else
weight -=
5;
if (
this.
_img.
width >=
this.
_img.
height)
weight++;
else
weight--;
if (
weight >
0) {
//撑满宽度
this.
_img_show.
width =
this.
_option.
crop_box_width;
this.
_img_show.
height =
this.
_option.
crop_box_width / (
this.
_img.
width /
this.
_img.
height);
}
else {
//撑满高度
this.
_img_show.
height =
this.
_option.
crop_box_height;
this.
_img_show.
width =
this.
_option.
crop_box_height / (
this.
_img.
height /
this.
_img.
width);
}
},
resizeCrop
:
function(
real) {
//剪裁框大小
this.
_img_show.
crop_width =
real.
width *
this.
_img_show.
scale;
this.
_img_show.
crop_height =
real.
height *
this.
_img_show.
scale;
}
}
这段代码确实可行,首次发文,不喜勿喷,交流讨论请添加微信:17312678391。