Merge branch 'master' into master

pull/171/head
Tomáš Hübelbauer 7 years ago committed by GitHub
commit 098d78d325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,22 +1,26 @@
quaggaJS quaggaJS
======== ========
- [Changelog](#changelog) (2017-01-08) [![Join the chat at https://gitter.im/quaggaJS/Lobby](https://badges.gitter.im/quaggaJS/Lobby.svg)](https://gitter.im/quaggaJS/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- [Changelog](#changelog) (2017-06-07)
- [Browser Support](#browser-support) - [Browser Support](#browser-support)
- [Installing](#installing) - [Installing](#installing)
- [Getting Started](#gettingstarted) - [Getting Started](#gettingstarted)
- [API](#api) - [API](#api)
- [Configuration](#configobject) - [Configuration](#configobject)
- [Tips & Tricks](#tipsandtricks)
- [Sponsors](#sponsors)
## What is QuaggaJS? ## What is QuaggaJS?
QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real- QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real-
time localization and decoding of various types of barcodes such as __EAN__, time localization and decoding of various types of barcodes such as __EAN__,
__CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__, __I2of5__ and __CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__, __I2of5__,
__CODABAR__. The library is also capable of using `getUserMedia` to get direct __2of5__, __CODE 93__ and __CODABAR__. The library is also capable of using
access to the user's camera stream. Although the code relies on heavy image- `getUserMedia` to get direct access to the user's camera stream. Although the
processing even recent smartphones are capable of locating and decoding code relies on heavy image-processing even recent smartphones are capable of
barcodes in real-time. locating and decoding barcodes in real-time.
Try some [examples](https://serratus.github.io/quaggaJS/examples) and check out Try some [examples](https://serratus.github.io/quaggaJS/examples) and check out
the blog post ([How barcode-localization works in QuaggaJS][oberhofer_co_how]) the blog post ([How barcode-localization works in QuaggaJS][oberhofer_co_how])
@ -443,6 +447,8 @@ barcodes which should be decoded during the session. Possible values are:
- upc_reader - upc_reader
- upc_e_reader - upc_e_reader
- i2of5_reader - i2of5_reader
- 2of5_reader
- code_93_reader
Why are not all types activated by default? Simply because one should Why are not all types activated by default? Simply because one should
explicitly define the set of barcodes for their use-case. More decoders means explicitly define the set of barcodes for their use-case. More decoders means
@ -567,7 +573,7 @@ that node does not support web-workers out of the box. Therefore the config
property `numOfWorkers` must be explicitly set to `0`. property `numOfWorkers` must be explicitly set to `0`.
```javascript ```javascript
var Quagga = require('quagga'); var Quagga = require('quagga').default;
Quagga.decodeSingle({ Quagga.decodeSingle({
src: "image-abc-123.jpg", src: "image-abc-123.jpg",
@ -587,6 +593,36 @@ Quagga.decodeSingle({
}); });
``` ```
## <a name="tipsandtricks">Tips & Tricks</a>
A growing collection of tips & tricks to improve the various aspects of Quagga.
### Barcodes too small?
Barcodes too far away from the camera, or a lens too close to the object
result in poor recognition rates and Quagga might respond with a lot of
false-positives.
Starting in Chrome 59 you can now make use of `capabilities` and directly
control the zoom of the camera. Head over to the
[web-cam demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)
and check out the __Zoom__ feature.
You can read more about those `capabilities` in
[Let's light a torch and explore MediaStreamTrack's capabilities](https://www.oberhofer.co/mediastreamtrack-and-its-capabilities)
### Video too dark?
Dark environments usually result in noisy images and therefore mess with the
recognition logic.
Since Chrome 59 you can turn on/off the __Torch__ of our device and vastly
improve the quality of the images. Head over to the
[web-cam demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)
and check out the __Torch__ feature.
To find out more about this feature [read on](https://www.oberhofer.co/mediastreamtrack-and-its-capabilities).
## Tests ## Tests
Unit Tests can be run with [Karma][karmaUrl] and written using Unit Tests can be run with [Karma][karmaUrl] and written using
@ -663,8 +699,32 @@ calling ``decodeSingle`` with the same configuration as used during recording
. In order to reproduce the exact same result, you have to make sure to turn . In order to reproduce the exact same result, you have to make sure to turn
on the ``singleChannel`` flag in the configuration when using ``decodeSingle``. on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.
## <a name="sponsors">Sponsors</a>
- [Maintenance Connection Canada (Asset Pro Solutions Inc.](http://maintenanceconnection.ca/)
## <a name="changelog">Changelog</a> ## <a name="changelog">Changelog</a>
### 2017-06-07
- Improvements
- added `muted` and `playsinline` to `<video/>` to make it work for Safari 11
Beta (even iOS)
- Fixes
- Fixed [example/live_w_locator.js](https://github.com/serratus/quaggaJS/blob/master/example/live_w_locator.js)
### 2017-06-06
- Features
- Support for Standard 2of5 barcodes (See
[\#194](https://github.com/serratus/quaggaJS/issues/194))
- Support for Code 93 barcodes (See
[\#194](https://github.com/serratus/quaggaJS/issues/195))
- Exposing `Quagga.CameraAccess.getActiveTrack()` to get access to the
currently used `MediaStreamTrack`
- Example can be viewed here: [example/live_w_locator.js](https://github.com/serratus/quaggaJS/blob/master/example/live_w_locator.js) and a [demo](https://serratus.github.io/quaggaJS/examples/live_w_locator.html)
Take a look at the release-notes (
[0.12.0](https://github.com/serratus/quaggaJS/releases/tag/v0.12.0))
### 2017-01-08 ### 2017-01-08
- Improvements - Improvements
- Exposing `CameraAccess` module to get access to methods like - Exposing `CameraAccess` module to get access to methods like

@ -1,6 +1,6 @@
{ {
"name": "quagga", "name": "quagga",
"version": "0.11.6", "version": "0.12.1",
"description": "An advanced barcode-scanner written in JavaScript", "description": "An advanced barcode-scanner written in JavaScript",
"main": "dist/quagga.js", "main": "dist/quagga.js",
"ignore": [ "ignore": [

2058
dist/quagga.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,79 +1,109 @@
@charset "UTF-8"; @charset "UTF-8";
/* usual styles */
/* LESS - http://lesscss.org style sheet */
/* Palette color codes */
/* Palette URL: http://paletton.com/#uid=31g0q0kHZAviRSkrHLOGomVNzac */
/* Feel free to copy&paste color codes to your application */
/* MIXINS */
/* As hex codes */
/* Main Primary color */
/* Main Secondary color (1) */
/* Main Secondary color (2) */
/* As RGBa codes */
/* Main Primary color */
/* Main Secondary color (1) */
/* Main Secondary color (2) */
/* Generated by Paletton.com ├é┬® 2002-2014 */
/* http://paletton.com */
@import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); @import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600");
/* line 1, ../sass/_viewport.scss */
body {
background-color: #FFF;
margin: 0px;
font-family: Ubuntu, sans-serif;
color: #1e1e1e;
font-weight: normal;
padding-top: 0;
}
h1, h2, h3, h4 {
font-family: "Cabin Condensed", sans-serif;
}
header {
background: #FFC600;
padding: 1em;
}
header .headline {
max-width: 640px;
margin: 0 auto;
}
header .headline h1 {
color: #FFDD69;
font-size: 3em;
margin-bottom: 0;
}
header .headline h2 {
margin-top: 0.2em;
}
footer {
background: #0A4DB7;
color: #6C9CE8;
padding: 1em 2em 2em;
}
#container {
width: 640px;
margin: 20px auto;
padding: 10px;
}
#interactive.viewport { #interactive.viewport {
width: 640px; width: 640px;
height: 480px; height: 480px;
} }
/* line 6, ../sass/_viewport.scss */
#interactive.viewport canvas, video { #interactive.viewport canvas, video {
float: left; float: left;
width: 640px; width: 640px;
height: 480px; height: 480px;
} }
/* line 10, ../sass/_viewport.scss */
#interactive.viewport canvas.drawingBuffer, video.drawingBuffer { #interactive.viewport canvas.drawingBuffer, video.drawingBuffer {
margin-left: -640px; margin-left: -640px;
} }
/* line 16, ../sass/_viewport.scss */
.controls fieldset { .controls fieldset {
border: none; border: none;
margin: 0;
padding: 0;
} }
/* line 19, ../sass/_viewport.scss */
.controls .input-group { .controls .input-group {
float: left; float: left;
} }
/* line 21, ../sass/_viewport.scss */
.controls .input-group input, .controls .input-group button { .controls .input-group input, .controls .input-group button {
display: block; display: block;
} }
/* line 25, ../sass/_viewport.scss */
.controls .reader-config-group { .controls .reader-config-group {
float: right; float: right;
} }
/* line 28, ../sass/_viewport.scss */
.controls .reader-config-group label { .controls .reader-config-group label {
display: block; display: block;
} }
/* line 30, ../sass/_viewport.scss */
.controls .reader-config-group label span { .controls .reader-config-group label span {
width: 11rem; width: 9rem;
display: inline-block; display: inline-block;
text-align: right; text-align: right;
} }
/* line 37, ../sass/_viewport.scss */
.controls:after { .controls:after {
content: ''; content: '';
display: block; display: block;
clear: both; clear: both;
} }
/* line 44, ../sass/_viewport.scss */
#result_strip { #result_strip {
margin: 10px 0; margin: 10px 0;
border-top: 1px solid #EEE; border-top: 1px solid #EEE;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #EEE;
padding: 10px 0; padding: 10px 0;
} }
/* line 50, ../sass/_viewport.scss */
#result_strip > ul { #result_strip > ul {
padding: 0; padding: 0;
margin: 0; margin: 0;
@ -83,41 +113,41 @@
overflow-y: hidden; overflow-y: hidden;
white-space: nowrap; white-space: nowrap;
} }
/* line 59, ../sass/_viewport.scss */
#result_strip > ul > li { #result_strip > ul > li {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
width: 160px; width: 160px;
} }
/* line 63, ../sass/_viewport.scss */
#result_strip > ul > li .thumbnail { #result_strip > ul > li .thumbnail {
padding: 5px; padding: 5px;
margin: 4px; margin: 4px;
border: 1px dashed #CCC; border: 1px dashed #CCC;
} }
/* line 68, ../sass/_viewport.scss */
#result_strip > ul > li .thumbnail img { #result_strip > ul > li .thumbnail img {
max-width: 140px; max-width: 140px;
} }
/* line 71, ../sass/_viewport.scss */
#result_strip > ul > li .thumbnail .caption { #result_strip > ul > li .thumbnail .caption {
white-space: normal; white-space: normal;
} }
/* line 73, ../sass/_viewport.scss */
#result_strip > ul > li .thumbnail .caption h4 { #result_strip > ul > li .thumbnail .caption h4 {
text-align: center; text-align: center;
word-wrap: break-word; word-wrap: break-word;
height: 40px; height: 40px;
margin: 0px; margin: 0px;
} }
/* line 83, ../sass/_viewport.scss */
#result_strip > ul:after { #result_strip > ul:after {
content: ""; content: "";
display: table; display: table;
clear: both; clear: both;
} }
/* line 7, ../sass/_overlay.scss */
.scanner-overlay { .scanner-overlay {
display: none; display: none;
width: 640px; width: 640px;
@ -133,21 +163,21 @@
-webkit-box-shadow: #333333 0px 4px 10px; -webkit-box-shadow: #333333 0px 4px 10px;
box-shadow: #333333 0px 4px 10px; box-shadow: #333333 0px 4px 10px;
} }
/* line 20, ../sass/_overlay.scss */
.scanner-overlay > .header { .scanner-overlay > .header {
position: relative; position: relative;
margin-bottom: 14px; margin-bottom: 14px;
} }
/* line 23, ../sass/_overlay.scss */
.scanner-overlay > .header h4, .scanner-overlay > .header .close { .scanner-overlay > .header h4, .scanner-overlay > .header .close {
line-height: 16px; line-height: 16px;
} }
/* line 26, ../sass/_overlay.scss */
.scanner-overlay > .header h4 { .scanner-overlay > .header h4 {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
} }
/* line 30, ../sass/_overlay.scss */
.scanner-overlay > .header .close { .scanner-overlay > .header .close {
position: absolute; position: absolute;
right: 0px; right: 0px;
@ -160,7 +190,7 @@
cursor: pointer; cursor: pointer;
} }
/* line 1, ../sass/_icons.scss */
i.icon-24-scan { i.icon-24-scan {
width: 24px; width: 24px;
height: 24px; height: 24px;
@ -172,11 +202,8 @@ i.icon-24-scan {
vertical-align: text-top; vertical-align: text-top;
} }
@media (min-width: 604px) and (max-width: 1024px) {
/* tablet styles */
}
@media (max-width: 603px) { @media (max-width: 603px) {
/* line 2, ../sass/phone/_core.scss */
#container { #container {
width: 300px; width: 300px;
margin: 10px auto; margin: 10px auto;
@ -184,46 +211,58 @@ i.icon-24-scan {
-webkit-box-shadow: none; -webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
} }
/* line 9, ../sass/phone/_core.scss */
#container form.voucher-form input.voucher-code { #container form.voucher-form input.voucher-code {
width: 180px; width: 180px;
} }
} }
@media (max-width: 603px) { @media (max-width: 603px) {
/* line 5, ../sass/phone/_viewport.scss */
.reader-config-group {
width: 100%;
}
.reader-config-group label > span {
width: 50%;
}
.reader-config-group label > select, .reader-config-group label > input {
max-width: calc(50% - 2px);
}
#interactive.viewport { #interactive.viewport {
width: 300px; width: 300px;
height: 300px; height: 300px;
overflow: hidden; overflow: hidden;
} }
/* line 11, ../sass/phone/_viewport.scss */
#interactive.viewport canvas, video { #interactive.viewport canvas, video {
margin-top: -50px; margin-top: -50px;
width: 300px; width: 300px;
height: 400px; height: 400px;
} }
/* line 15, ../sass/phone/_viewport.scss */
#interactive.viewport canvas.drawingBuffer, video.drawingBuffer { #interactive.viewport canvas.drawingBuffer, video.drawingBuffer {
margin-left: -300px; margin-left: -300px;
} }
/* line 20, ../sass/phone/_viewport.scss */
#result_strip { #result_strip {
margin-top: 5px; margin-top: 5px;
padding-top: 5px; padding-top: 5px;
} }
/* line 24, ../sass/phone/_viewport.scss */
#result_strip ul.thumbnails > li { #result_strip ul.thumbnails > li {
width: 150px; width: 150px;
} }
/* line 27, ../sass/phone/_viewport.scss */
#result_strip ul.thumbnails > li .thumbnail .imgWrapper { #result_strip ul.thumbnails > li .thumbnail .imgWrapper {
width: 130px; width: 130px;
height: 130px; height: 130px;
overflow: hidden; overflow: hidden;
} }
/* line 31, ../sass/phone/_viewport.scss */
#result_strip ul.thumbnails > li .thumbnail .imgWrapper img { #result_strip ul.thumbnails > li .thumbnail .imgWrapper img {
margin-top: -25px; margin-top: -25px;
width: 130px; width: 130px;
@ -231,7 +270,7 @@ i.icon-24-scan {
} }
} }
@media (max-width: 603px) { @media (max-width: 603px) {
/* line 8, ../sass/phone/_overlay.scss */
.overlay.scanner { .overlay.scanner {
width: 640px; width: 640px;
height: 510px; height: 510px;
@ -243,66 +282,17 @@ i.icon-24-scan {
-webkit-box-shadow: none; -webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
} }
/* line 17, ../sass/phone/_overlay.scss */
.overlay.scanner > .header { .overlay.scanner > .header {
margin-bottom: 14px; margin-bottom: 14px;
} }
/* line 19, ../sass/phone/_overlay.scss */
.overlay.scanner > .header h4, .overlay.scanner > .header .close { .overlay.scanner > .header h4, .overlay.scanner > .header .close {
line-height: 16px; line-height: 16px;
} }
/* line 22, ../sass/phone/_overlay.scss */
.overlay.scanner > .header .close { .overlay.scanner > .header .close {
height: 16px; height: 16px;
width: 16px; width: 16px;
} }
} }
/* line 15, ../sass/styles.scss */
body {
background-color: #FFF;
margin: 0px;
font-family: Ubuntu, sans-serif;
color: #1e1e1e;
font-weight: normal;
padding-top: 0;
}
/* line 24, ../sass/styles.scss */
h1, h2, h3, h4 {
font-family: "Cabin Condensed", sans-serif;
}
/* line 28, ../sass/styles.scss */
header {
background: #FFC600;
padding: 1em;
}
/* line 31, ../sass/styles.scss */
header .headline {
width: 640px;
margin: 0 auto;
}
/* line 34, ../sass/styles.scss */
header .headline h1 {
color: #FFDD69;
font-size: 3em;
margin-bottom: 0;
}
/* line 39, ../sass/styles.scss */
header .headline h2 {
margin-top: 0.2em;
}
/* line 45, ../sass/styles.scss */
footer {
background: #0A4DB7;
color: #6C9CE8;
padding: 1em 2em 2em;
}
/* line 51, ../sass/styles.scss */
#container {
width: 640px;
margin: 20px auto;
padding: 10px;
}

