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等)

浙公网安备 33010602011771号