Html5QRCode扫描条形码+二维码+5秒没扫出后截图以文件扫描
目的:使用html2canvas画布去截取下来的图片,然后去尝试解析其图片用来识别条形码和二维码
代码:
<html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>scan</title> <style> button { display: block; width: 100%; margin: 6px; outline: none; height: 40px; line-height: 40px; color: #fff; background-color: #26a2ff; text-align: center; border-radius: 4px; border: none; cursor: pointer; } #qr-input-file { opacity: 0; filter: alpha(opacity=0); display: inline-block; width: 100%; height: 100%; } #upload-text { position: relative; bottom: 40px; user-select: none; } </style> <script src="~/easyui/jquery.min.js"></script> <script src="~/scan/html5-qrcode.min.js"></script> <script src="~/scan/html2canvas.min.js"></script> </head> <body> <div id="tempDiv"></div> <button id="num">0</button> <button id="refresh">刷新</button> <button id="scan">使用相机扫一扫方式</button> <button id="useLocal"> <input type="file" id="qr-input-file" accept="image/*" value="使用文件方式"> <span id="upload-text">使用文件方式</span> </button> <H3 id="readResult"></H3> <div id="reader" width="600px"></div> <canvas id="canvas" @*width="250" height="250"*@></canvas> <div id="imgDiv" style="width:250px;height:200px;"></div> </body> <script> function onScanSuccess(decodedText, decodedResult) { $('#readResult').html(decodedText + ":" + decodedResult); } function onScanFailure(error) { $('#readResult').html(error); } var num = 0; var trice = 0; var intervalSecond; function AddSecond() { if (trice == 0) { trice ++; intervalSecond = setInterval(function () { num++; $('#num').html(num); }, 1000); // 1000毫秒后执行 } } function SubPicToCode(html5QrCode) { //开始截图模拟文件识别 clearInterval(intervalSecond); const video = document.querySelector('video'); //const canvas2 = $('#canvas')[0]; //const context = canvas.getContext('2d'); const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); var canvasWidth = $('video').width(); var canvasHeight = $('video').height(); $('#canvas').css('width', canvasWidth); $('#canvas').css('height', canvasHeight); //从视频流中取帧并绘制到canvas上 context.drawImage(video, 0, 0, canvas.width, canvas.height); //关闭摄像头 html5QrCode.stop().then((ignore) => { // QR Code scanning is stopped. }).catch((err) => { // Stop failed, handle it. }); convert_elements_to_image_and_download(html5QrCode,["#canvas"]); } function Clear() { num = 0; trice = 0; $('#num').html(num); $('#imgDiv').html(''); $('#canvas').width(0); $('#canvas').height(0); clearInterval(intervalSecond); } $(function () { $('#refresh').click(function () { location.reload(); }); $('#scan').click(function () { $('#readResult').html(""); Clear(); const html5QrCode = new Html5Qrcode("reader"); const qrCodeSuccessCallback = (decodedText, decodedResult) => { /* handle success */ $('#readResult').html("扫描成功:" + decodedText); //关闭摄像头 html5QrCode.stop().then((ignore) => { // QR Code scanning is stopped. }).catch((err) => { // Stop failed, handle it. }); }; const qrCodeFailCallback = (error) => { /* handle Fail */ $('#readResult').html("扫描失败:" + error); if (num == 0) AddSecond(); else if (num >= 5) SubPicToCode(html5QrCode); //关闭摄像头 //html5QrCode.stop().then((ignore) => { // // QR Code scanning is stopped. //}).catch((err) => { // // Stop failed, handle it. //}); }; const config = { fps: 10, qrbox: { width: 250, height: 250 } }; // If you want to prefer front camera //html5QrCode.start({ facingMode: "user" }, config, qrCodeSuccessCallback); // If you want to prefer back camera html5QrCode.start({ facingMode: "environment" }, config, qrCodeSuccessCallback, qrCodeFailCallback) .catch((err) => { $('#readResult').html("扫描异常:" + err); //关闭摄像头 html5QrCode.stop().then((ignore) => { // QR Code scanning is stopped. }).catch((err) => { // Stop failed, handle it. }); }); // Select front camera or fail with `OverconstrainedError`. //html5QrCode.start({ facingMode: { exact: "user"} }, config, qrCodeSuccessCallback); // Select back camera or fail with `OverconstrainedError`. //html5QrCode.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback); }) //选择文件扫描 $('#qr-input-file').change(function (e) { $('#readResult').html(""); Clear(); const html5QrCode = new Html5Qrcode("reader"); if (e.target.files.length == 0) { // No file selected, ignore return; } const imageFile = e.target.files[0]; // Scan QR Code html5QrCode.scanFile(imageFile, true) .then(decodedText => { // success, use decodedText //console.log(decodedText); $('#readResult').html(decodedText); $('#qr-input-file').val(''); }) .catch(err => { // failure, handle it. console.log(`Error scanning file. Reason: ${err}`) $('#readResult').html("扫描错误:" + err); }); }); }) //截图 async function convert_elements_to_image_and_download(html5QrCode,array_ele_selectors, is_vertical = true) { // 元素img data保存列表 let array_ele_img_datas = new Array(); // 元素img 宽度保存列表 let array_ele_img_widths = new Array(); // 元素img 高度保存列表 let array_ele_img_heights = new Array(); for (let i = 0; i < array_ele_selectors.length; i++) { let selector = document.querySelector(array_ele_selectors[i]); array_ele_img_datas.push(await generate_img_data(selector)); array_ele_img_widths.push(get_ele_width(selector)); array_ele_img_heights.push(get_ele_height(selector)); } let img_data = null; if (is_vertical) { //垂直排列合并元素图片 img_data = await vertical_merge_elements_pic( array_ele_img_datas, array_ele_img_widths, array_ele_img_heights); } else { console.log("Not support yet!"); return false; } //show_picture(img_data); var imgObject = new Image(); imgObject.src = img_data; //call the methods that will create a 64-bit version of thumbnail here. var canvasWidth = $('#canvas').width(); var canvasHeight = $('#canvas').height(); var x = (canvasWidth - 250) / 2; var y = (canvasHeight - 250) / 2; SubPointPic(html5QrCode,x,y,250,250); } function SubPointPic(html5QrCode,xOffset, yOffset, width, height) { const targetElement = document.querySelector("#canvas"); //截取指定坐标图片 html2canvas(targetElement, { x: xOffset, y: yOffset, width: width, height: height, }).then((canvas) => { // 获取canvas图像数据 const imageData = canvas.toDataURL("image/jpeg"); // 进一步处理图像数据 //place image in appropriate div document.getElementById("imgDiv").innerHTML = '<img id="imgCan" alt="" src="' + imageData + '" />'; Base64ToCode(html5QrCode,imageData, "123.png"); }); } //base64转File function Base64ToCode(html5QrCode, base64String, fileName) { const arr = base64String.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } const imageFile = new File([u8arr], fileName, { type: mime }); // Scan QR Code //const html5QrCode = new Html5Qrcode("reader"); html5QrCode.scanFile(imageFile, true) .then(decodedText => { // success, use decodedText //console.log(decodedText); alert("图片解析的"); $('#readResult').html(decodedText); //$('#qr-input-file').val(''); }) .catch(err => { // failure, handle it. console.log(`Error scanning file. Reason: ${err}`) $('#readResult').html("扫描错误:" + err); }); } async function vertical_merge_elements_pic(array_ele_img_datas, array_ele_img_widths, array_ele_img_heights) { // 垂直方向合并各个元素图片 let total_height = 0; let max_width = 0; for (let i = 0; i < array_ele_img_datas.length; i++) { total_height += array_ele_img_heights[i]; if (max_width < array_ele_img_widths[i]) { max_width = array_ele_img_widths[i]; } } // 创建canvas元素 var canvas = document.createElement('canvas'); // 设置canvas的宽高 canvas.width = max_width; canvas.height = total_height; // 获取canvas的2D绘图上下文 var ctx = canvas.getContext('2d'); //在canvas上绘制图片 let already_have_height = 0; for (var j = 0; j < array_ele_img_datas.length; j++) { await new Promise((resolve, reject) => { let tmp_img = new Image(); tmp_img.onload = () => { ctx.drawImage(tmp_img, 0, already_have_height); resolve(); }; tmp_img.onerror = reject; tmp_img.src = array_ele_img_datas[j]; }); already_have_height += array_ele_img_heights[j]; } // 返回合并后的图片 return canvas.toDataURL(); } function get_ele_width(element) { //获取元素宽度 return element.clientWidth; } function get_ele_height(element) { //获取元素高度 return element.clientHeight; } async function generate_img_data(element) { //返回的是图片base64编码 try { // html2canvas是异步执行的 // 使用await关键字等待html2canvas的Promise完成 const canvas = await html2canvas(element); console.log("Canvas generated:", canvas); return canvas.toDataURL(); } catch (error) { console.error('Error generating canvas:', error); } } function show_picture(data_url) { // 创建一个a标签用于下载 const a = document.createElement('img'); a.src = data_url; // 设置下载的文件名 //a.download = 'screenshot.png'; // 触发点击事件 //a.click(); $('#tempDiv').html(a); } function picture_toFile(data_url) { // 创建一个a标签用于下载 const a = document.createElement('input'); a.src = data_url; // 设置下载的文件名 //a.download = 'screenshot.png'; // 触发点击事件 //a.click(); $('#tempDiv').append(a); } function download_picture(data_url) { // 创建一个a标签用于下载 const a = document.createElement('a'); a.href = data_url; // 设置下载的文件名 a.download = 'screenshot.png'; // 触发点击事件 a.click(); } //File转base64 function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (event) => { resolve(event.target.result); }; reader.onerror = reject; reader.readAsDataURL(file); // 读取文件为DataURL }); } //base64转File function base64ToFile(base64String, fileName) { const arr = base64String.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], fileName, { type: mime }); } </script> </html>
结论:效果不理想,预计还需要对截取的图片进行数据流分析,进而对文件清晰度的还原。(OpenCV等)