@ -51,7 +51,9 @@
<option value="upc">UPC</option> <option value="upc">UPC</option>
<option value="upc_e">UPC-E</option> <option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option> <option value="codabar">Codabar</option>
<option value="i2of5">ITF</option> <option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select> </select>
</label> </label>
<label> <label>

@ -8,7 +8,7 @@
<meta name="description" content="" /> <meta name="description" content="" />
<meta name="author" content="Christoph Oberhofer" /> <meta name="author" content="Christoph Oberhofer" />
<meta name="viewport" content="width=device-width; initial-scale=1.0" /> <meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=no" />
<link rel="stylesheet" type="text/css" href="css/styles.css" /> <link rel="stylesheet" type="text/css" href="css/styles.css" />
</head> </head>
@ -43,11 +43,13 @@
<option value="upc">UPC</option> <option value="upc">UPC</option>
<option value="upc_e">UPC-E</option> <option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option> <option value="codabar">Codabar</option>
<option value="i2of5">ITF</option> <option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select> </select>
</label> </label>
<label> <label>
<span>Resolution (long side)</span> <span>Resolution (width)</span>
<select name="input-stream_constraints"> <select name="input-stream_constraints">
<option value="320x240">320px</option> <option value="320x240">320px</option>
<option selected="selected" value="640x480">640px</option> <option selected="selected" value="640x480">640px</option>
@ -86,6 +88,14 @@
<select name="input-stream_constraints" id="deviceSelection"> <select name="input-stream_constraints" id="deviceSelection">
</select> </select>
</label> </label>
<label style="display: none">
<span>Zoom</span>
<select name="settings_zoom"></select>
</label>
<label style="display: none">
<span>Torch</span>
<input type="checkbox" name="settings_torch" />
</label>
</fieldset> </fieldset>
</div> </div>
<div id="result_strip"> <div id="result_strip">

