使用H5的Canvas,实现证件照的识别
需求:实现证件照上传时,提示用户证件照是否合法。 思路:在用户上传的照片上取三个像素点,判断像素点是否符合证件照的特点 项目中用到了element-plus中的el-upload 控件实现图片的上传,在实现此功能的过程中遇到了一系列的问题: 画布什么时候创建,创建的画布放在哪里…在画布里边拿不到原图的宽高等问题,经过多次尝试都已经解决。 首先创建一个画布(Canvas)
<canvas id="myCanvas" style="opacity: 0;" v-if='1'></canvas>
给存放证件照的img标签绑定id
<el-upload
class="avatar-uploader"
ref='upload'
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:on-change="onChange"
:before-upload="beforeAvatarUpload"
:name='imgname'
style="
margin-top:19px;
width: 109px;
height: 136px;
text-align: center;
border: 2px dashed rgb(181, 181, 181);
text-align:center;
background-color:rgb(250, 250, 250)
"
>
<img :src="imageUrl" class="avatar" style="width:110px;height:136px;" id='scream'>
</el-upload>
这时候,我们需要考虑什么时候在把图片放到画布上比较好, 我这里是在,证件照上传之后,立即在画布上画出图片,在el-upload的onchange回调函数中进行,这样做思路没问题,但是onchange的调用时机(文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用),对此过程有影响,我们再添加文件时候已经调用了一次,这时候img里边还没有放东西,所以会报错。 解决这个问题: 我们可以使用一张图片来占用,我们提示用户的图标。(我这里一开始就给imageUrl绑定图片) 继续刚才的思路:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById('scream')
img.onload = function() {
var imgW= img.offsetWidth
var imgH= img.clientHeight
ctx.drawImage(img,0,0,imgW,imgH,0,0,imgW,imgH);
}
使用context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 剪切证件照, 各参数的含义: img 规定要使用的图像、画布或视频。 sx 可选。开始剪切的 x 坐标位置。 sy 可选。开始剪切的 y 坐标位置。 swidth 可选。被剪切图像的宽度。 sheight 可选。被剪切图像的高度。 x 在画布上放置图像的 x 坐标位置。 y 在画布上放置图像的 y 坐标位置。 width 可选。要使用的图像的宽度(伸展或缩小图像)。 height 可选。要使用的图像的高度(伸展或缩小图像)。 (参考菜鸟教程) 这样处理看起来没问题,但是当我们接下来去取像素点的时候会发现,拿到的像素点并不是我们想要到,看一下img标签里边对图片的限制,显然,为了让图片在在页面上显示的更加美观,给用户一种良好的体验,我们需要对用户上传的大小不一的图片做一下限制,所以画布上画的并不是用户上传的图片。 为了拿到原图,解决思路: 可以在定义一个和el-upload绑定相同URL的img标,把它画到画布里:
<img :src="imageUrl" class="avatar" id='scream1' style="opacity: 0;" >
接下来就只要拿到画布三个我们想要的像素点,就能解决问题了, 要求用户上传蓝底的证件照,我取的是左上角,右上角 和中间 三个点:
ctx.drawImage(img,0,0,imgW,imgH,0,0,imgW,imgH);
var rgb=ctx.getImageData(10,10,1,1).data;
var rgb2=ctx.getImageData(imgW-10,10,1,1).data;
var rgb3=ctx.getImageData(imgW/2+10,imgH/2-10,1,1).data;
接下来就是判断这三个点是否符合要求了, 我是去每个点的rgb进行判断的,像素点颜色的范围,需要你自己去找你想要的的范围 onchange 里边的关键代码:
onChange(file,fileList){
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById('scream1')
var that=this
img.onload = function() {
var imgW= img.offsetWidth
var imgH= img.clientHeight
ctx.drawImage(img,0,0,imgW,imgH,0,0,imgW,imgH);
var rgb=ctx.getImageData(10,10,1,1).data;
var rgb2=ctx.getImageData(imgW-10,10,1,1).data;
var rgb3=ctx.getImageData(imgW/2+10,imgH/2-10,1,1).data;
var rdata=rgb[0]
var gdata=rgb[1]
var bdata=rgb[2]
var rdata2=rgb2[0]
var gdata2=rgb2[1]
var bdata2=rgb2[2]
var rdata3=rgb3[0]
var gdata3=rgb3[1]
var bdata3=rgb3[2]
if( 0<=rdata && rdata<=79 &&
0 <= gdata && gdata <=218
&&240 <=bdata && bdata<=255
&& 0<=rdata2 && rdata2<=79
&& 0<=gdata2 && gdata2<=218
&&240<=bdata2 && bdata2<=255
&&173<=rdata3 && rdata3<=244
&& 180<=gdata3 && gdata3<=215&&
150<=bdata3 && bdata3<=187){
this.abnrmal=0
window.localStorage.setItem('abnrmal',this.abnrmal)
}else{
this.abnrmal=1
window.localStorage.setItem('abnrmal',this.abnrmal)
that.$message.error('请上传蓝底的证件照')
}
}
},
最后还有一个问题,就是千万不要有强迫症!!如果你一开始就把在画布组件上使用了,v-if / v-show 让图片不显示在页面上,那么就没办法进行了。 我们一开始随便在页面上操作,让这些东西消失在用户的视角,只需要最后,设置一下没用标签/组件的透明度(opacity)
<canvas id="myCanvas" style="opacity: 0;" ></canvas>
<img :src="imageUrl" class="avatar" id='scream1' style="opacity: 0;" >
效果截图
|