100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 手机移动端-纯js浏览器h5调用摄像头扫描识别解析 条形码+二维码

手机移动端-纯js浏览器h5调用摄像头扫描识别解析 条形码+二维码

时间:2021-08-22 20:07:45

相关推荐

手机移动端-纯js浏览器h5调用摄像头扫描识别解析 条形码+二维码

一、场景

手机移动端-原生js 浏览器h5解决识别二维码条形码功能;

不借助Hbuilder.需要自己打包成APP,比如用Hbuilder打包,浏览器端项目h5无打包成app部署X不采用

不借助微信扫一扫,调用微信js-jdk有多麻烦,还要认证服务号,也不适用其它浏览器打开X不采用

二、思路

1.思路一:input(相机拍照)+条形码或二维码识别js支持库

通过h5-input[camera]调用相机进行拍照成图片,通过条形码等识别库解析出数据;

<input @change="toQR" type="file" accept="image/*" capture="camera">

1-1.方案一:input+ Quagga识别库,success,可识别 条形码,不能识别二维码;

quagga库地址/package/quagga

npm install quagga --save

1-2.方案二:input+jsqr识别库,success,可识别条形码,也可识别二维码,但二维码识别很局限性,如果只做条形码识别可采用,若是识别二维码不适用;

jsqr库地址/package/jsqr

npm install jsqr --save

例: 1.正方形不带其它无效内容只二维码的图片,设置jsqr识别长宽 100*100 ,可成功识别

2.长方形带其它无效内容,比如拍照出来的二维码图片,设置jsqr识别长宽自适(传入图片的长宽或100*100),都识别失败

1-3.方案三: input+qrcode库,失败

qrcode.decode(img)

2.思路二:调用摄像头(video动态识别)+条形码或二维码识别js支持库

调用手机原生摄像头 动态识别用相关支持js库 解析 二维码条形码

2-1.方案四:video+zxing识别库,success,可识别条形码可识别二维码,完美解决,楼主采用的这种;

zxing-js/library库地址/zxing-js/library

npm install @zxing/library --save

三、实例

1-1.方案一

vue-demo