@ -2,7 +2,19 @@ $(function() {
var resultCollector = Quagga.ResultCollector.create({ var resultCollector = Quagga.ResultCollector.create({
capture: true, capture: true,
capacity: 20, capacity: 20,
blacklist: [{code: "2167361334", format: "i2of5"}], blacklist: [{
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) { filter: function(codeResult) {
// only store results which match this constraint // only store results which match this constraint
// e.g.: codeResult // e.g.: codeResult
@ -19,12 +31,57 @@ $(function() {
} }
//Quagga.registerResultCollector(resultCollector); //Quagga.registerResultCollector(resultCollector);
App.attachListeners(); App.attachListeners();
App.checkCapabilities();
Quagga.start(); Quagga.start();
}); });
}, },
handleError: function(err) { handleError: function(err) {
console.log(err); console.log(err);
}, },
checkCapabilities: function() {
var track = Quagga.CameraAccess.getActiveTrack();
var capabilities = {};
if (typeof track.getCapabilities === 'function') {
capabilities = track.getCapabilities();
}
this.applySettingsVisibility('zoom', capabilities.zoom);
this.applySettingsVisibility('torch', capabilities.torch);
},
updateOptionsForMediaRange: function(node, range) {
console.log('updateOptionsForMediaRange', node, range);
var NUM_STEPS = 6;
var stepSize = (range.max - range.min) / NUM_STEPS;
var option;
var value;
while (node.firstChild) {
node.removeChild(node.firstChild);
}
for (var i = 0; i <= NUM_STEPS; i++) {
value = range.min + (stepSize * i);
option = document.createElement('option');
option.value = value;
option.innerHTML = value;
node.appendChild(option);
}
},
applySettingsVisibility: function(setting, capability) {
// depending on type of capability
if (typeof capability === 'boolean') {
var node = document.querySelector('input[name="settings_' + setting + '"]');
if (node) {
node.parentNode.style.display = capability ? 'block' : 'none';
}
return;
}
if (window.MediaSettingsRange && capability instanceof window.MediaSettingsRange) {
var node = document.querySelector('select[name="settings_' + setting + '"]');
if (node) {
this.updateOptionsForMediaRange(node, capability);
node.parentNode.style.display = 'block';
}
return;
}
},
initCameraSelection: function(){ initCameraSelection: function(){
var streamLabel = Quagga.CameraAccess.getActiveStreamLabel(); var streamLabel = Quagga.CameraAccess.getActiveStreamLabel();
@ -104,6 +161,17 @@ $(function() {
$(".controls").off("click", "button.stop"); $(".controls").off("click", "button.stop");
$(".controls .reader-config-group").off("change", "input, select"); $(".controls .reader-config-group").off("change", "input, select");
}, },
applySetting: function(setting, value) {
var track = Quagga.CameraAccess.getActiveTrack();
if (track && typeof track.getCapabilities === 'function') {
switch (setting) {
case 'zoom':
return track.applyConstraints({advanced: [{zoom: parseFloat(value)}]});
case 'torch':
return track.applyConstraints({advanced: [{torch: !!value}]});
}
}
},
setState: function(path, value) { setState: function(path, value) {
var self = this; var self = this;
@ -111,6 +179,10 @@ $(function() {
value = self._accessByPath(self.inputMapper, path)(value); value = self._accessByPath(self.inputMapper, path)(value);
} }
if (path.startsWith('settings.')) {
var setting = path.substring(9);
return self.applySetting(setting, value);
}
self._accessByPath(self.state, path, value); self._accessByPath(self.state, path, value);
console.log(JSON.stringify(self.state)); console.log(JSON.stringify(self.state));
@ -169,7 +241,8 @@ $(function() {
patchSize: "medium", patchSize: "medium",
halfSample: true halfSample: true
}, },
numOfWorkers: 4, numOfWorkers: 2,
frequency: 10,
decoder: { decoder: {
readers : [{ readers : [{
format: "code_128_reader", format: "code_128_reader",

@ -0,0 +1,27 @@
var Quagga = require('../lib/quagga').default;
var buffer = require('fs').readFileSync('../test/fixtures/code_128/image-001.jpg');
decode(buffer);
function decode(buff){
Quagga.decodeSingle({
src: buff,
numOfWorkers: 0,
inputStream: {
mime: "image/jpeg",
size: 800,
area: {
top: "10%",
right: "5%",
left: "5%",
bottom: "10%"
}
}
}, function(result) {
if (result.codeResult) {
console.log("result", result.codeResult.code);
} else {
console.log("not detected");
}
});
}

@ -1,10 +0,0 @@
i.icon-24-scan{
width: 24px;
height: 24px;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzFFMjMzNTBFNjcwMTFFMkIzMERGOUMzMzEzM0E1QUMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzFFMjMzNTFFNjcwMTFFMkIzMERGOUMzMzEzM0E1QUMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDMUUyMzM0RUU2NzAxMUUyQjMwREY5QzMzMTMzQTVBQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDMUUyMzM0RkU2NzAxMUUyQjMwREY5QzMzMTMzQTVBQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtQr90wAAAUuSURBVHjanFVLbFRVGP7ua97T9DGPthbamAYYBNSMVbBpjCliWWGIEBMWsnDJxkh8RDeEDW5MDGticMmGBWnSlRSCwgLFNkqmmrRIqzjTznTazkxn5s7c6/efzm0G0Jhwkj/nP+d/nv91tIWFBTQaDQWapkGW67p4ltUub5qmAi0UCqF/a/U2m81tpmddotwwDGSz2dzi4uKSaOucnJycGhsbe1XXdQiIIcdxEAgEtgXq9brySHCht79UXi/8QheawN27d385fPjwuEl6XyKR6LdtW7t06RLK5TKOHj2K/fv3Q87Dw8OYn5/HiRMnMDs7i5mZGQwODiqlPp8PuVwO6XRaOXb16lXl1OnTp5FMJvtosF8M+MWLarWqGJaWlpBKpRRcu3YN4+PjmJ6exsTEhDJw5coVjI6OKgPhcBiZTAbxeBx+vx+XL19Gd3c3Tp48Ka9zqDYgBlTQxYNgMIhIJKLCILkQb+TZsgvdsiyFi+feWRR7oRNZyanQtvW2V4DEUUBiK2eJpeDirSyhCe7F2QPh8fiEp72i9PbsC5G52DbiKZA771yr1dTuGfJ4PQNPFoAyQNR1aNEmsS5eyB3PgjeooMZd2AWvNmzYci/Gea7TeFOcI93jV/K67noGmi4vdRI9gPSDeMLSdKUBZZczlWm1rTtHjLZ24d+WER2tc8N1m+Y+ID74wx0zGYvhg9UNrJdtHJyZRdQfwPsrq9g99xsGlgsYmr6BNzO/IVwsYfjBQ6XYz6JI/72MV366B5/lw0elOkJWGUM3bmKtWjXSLuLaBWhnPnnp0FfoiFi4+TMfVAb2poBkDLjO845uYLEAjL4ALGWBP5YAOsP4AJYBFDaB1HOSVWD2PuV95H2RdV93Lv74/cf6p6Zxq/h6OofeOPJBC39JtONdwOAAViOs4p4OFGTf0Uc8iiyrr9YdQrUnDLsngrVOC0jQib44HlF2RafRZBz1Qy+vfhgK3NJZBlrm+LEm9qWwzFgLU7Ozg0JxZP06jQSRpQ7EerAWDSt6PuhHPmChEAog56fCLvJT5hHTm3OZkz3DyLx7XNWTGEA1GkV14gjWgwbW0ESVjYRwCOuai03L5E7OUBAV4kXSS4auoGIaKOma4m8EA5R1sMEGLh95C+XuLph0WJWpxepYYLtfT0RRgY1KgNODY6BoaChRuEhDCIZQYseuki5KN6hcQHiq7OZNv4/Zq2O6P4Lfkwn46vZjjaYZrIpvWbpzjLErrc4xUGE4avRedpYJalRcIl5hQius/SrPm9xrNOQYJhao6BvNUeWqtY8KaWuNjHOFAr7mM9f4NA4UbKysoUJ8PV9UzVOx6wxDDWUOxnK1pmCD07fOMAvtIsM3l89Dl3HRGhVma9AZMqjOnz2LQqWCxs6dqr3T7x1DTzKJaG8SekcHhg4cgI/56uKdlKnBV/WndqN3YAB/7tyBd3oT6GBIOzs7kc/nDfFdDFT5bS73cp06dQoaPa/Rw/rtO/resTHxxE2m9rCrbSR27UJCcMf1BpiA5rAAGgdfc868fUR1sMwj0cm9Iu9IctweisViB3hhKTHDcHc5jv/LspbyaZrR1OD82/fIlOkuB9LnEWRmDX2TsddUPg3D5gvuc0je0rZaD5EW6G3yjS+A3eeBEWq3XW/Abw1HhUspXADufQb86oW7tZytkYCN//3hHwBvDALPi8EnSOYK8DAOfCc2h4aGcO7cuafkzampqf9UripH12/DtOZbx8ciVGzYy5OO40o25ascGRl5Ssc/AgwAjW3JwqIUjSYAAAAASUVORK5CYII=");
display: inline-block;
background-repeat: no-repeat;
line-height: 24px;
margin-top: 1px;
vertical-align: text-top;
}

@ -1,48 +0,0 @@
$overlayWidth: $videoWidth;
$overlayHeadline: 16px;
$overlayHeadlineMargin: 14px;
$overlayPadding: 20px;
$overlayHeight: $videoHeight + $overlayHeadlineMargin + $overlayHeadline;
.scanner-overlay {
display: none;
width: $overlayWidth;
height: $overlayHeight;
position: absolute;
padding: $overlayPadding;
top: 50%;
margin-top: -($overlayHeight)/2 - $overlayPadding;
left: 50%;
margin-left: -($overlayWidth + 2*$overlayPadding)/2;
background-color: $overlayBackground;
@include box-shadow(#333333 0px 4px 10px);
& > .header{
position: relative;
margin-bottom: $overlayHeadlineMargin;
h4, .close{
line-height: $overlayHeadline;
}
h4{
margin: 0px;
padding: 0px;
}
.close{
position: absolute;
right: 0px;
top: 0px;
height: $overlayHeadline;
width: $overlayHeadline;
text-align: center;
font-weight: bold;
font-size: 14px;
cursor: pointer;
}
}
& > .body{
}
}

@ -1,3 +0,0 @@
@import "phone/core";
@import "phone/viewport";
@import "phone/overlay";

@ -1,4 +0,0 @@
@include tablet {
/* tablet styles */
}

@ -1,17 +0,0 @@
$tablet_upper: 1024px;
$phone_upper: 603px;
@mixin phone {
@media (max-width: $phone_upper) {
@content;
}
} // @mixin phone
@mixin tablet {
@media (min-width: $phone_upper+1) and (max-width: $tablet_upper) {
@content;
}
} // @mixin tablet

@ -1,7 +0,0 @@
$background_color: #FFF;
$overlayBackground: #FFF;
$videoWidth: 640px;
$videoHeight: 480px;
$text-font: Ubuntu, sans-serif;
$header-font: 'Cabin Condensed', sans-serif;

@ -1,89 +0,0 @@
#interactive.viewport{
width: $videoWidth;
height: $videoHeight;
}
#interactive.viewport canvas, video{
float: left;
width: $videoWidth;
height: $videoHeight;
&.drawingBuffer{
margin-left: -$videoWidth;
}
}
.controls {
fieldset {
border: none;
}
.input-group {
float: left;
input, button {
display: block;
}
}
.reader-config-group {
float: right;
label {
display: block;
span {
width: 11rem;
display: inline-block;
text-align: right;
}
}
}
&:after {
content:'';
display: block;
clear: both;
}
}
#result_strip{
margin: 10px 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid #EEE;
padding: 10px 0;
& > ul {
padding: 0;
margin: 0;
list-style-type: none;
width: auto;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
& > li{
display: inline-block;
vertical-align: middle;
width: $videoWidth/4;
.thumbnail{
padding: 5px;
margin: 4px;
border: 1px dashed #CCC;
img{
max-width: $videoWidth/4 - 20px;
}
.caption{
white-space: normal;
h4{
text-align: center;
word-wrap: break-word;
height: 40px;
margin: 0px;
}
}
}
}
&:after{
content: "";
display: table;
clear: both;
}
}
}

@ -1,55 +0,0 @@
/* LESS - http://lesscss.org style sheet */
/* Palette color codes */
/* Palette URL: http://paletton.com/#uid=31g0q0kHZAviRSkrHLOGomVNzac */
/* Feel free to copy&paste color codes to your application */
/* MIXINS */
/* As hex codes */
$color-primary-0: #FFC600; /* Main Primary color */
$color-primary-1: #FFDD69;
$color-primary-2: #FFCE22;
$color-primary-3: #B78E00;
$color-primary-4: #513F00;
$color-secondary-1-0: #0A4DB7; /* Main Secondary color (1) */
$color-secondary-1-1: #6C9CE8;
$color-secondary-1-2: #2E6FD6;
$color-secondary-1-3: #073379;
$color-secondary-1-4: #021636;
$color-secondary-2-0: #5809BB; /* Main Secondary color (2) */
$color-secondary-2-1: #A36BE9;
$color-secondary-2-2: #782DD8;
$color-secondary-2-3: #3A077C;
$color-secondary-2-4: #190237;
/* As RGBa codes */
$rgba-primary-0: rgba(255,198, 0,1); /* Main Primary color */
$rgba-primary-1: rgba(255,221,105,1);
$rgba-primary-2: rgba(255,206, 34,1);
$rgba-primary-3: rgba(183,142, 0,1);
$rgba-primary-4: rgba( 81, 63, 0,1);
$rgba-secondary-1-0: rgba( 10, 77,183,1); /* Main Secondary color (1) */
$rgba-secondary-1-1: rgba(108,156,232,1);
$rgba-secondary-1-2: rgba( 46,111,214,1);
$rgba-secondary-1-3: rgba( 7, 51,121,1);
$rgba-secondary-1-4: rgba( 2, 22, 54,1);
$rgba-secondary-2-0: rgba( 88, 9,187,1); /* Main Secondary color (2) */
$rgba-secondary-2-1: rgba(163,107,233,1);
$rgba-secondary-2-2: rgba(120, 45,216,1);
$rgba-secondary-2-3: rgba( 58, 7,124,1);
$rgba-secondary-2-4: rgba( 25, 2, 55,1);
/* Generated by Paletton.com © 2002-2014 */
/* http://paletton.com */

@ -1 +0,0 @@
@import url('http://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600');

@ -1,15 +0,0 @@
@include phone {
#container{
width: 300px;
margin: 10px auto;
@include box-shadow(none);
form.voucher-form{
input{
&.voucher-code{
width: 180px;
}
}
}
}
}

@ -1,28 +0,0 @@
@include phone {
$overlayWidth: $videoWidth;
$overlayHeadline: 16px;
$overlayHeadlineMargin: 14px;
$overlayPadding: 20px;
$overlayHeight: $videoHeight + $overlayHeadlineMargin + $overlayHeadline;
.overlay.scanner {
width: $overlayWidth;
height: $overlayHeight;
padding: $overlayPadding;
margin-top: -($overlayHeight)/2 - $overlayPadding;
margin-left: -($overlayWidth + 2*$overlayPadding)/2;
background-color: $overlayBackground;
@include box-shadow(none);
& > .header{
margin-bottom: $overlayHeadlineMargin;
h4, .close{
line-height: $overlayHeadline;
}
.close{
height: $overlayHeadline;
width: $overlayHeadline;
}
}
}
}

@ -1,42 +0,0 @@
@include phone {
$videoWidth: 300px;
$videoHeight: 400px;
#interactive.viewport{
width: $videoWidth;
height: $videoWidth;
overflow: hidden;
}
#interactive.viewport canvas, video{
margin-top: ($videoWidth - $videoHeight)/2;
width: $videoWidth;
height: $videoHeight;
&.drawingBuffer{
margin-left: -$videoWidth;
}
}
#result_strip{
margin-top: 5px;
padding-top: 5px;
ul.thumbnails{
& > li{
width: $videoWidth/2;
.thumbnail{
.imgWrapper{
width: $videoWidth/2 - 20px;
height: $videoWidth/2 - 20px;
overflow: hidden;
img{
margin-top: (($videoWidth/2 - 20px) - ($videoHeight/2 - 20px))/2;
width: $videoWidth/2 - 20px;
height: $videoHeight/2 - 20px;
}
}
}
}
}
}
}

@ -1,14 +0,0 @@
@import "compass/css3";
@import "variables";
@import "utility";
/* usual styles */
@import "fonts";
@import "viewport";
@import "overlay";
@import "icons";
@import "tablet";
@import "phone";

@ -1,56 +0,0 @@
@import "compass/css3";
@import "variables";
@import "utility";
/* usual styles */
@import "colors";
@import "fonts";
@import "viewport";
@import "overlay";
@import "icons";
@import "tablet";
@import "phone";
body{
background-color: #FFF;
margin: 0px;
font-family: $text-font;
color: #1e1e1e;
font-weight: normal;
padding-top: 0;
}
h1,h2,h3,h4 {
font-family: $header-font;
}
header {
background: $color-primary-0;
padding: 1em;
.headline {
width: 640px;
margin: 0 auto;
h1 {
color: $color-primary-1;
font-size: 3em;
margin-bottom: 0;
}
h2 {
margin-top: 0.2em;
}
}
}
footer {
background: $color-secondary-1-0;
color: $color-secondary-1-1;
padding: 1em 2em 2em;
}
#container{
width: 640px;
margin: 20px auto;
padding: 10px;
}

@ -45,6 +45,9 @@
<option value="upc_e">UPC-E</option> <option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option> <option value="codabar">Codabar</option>
<option value="i2of5">I2of5</option> <option value="i2of5">I2of5</option>
<option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select> </select>
</fieldset> </fieldset>
</div> </div>

@ -14,6 +14,9 @@ module.exports = function(config) {
'test/test-main-integration.js': ['webpack'] 'test/test-main-integration.js': ['webpack']
}, },
webpack: { webpack: {
entry: [
'./src/quagga.js'
],
module: { module: {
loaders: [{ loaders: [{
test: /\.jsx?$/, test: /\.jsx?$/,
@ -45,7 +48,7 @@ module.exports = function(config) {
reporters: ['progress'], reporters: ['progress'],
port: 9876, port: 9876,
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO, // LOG_DEBUG
autoWatch: true, autoWatch: true,
browsers: ['Chrome'], browsers: ['Chrome'],
singleRun: false singleRun: false

@ -13,6 +13,9 @@ module.exports = function(config) {
'test/test-main.js': ['webpack'] 'test/test-main.js': ['webpack']
}, },
webpack: { webpack: {
entry: [
'./src/quagga.js'
],
module: { module: {
loaders: [{ loaders: [{
test: /\.jsx?$/, test: /\.jsx?$/,

@ -24,7 +24,7 @@ InputStream.createImageStream = function() {
function loadImages() { function loadImages() {
loaded = false; loaded = false;
GetPixels(baseUrl, function(err, pixels) { GetPixels(baseUrl, _config.mime, function(err, pixels) {
if (err) { if (err) {
console.log(err); console.log(err);
exit(1); exit(1);

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
{ {
"name": "quagga", "name": "quagga",
"version": "0.11.6", "version": "0.12.1",
"description": "An advanced barcode-scanner written in JavaScript", "description": "An advanced barcode-scanner written in JavaScript",
"main": "lib/quagga.js", "main": "lib/quagga.js",
"browser": "dist/quagga.min.js", "browser": "dist/quagga.min.js",

@ -488,7 +488,7 @@ export function grayAndHalfSampleFromCanvasData(canvasData, size, outArray) {
while (bottomRowIdx < endIdx) { while (bottomRowIdx < endIdx) {
for ( i = 0; i < outWidth; i++) { for ( i = 0; i < outWidth; i++) {
outArray[outImgIdx] = Math.floor(( outArray[outImgIdx] = (
(0.299 * canvasData[topRowIdx * 4 + 0] + (0.299 * canvasData[topRowIdx * 4 + 0] +
0.587 * canvasData[topRowIdx * 4 + 1] + 0.587 * canvasData[topRowIdx * 4 + 1] +
0.114 * canvasData[topRowIdx * 4 + 2]) + 0.114 * canvasData[topRowIdx * 4 + 2]) +
@ -500,7 +500,7 @@ export function grayAndHalfSampleFromCanvasData(canvasData, size, outArray) {
0.114 * canvasData[(bottomRowIdx) * 4 + 2]) + 0.114 * canvasData[(bottomRowIdx) * 4 + 2]) +
(0.299 * canvasData[(bottomRowIdx + 1) * 4 + 0] + (0.299 * canvasData[(bottomRowIdx + 1) * 4 + 0] +
0.587 * canvasData[(bottomRowIdx + 1) * 4 + 1] + 0.587 * canvasData[(bottomRowIdx + 1) * 4 + 1] +
0.114 * canvasData[(bottomRowIdx + 1) * 4 + 2])) / 4); 0.114 * canvasData[(bottomRowIdx + 1) * 4 + 2])) / 4;
outImgIdx++; outImgIdx++;
topRowIdx = topRowIdx + 2; topRowIdx = topRowIdx + 2;
bottomRowIdx = bottomRowIdx + 2; bottomRowIdx = bottomRowIdx + 2;
@ -521,8 +521,8 @@ export function computeGray(imageData, outArray, config) {
} }
} else { } else {
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
outArray[i] = Math.floor( outArray[i] =
0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2]); 0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2];
} }
} }
}; };

@ -11,6 +11,8 @@ import EAN2Reader from '../reader/ean_2_reader';
import EAN5Reader from '../reader/ean_5_reader'; import EAN5Reader from '../reader/ean_5_reader';
import UPCEReader from '../reader/upc_e_reader'; import UPCEReader from '../reader/upc_e_reader';
import I2of5Reader from '../reader/i2of5_reader'; import I2of5Reader from '../reader/i2of5_reader';
import TwoOfFiveReader from '../reader/2of5_reader';
import Code93Reader from '../reader/code_93_reader';
const READERS = { const READERS = {
code_128_reader: Code128Reader, code_128_reader: Code128Reader,
@ -23,7 +25,9 @@ const READERS = {
codabar_reader: CodabarReader, codabar_reader: CodabarReader,
upc_reader: UPCReader, upc_reader: UPCReader,
upc_e_reader: UPCEReader, upc_e_reader: UPCEReader,
i2of5_reader: I2of5Reader i2of5_reader: I2of5Reader,
'2of5_reader': TwoOfFiveReader,
code_93_reader: Code93Reader
}; };
export default { export default {
create: function(config, inputImageWrapper) { create: function(config, inputImageWrapper) {

@ -14,7 +14,7 @@ function waitForVideo(video) {
function checkVideo() { function checkVideo() {
if (attempts > 0) { if (attempts > 0) {
if (video.videoWidth > 0 && video.videoHeight > 0) { if (video.videoWidth > 10 && video.videoHeight > 10) {
if (ENV.development) { if (ENV.development) {
console.log(video.videoWidth + "px x " + video.videoHeight + "px"); console.log(video.videoWidth + "px x " + video.videoHeight + "px");
} }
@ -42,7 +42,9 @@ function initCamera(video, constraints) {
.then((stream) => { .then((stream) => {
return new Promise((resolve) => { return new Promise((resolve) => {
streamRef = stream; streamRef = stream;
video.setAttribute("autoplay", 'true'); video.setAttribute("autoplay", true);
video.setAttribute('muted', true);
video.setAttribute('playsinline', true);
video.srcObject = stream; video.srcObject = stream;
video.addEventListener('loadedmetadata', () => { video.addEventListener('loadedmetadata', () => {
video.play(); video.play();
@ -87,6 +89,15 @@ function enumerateVideoDevices() {
.then(devices => devices.filter(device => device.kind === 'videoinput')); .then(devices => devices.filter(device => device.kind === 'videoinput'));
} }
function getActiveTrack() {
if (streamRef) {
const tracks = streamRef.getVideoTracks();
if (tracks && tracks.length) {
return tracks[0];
}
}
}
export default { export default {
request: function(video, videoConstraints) { request: function(video, videoConstraints) {
return pickConstraints(videoConstraints) return pickConstraints(videoConstraints)
@ -101,11 +112,8 @@ export default {
}, },
enumerateVideoDevices, enumerateVideoDevices,
getActiveStreamLabel: function() { getActiveStreamLabel: function() {
if (streamRef) { const track = getActiveTrack();
const tracks = streamRef.getVideoTracks(); return track ? track.label : '';
if (tracks && tracks.length) { },
return tracks[0].label; getActiveTrack
}
}
}
}; };

@ -0,0 +1,257 @@
import BarcodeReader from './barcode_reader';
function TwoOfFiveReader(opts) {
BarcodeReader.call(this, opts);
this.barSpaceRatio = [1, 1];
}
var N = 1,
W = 3,
properties = {
START_PATTERN: {value: [W, N, W, N, N, N]},
STOP_PATTERN: {value: [W, N, N, N, W]},
CODE_PATTERN: {value: [
[N, N, W, W, N],
[W, N, N, N, W],
[N, W, N, N, W],
[W, W, N, N, N],
[N, N, W, N, W],
[W, N, W, N, N],
[N, W, W, N, N],
[N, N, N, W, W],
[W, N, N, W, N],
[N, W, N, W, N]
]},
SINGLE_CODE_ERROR: {value: 0.78, writable: true},
AVG_CODE_ERROR: {value: 0.30, writable: true},
FORMAT: {value: "2of5"}
};
const startPatternLength = properties.START_PATTERN.value.reduce((sum, val) => sum + val, 0);
TwoOfFiveReader.prototype = Object.create(BarcodeReader.prototype, properties);
TwoOfFiveReader.prototype.constructor = TwoOfFiveReader;
TwoOfFiveReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder) {
var counter = [],
self = this,
i,
counterPos = 0,
bestMatch = {
error: Number.MAX_VALUE,
code: -1,
start: 0,
end: 0
},
error,
j,
sum,
epsilon = self.AVG_CODE_ERROR;
isWhite = isWhite || false;
tryHarder = tryHarder || false;
if (!offset) {
offset = self._nextSet(self._row);
}
for ( i = 0; i < pattern.length; i++) {
counter[i] = 0;
}
for ( i = offset; i < self._row.length; i++) {
if (self._row[i] ^ isWhite) {
counter[counterPos]++;
} else {
if (counterPos === counter.length - 1) {
sum = 0;
for ( j = 0; j < counter.length; j++) {
sum += counter[j];
}
error = self._matchPattern(counter, pattern);
if (error < epsilon) {
bestMatch.error = error;
bestMatch.start = i - sum;
bestMatch.end = i;
return bestMatch;
}
if (tryHarder) {
for (j = 0; j < counter.length - 2; j++) {
counter[j] = counter[j + 2];
}
counter[counter.length - 2] = 0;
counter[counter.length - 1] = 0;
counterPos--;
} else {
return null;
}
} else {
counterPos++;
}
counter[counterPos] = 1;
isWhite = !isWhite;
}
}
return null;
};
TwoOfFiveReader.prototype._findStart = function() {
var self = this,
leadingWhitespaceStart,
offset = self._nextSet(self._row),
startInfo,
narrowBarWidth = 1;
while (!startInfo) {
startInfo = self._findPattern(self.START_PATTERN, offset, false, true);
if (!startInfo) {
return null;
}
narrowBarWidth = Math.floor((startInfo.end - startInfo.start) / startPatternLength);
leadingWhitespaceStart = startInfo.start - narrowBarWidth * 5;
if (leadingWhitespaceStart >= 0) {
if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
return startInfo;
}
}
offset = startInfo.end;
startInfo = null;
}
};
TwoOfFiveReader.prototype._verifyTrailingWhitespace = function(endInfo) {
var self = this,
trailingWhitespaceEnd;
trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
if (trailingWhitespaceEnd < self._row.length) {
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
return endInfo;
}
}
return null;
};
TwoOfFiveReader.prototype._findEnd = function() {
var self = this,
endInfo,
tmp,
offset;
self._row.reverse();
offset = self._nextSet(self._row);
endInfo = self._findPattern(self.STOP_PATTERN, offset, false, true);
self._row.reverse();
if (endInfo === null) {
return null;
}
// reverse numbers
tmp = endInfo.start;
endInfo.start = self._row.length - endInfo.end;
endInfo.end = self._row.length - tmp;
return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
};
TwoOfFiveReader.prototype._decodeCode = function(counter) {
var j,
self = this,
sum = 0,
normalized,
error,
epsilon = self.AVG_CODE_ERROR,
code,
bestMatch = {
error: Number.MAX_VALUE,
code: -1,
start: 0,
end: 0
};
for ( j = 0; j < counter.length; j++) {
sum += counter[j];
}
for (code = 0; code < self.CODE_PATTERN.length; code++) {
error = self._matchPattern(counter, self.CODE_PATTERN[code]);
if (error < bestMatch.error) {
bestMatch.code = code;
bestMatch.error = error;
}
}
if (bestMatch.error < epsilon) {
return bestMatch;
}
};
TwoOfFiveReader.prototype._decodePayload = function(counters, result, decodedCodes) {
var i,
self = this,
pos = 0,
counterLength = counters.length,
counter = [0, 0, 0, 0, 0],
code;
while (pos < counterLength) {
for (i = 0; i < 5; i++) {
counter[i] = counters[pos] * this.barSpaceRatio[0];
pos += 2;
}
code = self._decodeCode(counter);
if (!code) {
return null;
}
result.push(code.code + "");
decodedCodes.push(code);
}
return code;
};
TwoOfFiveReader.prototype._verifyCounterLength = function(counters) {
return (counters.length % 10 === 0);
};
TwoOfFiveReader.prototype._decode = function() {
var startInfo,
endInfo,
self = this,
code,
result = [],
decodedCodes = [],
counters;
startInfo = self._findStart();
if (!startInfo) {
return null;
}
decodedCodes.push(startInfo);
endInfo = self._findEnd();
if (!endInfo) {
return null;
}
counters = self._fillCounters(startInfo.end, endInfo.start, false);
if (!self._verifyCounterLength(counters)) {
return null;
}
code = self._decodePayload(counters, result, decodedCodes);
if (!code) {
return null;
}
if (result.length < 5) {
return null;
}
decodedCodes.push(endInfo);
return {
code: result.join(""),
start: startInfo.start,
end: endInfo.end,
startInfo: startInfo,
decodedCodes: decodedCodes
};
};
export default TwoOfFiveReader;

@ -1,3 +1,5 @@
import ArrayHelper from '../common/array_helper';
function BarcodeReader(config, supplements) { function BarcodeReader(config, supplements) {
this._row = []; this._row = [];
this.config = config || {}; this.config = config || {};
@ -195,6 +197,33 @@ BarcodeReader.prototype._fillCounters = function(offset, end, isWhite) {
return counters; return counters;
}; };
BarcodeReader.prototype._toCounters = function(start, counter) {
var self = this,
numCounters = counter.length,
end = self._row.length,
isWhite = !self._row[start],
i,
counterPos = 0;
ArrayHelper.init(counter, 0);
for ( i = start; i < end; i++) {
if (self._row[i] ^ isWhite) {
counter[counterPos]++;
} else {
counterPos++;
if (counterPos === numCounters) {
break;
} else {
counter[counterPos] = 1;
isWhite = !isWhite;
}
}
}
return counter;
};
Object.defineProperty(BarcodeReader.prototype, "FORMAT", { Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
value: 'unknown', value: 'unknown',
writeable: false writeable: false

@ -20,33 +20,6 @@ var properties = {
Code39Reader.prototype = Object.create(BarcodeReader.prototype, properties); Code39Reader.prototype = Object.create(BarcodeReader.prototype, properties);
Code39Reader.prototype.constructor = Code39Reader; Code39Reader.prototype.constructor = Code39Reader;
Code39Reader.prototype._toCounters = function(start, counter) {
var self = this,
numCounters = counter.length,
end = self._row.length,
isWhite = !self._row[start],
i,
counterPos = 0;
ArrayHelper.init(counter, 0);
for ( i = start; i < end; i++) {
if (self._row[i] ^ isWhite) {
counter[counterPos]++;
} else {
counterPos++;
if (counterPos === numCounters) {
break;
} else {
counter[counterPos] = 1;
isWhite = !isWhite;
}
}
}
return counter;
};
Code39Reader.prototype._decode = function() { Code39Reader.prototype._decode = function() {
var self = this, var self = this,
counters = [0, 0, 0, 0, 0, 0, 0, 0, 0], counters = [0, 0, 0, 0, 0, 0, 0, 0, 0],

@ -0,0 +1,251 @@
import BarcodeReader from './barcode_reader';
import ArrayHelper from '../common/array_helper';
function Code93Reader() {
BarcodeReader.call(this);
}
const ALPHABETH_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*";
var properties = {
ALPHABETH_STRING: {value: ALPHABETH_STRING},
ALPHABET: {value: ALPHABETH_STRING.split('').map(char => char.charCodeAt(0))},
CHARACTER_ENCODINGS: {value: [
0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A,
0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134,
0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6,
0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, 0x12E, 0x1D4, 0x1D2, 0x1CA,
0x16E, 0x176, 0x1AE, 0x126, 0x1DA, 0x1D6, 0x132, 0x15E
]},
ASTERISK: {value: 0x15E},
FORMAT: {value: "code_93", writeable: false}
};
Code93Reader.prototype = Object.create(BarcodeReader.prototype, properties);
Code93Reader.prototype.constructor = Code93Reader;
Code93Reader.prototype._decode = function() {
var self = this,
counters = [0, 0, 0, 0, 0, 0],
result = [],
start = self._findStart(),
decodedChar,
lastStart,
pattern,
nextStart;
if (!start) {
return null;
}
nextStart = self._nextSet(self._row, start.end);
do {
counters = self._toCounters(nextStart, counters);
pattern = self._toPattern(counters);
if (pattern < 0) {
return null;
}
decodedChar = self._patternToChar(pattern);
if (decodedChar < 0){
return null;
}
result.push(decodedChar);
lastStart = nextStart;
nextStart += ArrayHelper.sum(counters);
nextStart = self._nextSet(self._row, nextStart);
} while (decodedChar !== '*');
result.pop();
if (!result.length) {
return null;
}
if (!self._verifyEnd(lastStart, nextStart, counters)) {
return null;
}
if (!self._verifyChecksums(result)) {
return null;
}
result = result.slice(0, result.length - 2);
if ((result = self._decodeExtended(result)) === null) {
return null;
};
return {
code: result.join(""),
start: start.start,
end: nextStart,
startInfo: start,
decodedCodes: result
};
};
Code93Reader.prototype._verifyEnd = function(lastStart, nextStart) {
if (lastStart === nextStart || !this._row[nextStart]) {
return false;
}
return true;
};
Code93Reader.prototype._patternToChar = function(pattern) {
var i,
self = this;
for (i = 0; i < self.CHARACTER_ENCODINGS.length; i++) {
if (self.CHARACTER_ENCODINGS[i] === pattern) {
return String.fromCharCode(self.ALPHABET[i]);
}
}
return -1;
};
Code93Reader.prototype._toPattern = function(counters) {
const numCounters = counters.length;
let pattern = 0;
let sum = 0;
for (let i = 0; i < numCounters; i++) {
sum += counters[i];
}
for (let i = 0; i < numCounters; i++) {
let normalized = Math.round(counters[i] * 9 / sum);
if (normalized < 1 || normalized > 4) {
return -1;
}
if ((i & 1) === 0) {
for (let j = 0; j < normalized; j++) {
pattern = (pattern << 1) | 1;
}
} else {
pattern <<= normalized;
}
}
return pattern;
};
Code93Reader.prototype._findStart = function() {
var self = this,
offset = self._nextSet(self._row),
patternStart = offset,
counter = [0, 0, 0, 0, 0, 0],
counterPos = 0,
isWhite = false,
i,
j,
whiteSpaceMustStart;
for ( i = offset; i < self._row.length; i++) {
if (self._row[i] ^ isWhite) {
counter[counterPos]++;
} else {
if (counterPos === counter.length - 1) {
// find start pattern
if (self._toPattern(counter) === self.ASTERISK) {
whiteSpaceMustStart = Math.floor(Math.max(0, patternStart - ((i - patternStart) / 4)));
if (self._matchRange(whiteSpaceMustStart, patternStart, 0)) {
return {
start: patternStart,
end: i
};
}
}
patternStart += counter[0] + counter[1];
for ( j = 0; j < 4; j++) {
counter[j] = counter[j + 2];
}
counter[4] = 0;
counter[5] = 0;
counterPos--;
} else {
counterPos++;
}
counter[counterPos] = 1;
isWhite = !isWhite;
}
}
return null;
};
Code93Reader.prototype._decodeExtended = function(charArray) {
const length = charArray.length;
const result = [];
for (let i = 0; i < length; i++) {
const char = charArray[i];
if (char >= 'a' && char <= 'd') {
if (i > (length - 2)) {
return null;
}
const nextChar = charArray[++i];
const nextCharCode = nextChar.charCodeAt(0);
let decodedChar;
switch (char) {
case 'a':
if (nextChar >= 'A' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(nextCharCode - 64);
} else {
return null;
}
break;
case 'b':
if (nextChar >= 'A' && nextChar <= 'E') {
decodedChar = String.fromCharCode(nextCharCode - 38);
} else if (nextChar >= 'F' && nextChar <= 'J') {
decodedChar = String.fromCharCode(nextCharCode - 11);
} else if (nextChar >= 'K' && nextChar <= 'O') {
decodedChar = String.fromCharCode(nextCharCode + 16);
} else if (nextChar >= 'P' && nextChar <= 'S') {
decodedChar = String.fromCharCode(nextCharCode + 43);
} else if (nextChar >= 'T' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(127);
} else {
return null;
}
break;
case 'c':
if (nextChar >= 'A' && nextChar <= 'O') {
decodedChar = String.fromCharCode(nextCharCode - 32);
} else if (nextChar === 'Z') {
decodedChar = ':';
} else {
return null;
}
break;
case 'd':
if (nextChar >= 'A' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(nextCharCode + 32);
} else {
return null;
}
break;
}
result.push(decodedChar);
} else {
result.push(char);
}
}
return result;
};
Code93Reader.prototype._verifyChecksums = function(charArray) {
return this._matchCheckChar(charArray, charArray.length - 2, 20)
&& this._matchCheckChar(charArray, charArray.length - 1, 15);
};
Code93Reader.prototype._matchCheckChar = function(charArray, index, maxWeight) {
const arrayToCheck = charArray.slice(0, index);
const length = arrayToCheck.length;
const weightedSums = arrayToCheck.reduce((sum, char, i) => {
const weight = (((i * -1) + (length - 1)) % maxWeight) + 1;
const value = this.ALPHABET.indexOf(char.charCodeAt(0));
return sum + (weight * value);
}, 0);
const checkChar = this.ALPHABET[(weightedSums % 47)];
return checkChar === charArray[index].charCodeAt(0);
};
export default Code93Reader;

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

@ -304,4 +304,78 @@ describe('decodeSingle', function () {
}); });
_runTestSet(testSet, config); _runTestSet(testSet, config);
}); });
describe("2of5", function() {
var config = config = {
inputStream: {
size: 800,
singleChannel: false
},
locator: {
patchSize: "medium",
halfSample: true
},
numOfWorkers: 0,
decoder: {
readers: ["2of5_reader"]
},
locate: true,
src: null
},
testSet = [
{"name": "image-001.jpg", "result": "9577149002"},
{"name": "image-002.jpg", "result": "9577149002"},
{"name": "image-003.jpg", "result": "5776158811"},
{"name": "image-004.jpg", "result": "0463381455"},
{"name": "image-005.jpg", "result": "3261594101"},
{"name": "image-006.jpg", "result": "3261594101"},
{"name": "image-007.jpg", "result": "3261594101"},
{"name": "image-008.jpg", "result": "6730705801"},
{"name": "image-009.jpg", "result": "5776158811"},
{"name": "image-010.jpg", "result": "5776158811"}
];
testSet.forEach(function(sample) {
sample.format = "2of5";
});
_runTestSet(testSet, config);
});
describe("code_93", function() {
var config = config = {
inputStream: {
size: 800,
singleChannel: false
},
locator: {
patchSize: "large",
halfSample: true
},
numOfWorkers: 0,
decoder: {
readers: ["code_93_reader"]
},
locate: true,
src: null
},
testSet = [
{"name": "image-001.jpg", "result": "WIWV8ETQZ1"},
{"name": "image-002.jpg", "result": "EH3C-%GU23RK3"},
{"name": "image-003.jpg", "result": "O308SIHQOXN5SA/PJ"},
{"name": "image-004.jpg", "result": "DG7Q$TV8JQ/EN"},
{"name": "image-005.jpg", "result": "DG7Q$TV8JQ/EN"},
{"name": "image-006.jpg", "result": "O308SIHQOXN5SA/PJ"},
{"name": "image-007.jpg", "result": "VOFD1DB5A.1F6QU"},
{"name": "image-008.jpg", "result": "WIWV8ETQZ1"},
{"name": "image-009.jpg", "result": "4SO64P4X8 U4YUU1T-"},
{"name": "image-010.jpg", "result": "4SO64P4X8 U4YUU1T-"}
];
testSet.forEach(function(sample) {
sample.format = "code_93";
});
_runTestSet(testSet, config);
});
}); });

@ -153,21 +153,6 @@ describe("camera_access", () => {
done(); done();
}); });
}); });
it("should set deviceId if facingMode is set to environment", (done) => {
setDevices([{deviceId: "front", kind: "videoinput", label: "front Facing"},
{deviceId: "back", label: "back Facing", kind: "videoinput"}]);
const givenConstraints = {width: 180, facingMode: "environment"};
return pickConstraints(givenConstraints).then((actualConstraints) => {
expect(actualConstraints.video).to.deep.equal({width: 180, deviceId: "back"});
done();
})
.catch((err) => {
console.log(err);
expect(err).to.equal(null);
done();
});
});
}); });
}); });
}); });

Loading…
Cancel
Save