最近在做一个项目,要实现用户上传人脸图片给后端,大小和人脸都有一定的要求,需要使用到在web端实现图片裁剪功能,也就是将图片裁剪到对应大小,然后发送给后端。识别这个人的人脸!
于是想了一下要用canvas的drawImage实现这样功能。
原理很简单就是通过放大缩小和移动,确定放大缩小后的图片的宽高和相对截图canvas左边和上边的位置的值,对应使用canvas的api就可以实现。
上代码:
<template>
<div class="cropper" id="cropper"
:style="{width: (cropperWidth + 20) + 'px', height: (cropperHeight + 100) + 'px'}"
>
<div class="box"
@mousedown="boxMousedown($event)"
@mousemove="boxMousemove($event)"
@mouseup="boxMouseup($event)"
:style="{width: cropperWidth + 'px', height: cropperHeight + 'px'}"
>
<canvas id="cropperCan" :width="cropperWidth" :height="cropperHeight" ref="canvas"></canvas>
<img
draggable="false"
:src="imgUrl"
:style="{
height: cpheight + 'px',
width: cpwidth + 'px',
left: cpleft + 'px',
top: cptop + 'px'
}"
ref="phone"
/>
</div>
<div class="contr">
<el-slider v-model="scale" @change="scaleImg"></el-slider>
</div>
<div class="btn">
<el-button type="primary">取消</el-button>
<el-button type="primary" @click="savePic">保存</el-button>
</div>
</div>
</template>
<script>
// import { base64 } from './base64.js';
let orginLeft = 0;
let orginTop = 0;
export default {
data () {
return {
// base64Img: base64,
mouseStartX: 0, // 鼠标按钮的X坐边
mouseStartY: 0, // 鼠标按下的Y坐标
mouseEndX: 0,
mouseEndY: 0,
ismpuseMove: false, // 是否移动标识
scale: 100, // 放大缩小倍数
// cropperHeight: 400, // 画布高度输出的图片大小
// cropperWidth: 400, // 画布宽度输出图片的宽度
height: 700, // 外部计算得出图片的高度尺寸传进来
width: 933, // 外部计算得出图片的宽度尺寸传进来
left: 0,
top: 0
};
},
props: ['cropperHeight', 'cropperWidth', 'imgUrl'],
computed: {
// 计算图片放大缩小的宽度
cpwidth: function () {
let scaleVal = this.scale / 100;
return this.width * scaleVal;
},
// 计算图片放大缩小的高度
cpheight: function () {
let scaleVal = this.scale / 100;
return this.height * scaleVal;
},
// 计算图片移动后的相对截图左边的位置
cpleft: function () {
let scaleVal = 1;
return this.left * scaleVal;
},
// 计算图片移动后的相对截图顶部边的位置
cptop: function () {
let scaleVal = 1;
return this.top * scaleVal;
}
},
beforeCreate () {
},
mounted () {
this.height = this.$refs.phone.getBoundingClientRect().height;
this.width = this.$refs.phone.getBoundingClientRect().width;
},
methods: {
// 鼠标按下
boxMousedown (event) {
this.ismpuseMove = true;
this.mouseStartX = event.clientX;
this.mouseStartY = event.clientY;
orginLeft = this.left;
orginTop = this.top;
},
// 鼠标拖动图片跟着拖动
boxMousemove (event) {
if (this.ismpuseMove) {
let x = event.clientX;
let y = event.clientY;
this.left = orginLeft + (x - this.mouseStartX);
this.top = orginTop + (y - this.mouseStartY);
}
},
// 鼠标点击
boxMouseup (event) {
this.ismpuseMove = false;
this.mouseStartX = 0;
this.mouseStartY = 0;
},
scaleImg (val) {
},
savePic () {
let can = this.$refs.canvas; // canvas对象
let cpImg = new Image();
let sx = this.cpleft;
let sy = this.cptop;
let cwidth = this.cpwidth;
let cheight = this.cpheight;
cpImg.src = this.$refs.phone.src;
cpImg.width = this.cpwidth;
cpImg.height = this.cpheight;
can.getContext('2d').clearRect(0, 0, 478, 500); // 清空画布
can.getContext('2d').drawImage(cpImg, sx, sy, cwidth, cheight); // 绘制画布
let dataURL = can.toDataURL('image/png');
this.$emit('cropperImg', dataURL); // 抛出截图base64对象数据
// 调试预览截图
let preImg = new Image();
preImg.src = dataURL;
document.querySelector('#mainBox').appendChild(preImg);
}
}
};
</script>
<style lang="less" scoped>
#cropper{
padding: 10px;
border:1px solid #ccc;
margin:20px 0 0 600px;
background: #fff;
.box {
position: relative;
height: 500px;
width: 100%;
overflow: hidden;
background: url('./bg.png');
#cropperCan {
position: absolute;
left: 0;
display: none;
height: 500px;
width: 100%;
}
img {
position: relative;
}
}
.contr {
padding: 0 20px;
}
.btn {
text-align: right;
}
}
</style>
最后运行结果:
使用的时候可以直接调用组件:
<cropper
:cropperHeight="400"
:cropperWidth="400"
:imgUrl="img"
@cropperImg="cropperImg"
/>
cropperHeight、cropperWidth代表要裁剪的高和宽,imgUrl为图片的src地址 base64或者URL都可以,cropperImg则为截图保存后抛出的裁剪后的图片base64数据。
结束语:来公司一年了,年后好几个同事都离职了,自己也不知道未来要怎么走,庆幸的是自己发现了自己有很多的不足,最近也完成了一件对自己来说的“大事”,自己也在慢慢地努力中,一直在朝那个优秀的自己努力着。。。。。