QuaggaJS是条形码扫描器完全用JavaScript编写支持实时的本地化和各种类型的条形码,如

EAN, CODE 128,CODE 39,EAN 8,UPC-A ,UPC-C ,I2of5, 2of5,CODE 93和CODABAR.该类库还能够 getUserMedia直接访问用户的相机流,使得我们的开发变得更加简单。

项目地址: https://github.com/serratus/quaggaJS#browser-support

常用API

Quagga.init(config,callback)

该方法初始化给定配置的库config(见下文),并调用callback(err)Quagga完成引导阶段之后。如果配置了实时检测,则初始化过程还要求摄像机访问。如果发生错误,err 则设置参数并包含有关原因的信息。可能的原因可能inputStream.type是设置LiveStream,但浏览器不支持此API,或者简单地说,如果用户拒绝使用相机的权限。

如果没有指定目标,QuaggaJS会查找与CSS选择器匹配的元素#interactive.viewport(为了向后兼容)。 target可以是一个字符串(与CSS元素匹配的DOM节点)或DOM节点。

Quagga.start()

当库被初始化时,该start()方法启动视频流并开始定位和解码图像。

Quagga.stop()

如果解码器当前正在运行,则在调用stop()解码器之后不再处理任何图像。另外,如果在初始化时请求相机流,则此操作也会断开相机的连接。

Quagga.onProcessed(callback)

该方法注册callback(data)处理完成后为每个帧调用的函数。该data对象包含有关操作成功/失败的详细信息。取决于检测和/或解码是否成功,输出会有所不同

Quagga.onDetected(callback)

注册一个callback(data)功能,每当条形码图案被定位和解码成功时触发。传递的data对象包含关于解码处理的信息,包括可以通过调用获得的检测到的代码data.codeResult.code。

Quagga.offProcessed(handler)

如果onDetected事件不再是相关的,请从事件队列中offProcessed删除给定handler的事件

Quagga.offDetected(handler)

如果onDetected事件不再相关,请从事件队列中offDetected删除给定handler的事件。

结果对象:

回调通入onProcessed,onDetected接收data在执行对象。该data对象包含以下信息。取决于成功,某些领域可能是undefined或只是空的。

{
" codeResult ": {
"代码": " FANAVF1461710 ", //解码代码作为字符串
"格式": " code_128 ",//或code_39,库德巴,EAN_13,ean_8,UPC_A,upc_e
"启动": 355,
" end ": 26,
" codeset ": 100,
" startInfo ": {
" error ": 1.0000000000000002,
" code ": 104,
" start ": 21,
" end ": 41
},
" decodeCodes ": [{
" code ": 104,
" start ": 21,
" end ": 41
},
//为了简洁而剥离
{
"错误": 0.8888888888888893,
"代码": 106,
"启动": 328,
"端": 350
}],
" endInfo ": {
" error ": 0.8888888888888893,
" code ": 106,
" start ": 328,
" end ": 350
},
"方向": - 1
},
" line ": [{
" x ": 25.97278706156836,
" y ": 360.5616435369468
},{
" x ": 401.9220519377024,
" y ": 70.87524989906444
}],
"角度": - 0.6565217179979483,
"图案": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, / * ...* / 1 ],
" box ": [
[ 77.4074243622672,410.9288668804402 ]
[ 0.050203235235130705,310.53619724086366 ]
[ 360.15706727788256,33.05711026051813 ]
[ 437.5142884049146,133.44977990009465 ]
]
" box ": [
[
[ 77.4074243622672,410.9288668804402 ]
[ 0.050203235235130705,310.53619724086366 ]
[ 360.15706727788256,33.05711026051813 ]
[ 437.5142884049146,133.44977990009465 ]
]
[
[ 248.90769330706507,415.2041489551161 ]
[ 198.9532321622869,352.62160512937635 ]
[ 339.546160777576,240.3979259789976 ]
[ 389.5006219223542,302.98046980473737 ]
]
]
}

Configuration

QuaggaJS附带的配置涵盖了默认用例,可根据具体要求进行微调。

该配置由config定义以下高级属性的对象管理:

{
numOfWorkers: 4,
locate: true,
inputStream: {...},
frequency: 10,
decoder:{...},
locator: {...},
debug: false,
}

numOfWorkers

QuaggaJS支持线程,并在4线程的默认配置下运行。该数字应与目标设备中可用的核心数量一致。

如果您不知道前面的数字,或者设备种类太多,您可以使用navigator.hardwareConcurrency(参见 这里)可用或使用核心估计器

Locate

QuaggaJS的主要特征之一就是能够在给定的图像中定位条形码。该locate属性控制是否启用此功能(默认)或关闭。

为什么有人会关闭此功能?本地化条形码是一项计算上昂贵的操作,可能无法在某些设备上正常工作。另一个原因是缺乏自动对焦产生模糊的图像,这使得本地化功能非常不稳定。

然而,即使没有上述情况适用,还有一种情况可能会禁用locate:如果条形码的方向和/或大致位置已知,或者如果要引导用户通过矩形大纲。这可以同时提高性能和鲁棒性。

inputStream

该inputStream属性定义了QuaggaJS中的图像/视频的来源。

