在 MVC.NET 中使用 QuaggaJS
QuaggaJS 是一个 javascript 库,用于扫描条形码,具有完整的功能列表和高度的响应时间。
引言
QuaggaJS 是一个由 Christoph Oberhofer 维护的 javascript 库项目,它允许设备使用其摄像头作为条形码扫描仪,无论是静态图像还是实时图像。尽管此库提供了大量功能,但在本文中,我将重点介绍设备摄像头的实时流以读取条形码图像。
技术统计
浏览器支持(实时流)
可读条形码类型
- EAN
- CODE 128
- CODE 39
- EAN 8
- UPC-A
- UPC-C
- I2of5
- 2of5
- CODE 93
- CODABAR
- 获取 Quagga
首先,一开始很难找到关于 QuaggaJS 的信息。我合作过的大多数其他开发人员都鄙视 Web 条形码阅读器,理由是它们读取速度慢且难以使用。经过一些小的修改后,我发现 Quagga 非常容易使用。如果任何人,包括创建者,想要纠正我,请这样做。
起初,我从网站下载并安装了该库
https://serratus.github.io/quaggaJS
后来我意识到可以通过使用 CDN 更简单地实现,其中提供了 QuaggaJS 库的完整版本和精简版本
https://cdnjs.com/libraries/quagga
包含后,我还为项目布局页面中的 jquery 库使用了 CDN。
使用 QuaggaJS
在我的项目中,我使用 MVC.NET 4.5,其中我的控制器加载我的视图,没有模型。该视图有一个相应的 js 文件,其中包含该页面的所有 javascript。我将在本文中重点介绍此文件。
我决定让这个 QuaggaJS 项目按以下方式运行
- 按下“开始”按钮后,您可以扫描任意数量的条形码。
- 按钮文本将在“开始”和“停止”之间切换。
- 有关上次扫描的条形码的信息放在一个隐藏字段中。
- 停止扫描仪会触发一个 AJAX 调用,以获取有关扫描的条形码的信息。
在下面的代码中,您将看到我正在使用 jQuery 监听 ID 为“btnScan”的按钮的点击事件。此部分控制页面上的所有内容,我的标记页面中没有 JS。
var _scannerIsRunning = false;
$(document).ready(function () {
$("#btnScan").click(function () {
if (_scannerIsRunning) {
_scannerIsRunning = false;
Quagga.stop();
$("#btnScan").text("Start");
$("#scanner-container").hide();
} else {
startScanner();
$("video").attr("width", "100%");
$("#btnScan").text("Stop");
$("#scanner-container").show();
}
});
LoadPage();
});
大部分繁重的工作都是由一个函数完成的。我为我的特定需求配置了我的函数,并注释掉了我没有使用的其他选项。您可以看到下面的第一部分初始化 Quagga 对象,包括“type: ‘LiveStream’”而不是静态图像,以及各种约束,例如纵横比和 facingmode,参考相机朝向。
function startScanner() {
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector('#scanner-container'),
constraints: {
facingMode: "environment",
//"width":{"min":1200,},
//"height":{"min":300},
"aspectRatio": { "min": 1, "max": 100 }
},
},
"locator": { "patchSize": "medium", "halfSample": false },
"numOfWorkers": 1,
初始化程序的第二部分包括扫描频率,用于在一段时间内尝试扫描的次数,以及 numOfWorkers - 据我所知,这是在实时流中尝试定位和读取条形码的线程数。我将我的从 10 减少到 1,并且在我的浏览器(Google Chrome 版本 60.0.3112.113(官方版本)(64 位))中,它似乎运行得更快。初始化程序还包括解码器。下面是我使用的解码器,注释掉的是其他可用的解码器和“debug”选项。
"locator": { "patchSize": "medium", "halfSample": false },
"numOfWorkers": 1,
"frequency": 10,
"decoder": { "readers": [{ "format": "code_39_reader", "config": {} }] },
"locate": true,
//decoder: {
// readers: [
// "code_128_reader",
// "ean_reader",
// "ean_8_reader",
// "code_39_reader",
// "code_39_vin_reader",
// "codabar_reader",
// "upc_reader",
// "upc_e_reader",
// "i2of5_reader"
// ],
// debug: {
// showCanvas: true,
// showPatches: true,
// showFoundPatches: true,
// showSkeleton: true,
// showLabels: true,
// showPatchLabels: true,
// showRemainingPatchLabels: true,
// boxFromPatches: {
// showTransformed: true,
// showTransformedBox: true,
// showBB: true
// }
// }
//},
startScanner 函数中有另外两个部分,它们处理 QuaggaJS 对象的“onProcessed”和“onDetected”事件。我在网上找到的“onProcessed”示例足够灵活,我不需要更改它们,但是,我确实对“onDetected”处理程序进行了一些更改以满足我的应用程序的特定需求。
正如您在下面看到的,我的 onDetected 处理程序将扫描的代码值加载到隐藏字段中,使用调用 ajax 的函数将信息加载到页面,然后自动单击按钮,如果我希望找到的条形码关闭扫描仪的视图屏幕并切换我的按钮文本。删除它将使应用程序更接近我在开场白中提到的版本。
Quagga.onDetected(function (result) {
console.log("Barcode detected and processed : [" + result.codeResult.code + "]", result);
$("#hdnBarcode").val(result.codeResult.code);
LoadPage();
$("#btnScan").click();
});
正如您所看到的,QuaggaJS 对于此单一目的来说非常易于使用,同时具有多种功能操作,例如扫描静态图像等。我希望这对某人有所帮助,如果您有 QuaggaJS 经验,请随时对此发表评论。
最后
我没有在 CodeProject 中找到任何其他关于 QuaggaJS 的文章,所以我希望这篇文章能帮助其他人实现他们自己的实现。请随时发表评论和贡献,因为我不是 QuaggaJS 专家。 以下是完整的 js 文件。
var _scannerIsRunning = false;
$(document).ready(function () {
$("#btnScan").click(function () {
//alert("try to scan");
if (_scannerIsRunning) {
_scannerIsRunning = false;
Quagga.stop();
$("#btnScan").text("Start");
$("#scanner-container").hide();
} else {
startScanner();
$("video").attr("width", "100%");
$("#btnScan").text("Stop");
$("#scanner-container").show();
}
});
LoadPage();
});
function closeModal() {
$('.modal').hide();
// more cleanup here
}
function startScanner() {
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector('#scanner-container'),
constraints: {
facingMode: "environment",
//"width":{"min":1200,},
//"height":{"min":300},
"aspectRatio": { "min": 1, "max": 100 }
},
},
"locator": { "patchSize": "medium", "halfSample": false },
"numOfWorkers": 1,
"frequency": 10,
"decoder": { "readers": [{ "format": "code_39_reader", "config": {} }] },
"locate": true
}, function (err) {
if (err) {
console.log(err);
return
}
console.log("Initialization finished. Ready to start");
Quagga.start();
// Set flag to is running
_scannerIsRunning = true;
});
Quagga.onProcessed(function (result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
result.boxes.filter(function (box) {
return box !== result.box;
}).forEach(function (box) {
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
}
}
});
Quagga.onDetected(function (result) {
console.log("Barcode detected and processed : [" + result.codeResult.code + "]", result);
$("#hdnBarcode").val(result.codeResult.code);
LoadPage();
$("#btnScan").click();
});
}
function LoadPage()
{
if ($("#hdnBarcode").val() == "")
$("#hdnBarcode").val("1900067611"); //default barcode
$.ajax({
type: 'Get',
url: 'Home/GetData/' + $("#hdnBarcode").val(),
success: function (json) {
//...
}
});
}