HTML 5 手机扫描二维码登陆网页
首先声明我不是专业做前端的,只是一个java开发者,最近要做一个手机版的网站,但是需求要做类似于微信,扫描网页上的二维码登陆网页版微信,以当时认为这东西必须要APP才能支持,因为所有扫描二维码都是必须在手机上安装APP,也看过phonegap,其实也是需要生成一个apk,需要用户安装。所以就是硬着头皮在网上找资料。最后终于看到说HTML5可以调用视频,灵光一现。继续搜索。这时候才发现原来HTML5原来真的可以实现,
我先介绍一下它的大概处理流程(个人理解),其实大概思路就是通过调用手机端的摄像头将视频放入video中,然后将视频中的某一帧放入canvas中,canvas将图片信息转换换成base64码,把base64码传到后台转换成数据流,用java解析就行了。
下面就上代码了(调试的时候才发现手机浏览器中只有欧朋浏览器支持,而且版本是operaclassic的才行):
1、首先就是页面了
<!DOCTYPEHTML>
<html>
<head>
<metaname="viewport"content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<title>扫描二维码</title>
<scripttype="text/javascript">
varvideo,canvas;
window.addEventListener('DOMContentLoaded',function(){
'usestrict';
//调取摄像头
navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;
window.URL=window.URL||window.webkitURL||window.mozURL||window.msURL;
if(navigator.getUserMedia){
navigator.getUserMedia({video:true},gotStream,noStream);
video=$("#video").get(0);
canvas=$("#canvas").get(0);
//启动摄像头成功之后开始获取二维码
scanCode();
}else{
console.log('Nativewebcamerastreaming(getUserMedia)notsupportedinthisbrowser.');
}
//调取摄像头成功的回调函数
functiongotStream(stream){
if(video.mozSrcObject!==undefined){
video.mozSrcObject=stream;
}else{
video.src=(window.URL&&window.URL.createObjectURL(stream))||stream;
}
video.play();
}
//调取摄像头失败的回调函数
functionnoStream(){
console.error('Anerroroccurred:[CODE'+error.code+']');
}
$("#myVideo").bind("play",function(){
//$("#photo").attr("disabled",false);
});
},false);
//抓取video画面放入canvas
functionphotograph(){
varcontext=canvas.getContext("2d");
//获取抓取图片的区域
//获取取景框其实坐标位置和宽高
varcameraAperture_X=$("#td1").width();
//varcameraAperture_Y=$("#mid_div").height();
varcameraAperture_Y=$("#table_h").offset().top-$(".smtwo").height();
varcameraAperture_W=$("#cameraAperture").width();
varcameraAperture_H=$("#cameraAperture").height();
context.drawImage(video,Math.round(cameraAperture_X/2),Math.round(cameraAperture_Y/2),cameraAperture_W,cameraAperture_H,0,0,cameraAperture_W,cameraAperture_H);
imageConvertToGray(context);
varimgData=canvas.toDataURL("image/png");
$("#code").val(imgData);
}
//将图片处理成黑白的(二维码扫描需要处理黑白色图片,如果仅用于拍照这一步就省略了)
functionimageConvertToGray(ctx){
varlength=canvas.width*canvas.height;
imageData=ctx.getImageData(0,0,canvas.width,canvas.height);
for(vari=0;i<length*4;i+=4){
varmyRed=imageData.data[i];
varmyGreen=imageData.data[i+1];
varmyBlue=imageData.data[i+2];
myGray=parseInt((myRed+myGreen+myBlue)/3);
imageData.data[i]=myGray;
imageData.data[i+1]=myGray;
imageData.data[i+2]=myGray;
}
ctx.putImageData(imageData,0,0);
}
functionscanCode(){
//生成图片的base64码
photograph();
$("#picForm").ajaxSubmit({
url:'${ctx}/xxxx/xxxx.htm',
type:'post',
dataType:'text',
success:function(data){
if(data!=""){//扫描出结果
window.location.href="${ctx}/xxxx/xxxxxxxxxx.htm?data="+data+"&status="+$("#status").val();
//alert("扫描信息为:"+data);
}else{//继续扫描
setTimeout(function(){
scanCode();
},2000);
}
}
});
}
</script>
</head>
<body>
<formid="picForm"action="${ctx}/xxxx/xxxx.htm"method="post">
<inputtype="hidden"value=""id="code"name="code"/>
<inputtype="hidden"value="${status}"id="status"name="status"/>
<sectionclass="smtwo">
<h1><aclass="back"href="${ctx}/index/index.htm"><imgsrc="${ctx}/images/smtwo_1.png"style="border:none"alt=""></a>${titleMsg}</h1>
</section>
<sectionstyle="position:relative;">
<videowidth="100%"id="video"autoplay="autoplay"onclick="photograph();"></video>
<canvaswidth="200"height="200"id="canvas"style="display:none;"></canvas>
<divstyle="position:absolute;top:0;left:0;">
<divclass="smtw_bgbutsmtw"id="mid_div">
${content}
</div>
<tablewidth="100%"border="0"cellpadding="0"cellspacing="0"id="table_h">
<tr>
<tdclass="smtw_bgtd1"id="td1"></td>
<tdclass="td2">
<divclass="smtw_td"style="width:200px;height:200px;"id="cameraAperture"onclick="photograph()">
<spanclass="br1"></span>
<spanclass="br2"></span>
<spanclass="br3"></span>
<spanclass="br4"></span>
</div>
</td>
<tdclass="smtw_bgtd1"></td>
</tr>
</table>
<divclass="smtw_bgbutsmtw"id="bottom_div">
</div>
</div>
</section>
</form>
</body>
</html>
页面说明:
window.addEventListener页面启动的时候调用摄像头,我试过不用这个直接$(document).ready();不好使。
imageConvertToGray():这个函数主要是把照片变成黑白的,这个很重要,因为取得一帧图片是彩色的话就会影响读取二维码的效果(反正我没有处理成黑白之前扫描没成功过)
scanCode():这个就是扫描了,2秒抓一张图片传到后台进行处理如果成功会返回二维码包含内容。
这里需要说明的是canvas.toDataURL("image/png");canva转换成base64必须放到input隐藏变量里面,因为这个字符串很长。不能通过url提交,这样这个字符串长度会超了。
下面着中说取景框的问题,因为微信扫描二维码界面会有一个取景框,所以我们也要模拟这个,也就是说在video中的某一个区域截取图片放到canvas里面,所以在photograph()函数里面,我在context.drawImage的时候计算了需要取景的坐标,关于这个参数大家可以查看canvas属性就可以了解。
下来就是后台java解析了百度一下,到处都是,下面是我用的,置于jar包,大家自己找找哈。
packagesy.util;
importjava.awt.image.BufferedImage;
importjava.io.ByteArrayInputStream;
importjava.io.File;
importjava.io.InputStream;
importjavax.imageio.ImageIO;
importjp.sourceforge.qrcode.QRCodeDecoder;
importsy.bean.TwoDimensionCodeImage;
importDecoder.BASE64Decoder;
publicclassQRCodeDecoderHandlerUtil{
/**
*解析二维码(QRCode)
*@paraminput输入流
*@return
*/
publicstaticStringdecoderQRCode(InputStreaminput)throwsException{
BufferedImagebufImg=null;
Stringcontent=null;
bufImg=ImageIO.read(input);
QRCodeDecoderdecoder=newQRCodeDecoder();
content=newString(decoder.decode(newTwoDimensionCodeImage(bufImg)),"utf-8");
returncontent;
}
/**
*解析二维码(QRCode)
*@paramimgPath图片路径
*@return
*/
publicstaticStringdecoderQRCode(StringimgPath)throwsException{
//QRCode二维码图片的文件
FileimageFile=newFile(imgPath);
BufferedImagebufImg=null;
Stringcontent=null;
bufImg=ImageIO.read(imageFile);
QRCodeDecoderdecoder=newQRCodeDecoder();
content=newString(decoder.decode(newTwoDimensionCodeImage(bufImg)),"utf-8");
returncontent;
}
/**
*解析二维码
*@paramimgStr图片的Base64信息
*@return
*/
publicstaticStringdecoderQRCodeForBase64(StringimgStr)throwsException{
if(imgStr==null){
return"";
}
BASE64Decoderdecoder=newBASE64Decoder();
byte[]b=decoder.decodeBuffer(imgStr);
for(inti=0;i<b.length;++i){
if(b[i]<0){//调整异常数据
b[i]+=256;
}
}
InputStreaminput=newByteArrayInputStream(b);
Stringcontent=decoderQRCode(input);
returncontent;
}
publicstaticvoidmain(String[]args){
}
}
说明:我是借用decoderQRCode(InputStreaminput)方法,因为考虑到,如果用decoderQRCode(StringimgPath)就需要在服务器生成临时图片,这样不仅繁琐,还会产生一些垃圾图片。
decoderQRCodeForBase64这个方法就是将base64(前台取过来的)变成InputStream然后交给decoderQRCode(InputStreaminput)处理
好了OK,置于网页端的二维码里面如何存放信息,这个我想大家根据业务了,具体流程就是手机扫描到二维码里面的信息之后,手机版服务器通知网页版服务器然后网页版服务器登陆并且跳转到相应页面就OK了
第一次发帖,如果说的不明白的还请谅解,如果需要更详细的了解,请加我的QQ号:514772731