<template><div class="mt46 input-cells"><div class="flex a-center f-fl"><div>车架号</div><input v-model="queryParams.vin" class="cell-input ml5 mr10" type="text"placeholder="请输入或扫描拍照" /></div><div class="flex l-center a-left"><div class="qr-item mr5 ml5"><!--图标自用 / --> <!--<i class="iconfont icon-qr f18 c-ffaa09"></i>--><img src="#" width="20" height="20" alt=""><input v-if="isUploadBarCode" class="qr-item-input" @change="toQR" type="file" accept="image/*" capture="camera"></div></div></div></template><style scoped>.input-cells{display: flex;justify-content:space-between;align-items: center;position: relative;background-color: #fff;overflow: hidden;padding: .06rem .15rem;height: .32rem;line-height: .32rem;font-size: .14rem;}.input-label{margin-left: 0;font-size: .14rem;width: .9rem;}.input-cells>input{font-size: .14rem;text-align: right;}.input-cells>img{width: .06rem;height: .1rem;margin-right: .03rem;}.qr-item{width: .3rem;height: 100%;background-size: 120%;position: relative;overflow: hidden;border: 1px solid #dae7f6;background-color: #f5f5f5;}.qr-item-input{opacity: 0;width: 100%;height: 100%;background-size: 100%;position: absolute;top: 0;left: 0;}/*common*/.flex{display: flex;}.a-center{align-items: center;}.f-fl{float: left;}.ml5{margin-left: .05rem;}.mr10{margin-right: .1rem;}</style>

es6引入使用

import Quagga from 'quagga'

使用

<script type="text/ecmascript-6">import Quagga from 'quagga'export default {name: '',data() {return {queryParams: {vin: null},isUploadBarCode: true, // 控制销毁}},mounted() {},methods: {// 图片 识别 条形码toQR(e) {const that = thisconst file0 = e.target.files[0]// console.log('toQR()-file0', file0)this.isUploadBarCode = falseQuagga.decodeSingle({inputStream: {name : 'image',type : 'ImageStream',// size: 1600, // 这里指定图片的大小,需要自己测试一下singleChannel: false,},locator: {patchSize: 'medium',halfSample: false},numOfWorkers: 1,decoder: { // ean_reader 这里指定ean条形码,就是国际13位的条形码 code39 code_128readers: ['code_128_reader']},// readers: ['code_128_reader'],locate: true,src: URL.createObjectURL(file0)},(result) => {console.log('Quagga()-result', result)// let code = result.codeResult.codeif (result && result.codeResult) {that.queryParams.vin = result.codeResult.code// 执行 页面请求刷新} else {that.queryParams.vin = nullconsole.warn('识别失败,请手动输入')}this.isUploadBarCode = true})},}}</script>

1-2.方案二

方案二html+css公用与方案一

qrcodeSearch.js

// import QRCode from '../libs/qr/qrcode'import jsqr from 'jsqr'// 二维码 或 条形码 识别export function showQrCode(file, params, callback) {const ready = new FileReader()/* 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/ready.readAsDataURL(file) // 调用reader.readAsDataURL()方法,把图片转成base64ready.onload = function() {const re = this.resultcanvasDataURL(re, params, callback)}}function canvasDataURL(path, obj, callback) {const img = new Image()img.src = path// 生成canvasconst canvas = document.createElement('canvas')// const canvas = document.getElementById('qrcanvas')const ctx = canvas.getContext('2d')// const _this = thisimg.onload = function() {console.log('canvasDataURL()-img', img.height, img.width)// let w = img.width// let h = img.heightconst w = 100const h = 100ctx.clearRect(0, 0, w, h)ctx.drawImage(img, 0, 0, w, h);const imageData = ctx.getImageData(0, 0, w, h);const code = jsqr(imageData.data, w, h);const res = {data: null,message: '识别成功',code: 0,}if(code){res.data = code.datacallback(res)}else{res.code = -1res.data = nullres.message = '识别失败'callback(res)}}}

使用

<script type="text/ecmascript-6">import * as QrCode from './qrcodeSearch'export default {name: '',data() {return {queryParams: {vin: null},isUploadBarCode: true, // 控制销毁}},mounted() {},methods: {// 图片 识别 条形码toQR(e) {const that = thisconst file0 = e.target.files[0]// console.log('toQR()-file0', file0)this.isUploadBarCode = falseQrCode.showQrCode(file0, {}, function (res) {this.isUploadBarCode = trueconsole.log('showQrCode()-res', res)if (res.code === 0) {that.queryParams.vin = res.data} else {console.warn('识别失败,请手动输入')}})},}}</script>

2-1.方案四

注意,因为调用原生摄像头要在https环境下,故需要把代码发布到带域名(https)的测试环境进行调试【这是必要的前提条件,没有测试环境就不要整了】。故而代码调整要反复发布构建代码,不过楼主的这个例子已经是整好了的;

vue-demo

<template><div class="page bgc-f4f4f4"><!--路由返回--><!--<lisa-header title="扫描二维码"></lisa-header>--><video ref="video" id="video" class="video vjs-fluid" autoplay></video><div v-show="tipShow" class="tip">{{tipMsg}}</div></div></template><style scoped>/*vjs-fluid 自适video 长宽*/.video{/*border: 1px solid gray;*/margin-top: .5rem;/*width: 2.6rem;*//*height: 3rem;*/}.tip{color: white;font-size: .16rem;}/* common */.bgc-f4f4f4{background-color: #363636;}.page{overflow-y: auto;position: relative;}</style>

使用

<script type="text/ecmascript-6">import { MessageBox } from 'mint-ui'import { BrowserMultiFormatReader } from '@zxing/library'export default {name: 'qr-code-search',components: {},data() {return {loadingShow: false,codeReader: new BrowserMultiFormatReader(),textContent: null,vin: null,tipMsg: '正在尝试识别....',tipShow: false}},created() {// this.tipShow = truethis.openScan()},methods: {async openScan() {const that = thisthat.codeReader.getVideoInputDevices().then((videoInputDevices) => {that.tipShow = truethat.tipMsg = '正在调用后置摄像头...'console.log('videoInputDevices', videoInputDevices);// 默认获取第一个摄像头设备idlet firstDeviceId = videoInputDevices[0].deviceId;// 获取第一个摄像头设备的名称const videoInputDeviceslablestr = JSON.stringify(videoInputDevices[0].label);if (videoInputDevices.length > 1) {// 判断是否后置摄像头if (videoInputDeviceslablestr.indexOf('back') > -1) {firstDeviceId = videoInputDevices[0].deviceId;} else {firstDeviceId = videoInputDevices[1].deviceId;}}that.decodeFromInputVideoFunc(firstDeviceId)}).catch((err) => {that.tipShow = falseconsole.error(err);});},async openScanTwo() {const that = this// codeReader.reset() // 重置// that.textContent = null // 重置that.codeReader = await new BrowserMultiFormatReader()that.codeReader.getVideoInputDevices().then((videoInputDevices) => {that.tipShow = truethat.tipMsg = '正在调用后置摄像头...'console.log('videoInputDevices', videoInputDevices);// 默认获取第一个摄像头设备idlet firstDeviceId = videoInputDevices[0].deviceId;// 获取第一个摄像头设备的名称const videoInputDeviceslablestr = JSON.stringify(videoInputDevices[0].label);if (videoInputDevices.length > 1) {// 判断是否后置摄像头if (videoInputDeviceslablestr.indexOf('back') > -1) {firstDeviceId = videoInputDevices[0].deviceId;} else {firstDeviceId = videoInputDevices[1].deviceId;}}that.decodeFromInputVideoFunc(firstDeviceId)}).catch((err) => {that.tipShow = falseconsole.error(err);});},decodeFromInputVideoFunc(firstDeviceId) {const that = thisthat.codeReader.reset() // 重置that.textContent = null // 重置that.codeReader.decodeFromInputVideoDeviceContinuously(firstDeviceId, 'video', (result, err) => {that.tipMsg = '正在尝试识别...'// let nowContent = nullthat.textContent = nullif (result) {console.log(result);that.textContent = result.text;if (that.textContent) {that.tipShow = falsethat.msgBoxFunc(that.textContent)}}if (err && !(err)) {that.tipMsg = '识别失败'setTimeout(() => {that.tipShow = false},2000)console.error(err);}});},// that.$createDialog 是 cube-ui滴滴 messageBox ,到这一步 二维码值已出,这里是可有可无的代码块,看各自项目ui使用情况 自行替换 messageBoxmsgBoxFunc(textContent) {const that = this// alert('8执行了 msgBoxFunc(),textContent:' + textContent)// cube-ui messageBoxthat.$createDialog({type: 'prompt',// icon: 'cubeic-alert',title: '识别内容',// content: that.textContent,prompt: {value: textContent,placeholder: '请输入'},confirmBtn: {text: '确定内容',active: true,disabled: false,href: 'javascript:;'},cancelBtn: {text: '继续识别',active: false,disabled: false,href: 'javascript:;'},onConfirm: (e, promptValue) => {// that.hide()console.log('onConfirm: ()')that.vin = promptValue},onCancel: () => {console.log('onCancel: ()')that.$nextTick(()=>{that.openScanTwo()})}}).show()},// msgBoxFunc2() 整块代码是mint-ui messageBox示例用,此处未使用,可直接注释;msgBoxFunc2(textContent) {// mint-ui messageBox 有重复 inputValue值问题,新调用 显示是旧的值const that = this// alert('8执行了 msgBoxFunc(),textContent:' + textContent)MessageBox.prompt('识别内容', {inputValidator: (val) => {if (val === null) {return true;//初始化的值为null,不做处理的话,刚打开MessageBox就会校验出错,影响用户体验}},confirmButtonText: '确定内容',cancelButtonText: '继续识别',inputValue: textContent,}).then(({value, action}) => {if (action === 'confirm') {that.vin = value}if (action === 'cancel') {that.$nextTick(()=>{that.openScanTwo()})}}).catch(err => {console.log(err);})}}}</script>

四、尾结

道路过程是曲折坎坷的,结果是良好的,以为整不出来的然后柳暗花明;

参考文章:

/p/30a34157c7d1 zing-js/library

/aoshilang2249/article/details/105222706 MediaDevices.getUserMedia undefined 的问题

/yingzhi3104/article/details/105557591quagga识别条形码图片

/qq_37705048/article/details/79816438qrcode.js的识别

/haiyang5233233/article/details/105874129调用摄像头是提示navigator.mediaDevices.getUserMedia

/weixin_30260399/article/details/96458034调用后置摄像头问题

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。