{
name: "Live",
type: "LiveStream",
constraints: {
width: 640,
height: 480,
facingMode: "environment",
deviceId: "7832475934759384534"
},
area: { // defines rectangle of the detection/localization area
top: "0%", // top offset
right: "0%", // right offset
left: "0%", // left offset
bottom: "0%" // bottom offset
},
singleChannel: false // true: only the red color-channel is read
}

  首先,type属性可以被设置为三个不同的值: ImageStream,VideoStream,或LiveStream(默认值),并应根据使用情况进行选择。很可能,默认值是足够的。

  第二,该constraint键定义输入图像的物理尺寸和附加属性,例如facingMode在多个连接的设备的情况下设置用户相机的源。另外,如果需要,deviceId如果给用户选择相机,则可以设置。这可以通过MediaDevices.enumerateDevices()轻松实现

  第三,area支路限制图像的解码区域。值以百分比形式给出,与使用时的CSS样式属性相似 position: absolute。这area在locate属性设置false为为用户定义矩形的情况下也是有用的。

  最后一个关键singleChannel仅在有人想要调试解码器的错误行为的情况下才是相关的。如果设置为true输入图像的红色通道,而不是计算源RGB的灰度值。

frequency:

此顶级属性控制视频流的扫描频率。它是可选的,并定义每秒扫描的最大数量。这对于扫描会话长时间运行的情况以及诸如CPU功耗等资源非常有用。

decoder:

QuaggaJS通常以两级方式运行(locate设置为true),在条形码位于之后,解码过程开始。解码是将条形转换成其真实含义的过程。大多数配置选项decoder仅用于调试/可视化目的。

{
readers: [
'code_128_reader'
],
debug: {
drawBoundingBox: false,
showFrequency: false,
drawScanline: false,
showPattern: false
}
multiple: false
}

最重要的属性是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
  • 2of5_reader
  • code_93_reader

为什么默认情况下不会激活所有类型?只是因为应该为用例明确定义一组条形码。更多的解码器意味着更多的可能的冲突,或者是错误的。应该照顾读者的命令,因为有些人可能会返回一个值,即使它不是正确的类型(EAN-13与UPC-A)。

该multiple属性告诉解码器,在找到有效的条形码后是否应该继续解码。如果设置为多个true,结果将作为结果对象的数组返回。数组中的每个对象将具有一个 box,并且可能具有codeResult取决于解码单个框的成功。

其余的性质drawBoundingBox,showFrequency,drawScanline和 showPattern大多的调试和可视化过程中的利益。

启用扩展EAN:

默认设置ean_reader不能读取扩展名,如EAN-2或 EAN-5。为了激活这些补充,您必须按照以下配置提供它们:

decoder: {
readers: [{
format: "ean_reader",
config: {
supplements: [
'ean_5_reader', 'ean_2_reader'
]
}
}]
}

请注意,supplements当发现第一次补充时,reader停止解码的事宜的顺序。因此,如果您对EAN-2和EAN-5扩展感兴趣,请使用上面描述的顺序。

重要的是要提及,如果提供补充,常规的EAN-13代码不能再读取同一个reader。如果您想阅读带有和不带扩展名的EAN-13,则必须向ean_reader配置添加另一个阅读器。

Locator

locator如果locate标志设置为只有相关的配置true。它控制本地化过程的行为,需要针对每个具体的用例进行调整。默认设置只是在开发过程中最有效的值的组合。

只有两个属性与Quagga(halfSample和 patchSize)中的使用相关,而其余属性仅用于开发和调试

{
halfSample: true,
patchSize: "medium", // x-small, small, medium, large, x-large
debug: {
showCanvas: false,
showPatches: false,
showFoundPatches: false,
showSkeleton: false,
showLabels: false,
showPatchLabels: false,
showRemainingPatchLabels: false,
boxFromPatches: {
showTransformed: false,
showTransformedBox: false,
showBB: false
}
}
}

该halfSample标志告诉定位器处理是否应该对缩小的图像(半宽/高,四分之一像素计数)进行操作。打开 halfSample显着减少处理时间,并且还有助于由于隐式平滑而找到条形码图案。在条形码真的很小并且需要全分辨率来找到位置的情况下应该关闭它。如果需要,建议保持打开并使用更高分辨率的视频图像。

第二个属性patchSize定义搜索网格的密度。该属性接受的值的字符串x-small,small,medium,large和 x-large。的patchSize是正比于扫描条形码的大小。如果你有很大的条形码,可以读取特写,那么使用 large或x-large推荐。在条形码远离相机镜头(缺少自动对焦或小条形码)的情况下,建议将尺寸设置为small甚至均匀x-small。对于后者,还建议您调整分辨率以找到条形码。

ResultCollector

对结果进行筛选减少错误率

var resultCollector = Quagga.ResultCollector.create({

capture: true, //跟踪生成结果图像

capacity: 20, //存储结果的最大数量

blacklist: [{ //不应该被记录的code的黑名单

code: "WIWV8ETQZ1", format: "code_93"

}, {

code: "EH3C-%GU23RK3", format: "code_93"

}, {

code: "O308SIHQOXN5SA/PJ", format: "code_93"

}, {

code: "DG7Q$TV8JQ/EN", format: "code_93"

}, {

code: "VOFD1DB5A.1F6QU", format: "code_93"

}, {

code: "4SO64P4X8 U4YUU1T-", format: "code_93"

}],

filter: function(codeResult) { //过滤器,严格定义存出结果 returns true/false

// only store results which match this constraint

// e.g.: return codeResult.format === "ean_13";

return codeResult.format === "code_128_reader";

}

});