实现理念
2000毫秒截取一张摄像头当前录到数据转换base64给服务器发过去 服务器通过解码base64后保存文件到本地之后使用qrcode-reader校验是否为二维码 之后删除文件 给前端相应码中数据 或 提示这不是一个码
使用npm包一览
"jimp": "^0.16.1"
"multer": "^1.4.2"
"qrcode-reader": "^1.0.4"
"body-parser": "^1.19.0"
"express": "^4.17.1"
生成二维码得地址
[草料](https://cli.im/)
布局
<template>
<div class = 'qr-send'>
<video id="video" width="100%" height="100%"></video>
<div class = 'line-wrap'>
<div class = 'line' v-if = 'showLine'></div>
</div>
<canvas width="100%" height="100%" id = 'canvas'></canvas>
<img id = 'images' width = '100%' height = '100%'/>
</div>
</template>
样式
<style>
.line {
width: 80%;
height: 1px;
margin: 0 auto;
box-shadow: 0 2px 3px #0ff,
0 5px 3px #0ff,
0 5px 3px #0ff,
0 5px 3px #0ff,
0 5px 3px #0ff,
0 8px 3px #0ff;
}
.line-wrap {
width: 100%;
position: absolute;
left: 0;
top: 200px;
animation:myfirst 5s infinite;
transition: 2s linear;
}
@keyframes myfirst
{
from {
top: 200px;
}
to {
top: 1200px;
}
}
</style>
打开摄像头
在项目生命周期mounted时启动摄像头
获取屏幕宽高得目的是为canvas和img标签设置宽高达到全屏显示
// 获取屏幕宽高
let height = window.screen.availHeight;
const width = window.screen.availWidth;
const canvas = document.getElementById("canvas");
const images = document.getElementById("images");
// height += 300;
canvas.width = width;
canvas.height = height;
let constraints = {
video: {width, height},
audio: true
};
const tis = this;
navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
var video = document.querySelector('video');
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
tis.showLine = true;
};
}).catch(function(err) { console.log(err.name + ": " + err.message); });
const timer = setInterval (() => {
this.takePhoto(width, height, timer);
}, 2000);
截取图片并上传
// 保存图片到canvas
takePhoto(w, h, timer) {
//获得Canvas对象
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, w, h);
const base64 = canvas.toDataURL("image/png");
// 上传base64
qr_decode({
base64
}).then (res => {
if (res.code === '0000') {
clearInterval(timer);
console.log(res);
}
});
}
后端
1.基础配置
var express = require('express');
var bodyParser = require('body-parser');
const decodeImage = require('jimp').read;
const qrcodeReader = require('qrcode-reader');
var app = express();
const { writeFile, readFile, unlink } = require('fs');
app.use(bodyParser.json({limit: '1mb'}));
app.use(bodyParser.urlencoded({
extended: true
}));
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.all('*', function(req, res, next) {
res.setHeader('Access-Control-Allow-Headers', '*');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
next();
});
const config = {
port: 8808
};
const { port } = config;
var server = app.listen(port, function () {
var host = server.address().address
var port = server.address().port
console.log('\033[42;30m DONE \033[40;32m server open success port::' + port)
});
2.路由
app.post('/file', urlencodedParser, async function (req, res) {
const base64 = req.body.base64.replace(/^data:image\/\w+;base64,/, "");
const path = './update/'+ Date.now() +'.png';
var dataBuffer = Buffer.from(base64, 'base64');
await writeFile(path, dataBuffer, function(err) {
if(err){
console.log(err);
} else {
qr_decode(path, res);
}
});
});
3.解码
function qr_decode (pathName, res) {
readFile(pathName, function(errorWhenReadUploadFile, fileBuffer) {
decodeImage(fileBuffer, function(errorWhenDecodeImage, image) {
let decodeQR = new qrcodeReader();
decodeQR.callback = function(errorWhenDecodeQR, result) {
if (result === undefined) {
removeFile(pathName, res);
} else {
res.send(JSON.stringify({
code: '0000',
msg: '解码成功',
data: result.result
}));
console.log(result);
}
};
decodeQR.decode(image.bitmap);
});
});
}
4.删除文件
function removeFile (pathName, res) {
unlink(pathName, (err) => {
if(err) throw err;
res.send(JSON.stringify({
data: null,
code: "9990",
msg: '不是二维码(没有找到二维码信息)'
}));
});
}