Codabar support included

gh-pages
Christoph Oberhofer 10 years ago
parent ca64df23d1
commit 6047d14af9

@ -20,6 +20,8 @@ showInMenu: false
<input type="radio" name="reader" value="ean" /> <input type="radio" name="reader" value="ean" />
<label>Code39</label> <label>Code39</label>
<input type="radio" name="reader" value="code_39" /> <input type="radio" name="reader" value="code_39" />
<label>Codabar</label>
<input type="radio" name="reader" value="codabar" />
</fieldset> </fieldset>
</div> </div>
<div id="result_strip"> <div id="result_strip">

@ -437,7 +437,7 @@ define("almond", function(){});
define( define(
'barcode_reader',[],function() { 'barcode_reader',[],function() {
"use strict";
function BarcodeReader() { function BarcodeReader() {
this._row = []; this._row = [];
@ -631,7 +631,7 @@ define(
"./barcode_reader" "./barcode_reader"
], ],
function(BarcodeReader) { function(BarcodeReader) {
"use strict";
function Code128Reader() { function Code128Reader() {
BarcodeReader.call(this); BarcodeReader.call(this);
@ -1079,7 +1079,7 @@ define(
"./barcode_reader" "./barcode_reader"
], ],
function(BarcodeReader) { function(BarcodeReader) {
"use strict";
function EANReader() { function EANReader() {
BarcodeReader.call(this); BarcodeReader.call(this);
@ -1329,7 +1329,7 @@ define(
/* global define */ /* global define */
define('image_loader',[],function() { define('image_loader',[],function() {
"use strict";
var ImageLoader = {}; var ImageLoader = {};
ImageLoader.load = function(directory, callback, offset, size, sequence) { ImageLoader.load = function(directory, callback, offset, size, sequence) {
@ -1393,7 +1393,7 @@ define('image_loader',[],function() {
/* global define */ /* global define */
define('input_stream',["image_loader"], function(ImageLoader) { define('input_stream',["image_loader"], function(ImageLoader) {
"use strict";
var InputStream = {}; var InputStream = {};
InputStream.createVideoStream = function(video) { InputStream.createVideoStream = function(video) {
@ -1659,7 +1659,7 @@ define("typedefs", (function (global) {
/* global define */ /* global define */
define('subImage',["typedefs"], function() { define('subImage',["typedefs"], function() {
"use strict";
/** /**
* Construct representing a part of another {ImageWrapper}. Shares data * Construct representing a part of another {ImageWrapper}. Shares data
@ -1756,7 +1756,7 @@ define('subImage',["typedefs"], function() {
/* global define, vec2 */ /* global define, vec2 */
define('cluster',[],function() { define('cluster',[],function() {
"use strict";
/** /**
* Creates a cluster for grouping similar orientations of datapoints * Creates a cluster for grouping similar orientations of datapoints
@ -4101,7 +4101,7 @@ define("glMatrixAddon", ["glMatrix"], (function (global) {
/* global define */ /* global define */
define('array_helper',[],function() { define('array_helper',[],function() {
"use strict";
return { return {
init : function(arr, val) { init : function(arr, val) {
@ -4188,7 +4188,7 @@ define('array_helper',[],function() {
define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrixAddon, ArrayHelper) { define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrixAddon, ArrayHelper) {
"use strict";
/* /*
* cv_utils.js * cv_utils.js
* Collection of CV functions and libraries * Collection of CV functions and libraries
@ -4738,7 +4738,7 @@ define('image_wrapper',[
], ],
function(SubImage, CVUtils, ArrayHelper) { function(SubImage, CVUtils, ArrayHelper) {
'use strict';
/** /**
* Represents a basic image combining the data and size. * Represents a basic image combining the data and size.
@ -5159,7 +5159,7 @@ define('image_wrapper',[
* http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization * http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization
*/ */
define('tracer',[],function() { define('tracer',[],function() {
"use strict";
var Tracer = { var Tracer = {
searchDirections : [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]], searchDirections : [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]],
@ -5268,7 +5268,7 @@ define('tracer',[],function() {
* http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization * http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization
*/ */
define('rasterizer',["tracer"], function(Tracer) { define('rasterizer',["tracer"], function(Tracer) {
"use strict";
var Rasterizer = { var Rasterizer = {
createContour2D : function() { createContour2D : function() {
@ -5464,7 +5464,7 @@ define('rasterizer',["tracer"], function(Tracer) {
/* global define */ /* global define */
define('skeletonizer',[],function() { define('skeletonizer',[],function() {
"use strict";
/* @preserve ASM BEGIN */ /* @preserve ASM BEGIN */
function Skeletonizer(stdlib, foreign, buffer) { function Skeletonizer(stdlib, foreign, buffer) {
@ -5669,7 +5669,7 @@ define('skeletonizer',[],function() {
/* global define */ /* global define */
define('image_debug',[],function() { define('image_debug',[],function() {
"use strict";
return { return {
drawRect: function(pos, size, ctx, style){ drawRect: function(pos, size, ctx, style){
@ -5698,10 +5698,9 @@ define('image_debug',[],function() {
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, mat2, vec2 */ /* global define, mat2, vec2 */
define('barcode_locator',["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug"], define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug"],
function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug) { function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug) {
var _config, var _config,
_currentImageWrapper, _currentImageWrapper,
_skelImageWrapper, _skelImageWrapper,
@ -6197,7 +6196,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
// rasterrize area by comparing angular similarity; // rasterrize area by comparing angular similarity;
var maxLabel = rasterizeAngularSimilarity(patchesFound); var maxLabel = rasterizeAngularSimilarity(patchesFound);
if (maxLabel <= 1) { if (maxLabel < 1) {
return null; return null;
} }
@ -6218,7 +6217,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
/* global define */ /* global define */
define('bresenham',[],function() { define('bresenham',[],function() {
"use strict";
var Bresenham = {}; var Bresenham = {};
var Slope = { var Slope = {
@ -6424,7 +6423,7 @@ define(
"./array_helper" "./array_helper"
], ],
function(BarcodeReader, ArrayHelper) { function(BarcodeReader, ArrayHelper) {
"use strict";
function Code39Reader() { function Code39Reader() {
BarcodeReader.call(this); BarcodeReader.call(this);
@ -6489,6 +6488,9 @@ define(
return null; return null;
} }
decodedChar = self._patternToChar(pattern); decodedChar = self._patternToChar(pattern);
if (decodedChar < 0){
return null;
}
result.push(decodedChar); result.push(decodedChar);
lastStart = nextStart; lastStart = nextStart;
nextStart += ArrayHelper.sum(counters); nextStart += ArrayHelper.sum(counters);
@ -6618,13 +6620,327 @@ define(
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */ /* global define */
define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_reader'], function(Bresenham, ImageDebug, Code128Reader, EANReader, Code39Reader) { define(
'codabar_reader',[
"./barcode_reader"
],
function(BarcodeReader) {
"use strict";
function CodabarReader() {
BarcodeReader.call(this);
this._counters = [];
}
var properties = {
ALPHABETH_STRING: {value: "0123456789-$:/.+ABCD"},
ALPHABET: {value: [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 36, 58, 47, 46, 43, 65, 66, 67, 68]},
CHARACTER_ENCODINGS: {value: [0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, 0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E]},
START_END: {value: [0x01A, 0x029, 0x00B, 0x00E]},
MIN_ENCODED_CHARS: {value: 4},
MAX_ACCEPTABLE: {value: 2.0},
PADDING: {value: 1.5}
};
CodabarReader.prototype = Object.create(BarcodeReader.prototype, properties);
CodabarReader.prototype.constructor = CodabarReader;
CodabarReader.prototype._decode = function() {
var self = this,
result = [],
start,
decodedChar,
pattern,
nextStart,
end;
self._fillCounters();
start = self._findStart();
if (!start) {
return null;
}
nextStart = start.startCounter;
do {
pattern = self._toPattern(nextStart);
if (pattern < 0) {
return null;
}
decodedChar = self._patternToChar(pattern);
if (decodedChar < 0){
return null;
}
result.push(decodedChar);
nextStart += 8;
if (result.length > 1 && self._isStartEnd(pattern)) {
break;
}
} while(nextStart < self._counters.length);
// verify end
if ((result.length - 2) < self.MIN_ENCODED_CHARS || !self._isStartEnd(pattern)) {
return null;
}
// verify end white space
if (!self._verifyWhitespace(start.startCounter, nextStart - 8)){
return null;
}
if (!self._validateResult(result, start.startCounter)){
return null;
}
nextStart = nextStart > self._counters.length ? self._counters.length : nextStart;
end = start.start + self._sumCounters(start.startCounter, nextStart - 8);
return {
code : result.join(""),
start : start.start,
end : end,
startInfo : start,
decodedCodes : result
};
};
CodabarReader.prototype._verifyWhitespace = function(startCounter, endCounter) {
if ((startCounter - 1 <= 0) || this._counters[startCounter-1] >= (this._calculatePatternLength(startCounter) / 2.0)) {
if ((endCounter + 8 >= this._counters.length) || this._counters[endCounter+7] >= (this._calculatePatternLength(endCounter) / 2.0)) {
return true;
}
}
return false;
};
CodabarReader.prototype._calculatePatternLength = function(offset) {
var i,
sum = 0;
for (i = offset; i < offset + 7; i++) {
sum += this._counters[i];
}
return sum;
};
CodabarReader.prototype._thresholdResultPattern = function(result, startCounter){
var self = this,
categorization = {
space: {
narrow: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE},
wide: {size: 0, counts: 0, min: 0, max: Number.MAX_VALUE}
},
bar: {
narrow: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE},
wide: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE}
}
},
kind,
cat,
i,
j,
pos = startCounter,
pattern;
for (i = 0; i < result.length; i++){
pattern = self._charToPattern(result[i]);
for (j = 6; j >= 0; j--) {
kind = (j & 1) === 2 ? categorization.bar : categorization.space;
cat = (pattern & 1) === 1 ? kind.wide : kind.narrow;
cat.size += self._counters[pos + j];
cat.counts++;
pattern >>= 1;
}
pos += 8;
}
["space", "bar"].forEach(function(key) {
var kind = categorization[key];
kind.wide.min = Math.floor((kind.narrow.size/kind.narrow.counts + kind.wide.size / kind.wide.counts) / 2);
kind.narrow.max = Math.ceil(kind.wide.min);
kind.wide.max = Math.ceil((kind.wide.size * self.MAX_ACCEPTABLE + self.PADDING) / kind.wide.counts);
});
return categorization;
};
CodabarReader.prototype._charToPattern = function(char) {
var self = this,
charCode = char.charCodeAt(0),
i;
for (i = 0; i < self.ALPHABET.length; i++) {
if (self.ALPHABET[i] === charCode){
return self.CHARACTER_ENCODINGS[i];
}
}
return 0x0;
};
CodabarReader.prototype._validateResult = function(result, startCounter) {
var self = this,
thresholds = self._thresholdResultPattern(result, startCounter),
i,
j,
kind,
cat,
size,
pos = startCounter,
pattern;
for (i = 0; i < result.length; i++) {
pattern = self._charToPattern(result[i]);
for (j = 6; j >= 0; j--) {
kind = (j & 1) === 0 ? thresholds.bar : thresholds.space;
cat = (pattern & 1) === 1 ? kind.wide : kind.narrow;
size = self._counters[pos + j];
if (size < cat.min || size > cat.max) {
return false;
}
pattern >>= 1;
}
pos += 8;
}
return true;
};
CodabarReader.prototype._fillCounters = function() {
var self = this,
counterPos = 0,
isWhite = true,
offset = self._nextUnset(self._row),
i;
self._counters.length = 0;
self._counters[counterPos] = 0;
for (i = offset; i < self._row.length; i++) {
if (self._row[i] ^ isWhite) {
this._counters[counterPos]++;
} else {
counterPos++;
this._counters[counterPos] = 1;
isWhite = !isWhite;
}
}
};
CodabarReader.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;
};
CodabarReader.prototype._computeAlternatingThreshold = function(offset, end) {
var i,
min = Number.MAX_VALUE,
max = 0,
counter;
for (i = offset; i < end; i += 2){
counter = this._counters[i];
if (counter > max) {
max = counter;
}
if (counter < min) {
min = counter;
}
}
return ((min + max) / 2.0) | 0;
};
CodabarReader.prototype._toPattern = function(offset) {
var numCounters = 7,
end = offset + numCounters,
barThreshold,
spaceThreshold,
bitmask = 1 << (numCounters - 1),
pattern = 0,
i,
threshold;
if (end > this._counters.length) {
return -1;
}
barThreshold = this._computeAlternatingThreshold(offset, end);
spaceThreshold = this._computeAlternatingThreshold(offset + 1, end);
for (i = 0; i < numCounters; i++){
threshold = (i & 1) === 0 ? barThreshold : spaceThreshold;
if (this._counters[offset + i] > threshold) {
pattern |= bitmask;
}
bitmask >>= 1;
}
return pattern;
};
CodabarReader.prototype._isStartEnd = function(pattern) {
var i;
for (i = 0; i < this.START_END.length; i++) {
if (this.START_END[i] === pattern) {
return true;
}
}
return false;
};
CodabarReader.prototype._sumCounters = function(start, end) {
var i,
sum = 0;
for (i = start; i < end; i++) {
sum += this._counters[i];
}
return sum;
};
CodabarReader.prototype._findStart = function() {
var self = this,
i,
pattern,
start = self._nextUnset(self._row),
end;
for (i = 1; i < this._counters.length; i++) {
pattern = self._toPattern(i);
if (pattern !== -1 && self._isStartEnd(pattern)) {
// TODO: Look for whitespace ahead
start += self._sumCounters(0, i);
end = start + self._sumCounters(i, i + 8);
return {
start: start,
end: end,
startCounter: i,
endCounter: i + 8
};
}
}
};
return (CodabarReader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_reader', 'codabar_reader'], function(Bresenham, ImageDebug, Code128Reader, EANReader, Code39Reader, CodabarReader) {
"use strict";
var readers = { var readers = {
code_128_reader: Code128Reader, code_128_reader: Code128Reader,
ean_reader: EANReader, ean_reader: EANReader,
code_39_reader: Code39Reader code_39_reader: Code39Reader,
codabar_reader: CodabarReader
}; };
var BarcodeDecoder = { var BarcodeDecoder = {
create : function(config, inputImageWrapper) { create : function(config, inputImageWrapper) {
@ -6877,7 +7193,7 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
/* global define */ /* global define */
define('frame_grabber',["cv_utils"], function(CVUtils) { define('frame_grabber',["cv_utils"], function(CVUtils) {
"use strict";
var FrameGrabber = {}; var FrameGrabber = {};
@ -6970,7 +7286,7 @@ define('frame_grabber',["cv_utils"], function(CVUtils) {
/* global define */ /* global define */
define('html_utils',[], function() { define('html_utils',[], function() {
"use strict";
function createNode(htmlStr) { function createNode(htmlStr) {
var temp = document.createElement('div'); var temp = document.createElement('div');
@ -7060,7 +7376,7 @@ define('config',[],function(){
/* global define */ /* global define */
define('events',[],function() { define('events',[],function() {
"use strict";
var _events = function() { var _events = function() {
var events = {}; var events = {};
@ -7151,7 +7467,7 @@ define('events',[],function() {
/* global define, MediaStreamTrack */ /* global define, MediaStreamTrack */
define('camera_access',["html_utils"], function(HtmlUtils) { define('camera_access',["html_utils"], function(HtmlUtils) {
"use strict";
var streamRef; var streamRef;
/** /**
@ -7282,7 +7598,7 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
define('quagga',["code_128_reader", "ean_reader", "input_stream", "image_wrapper", "barcode_locator", "barcode_decoder", "frame_grabber", "html_utils", "config", "events", "camera_access", "image_debug"], define('quagga',["code_128_reader", "ean_reader", "input_stream", "image_wrapper", "barcode_locator", "barcode_decoder", "frame_grabber", "html_utils", "config", "events", "camera_access", "image_debug"],
function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, BarcodeDecoder, FrameGrabber, HtmlUtils, _config, Events, CameraAccess, ImageDebug) { function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, BarcodeDecoder, FrameGrabber, HtmlUtils, _config, Events, CameraAccess, ImageDebug) {
"use strict";
var _inputStream, var _inputStream,
_framegrabber, _framegrabber,

File diff suppressed because one or more lines are too long

@ -19,6 +19,8 @@ showInMenu: false
<input type="radio" name="reader" value="ean" /> <input type="radio" name="reader" value="ean" />
<label>Code39</label> <label>Code39</label>
<input type="radio" name="reader" value="code_39" /> <input type="radio" name="reader" value="code_39" />
<label>Codabar</label>
<input type="radio" name="reader" value="codabar" />
</fieldset> </fieldset>
<br clear="all" /> <br clear="all" />
</div> </div>

@ -22,6 +22,8 @@ showInMenu: false
<input type="radio" name="reader" value="ean" /> <input type="radio" name="reader" value="ean" />
<label>Code39</label> <label>Code39</label>
<input type="radio" name="reader" value="code_39" /> <input type="radio" name="reader" value="code_39" />
<label>Codabar</label>
<input type="radio" name="reader" value="codabar" />
</fieldset> </fieldset>
</div> </div>
<div id="result_strip"> <div id="result_strip">

@ -7,16 +7,16 @@ showInMenu: true
quaggaJS quaggaJS
======== ========
- [Changelog](#changelog) (2015-03-16) - [Changelog](#changelog) (2015-04-16)
## 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__,
__CODE128__ and __CODE39__. The library is also capable of using `getUserMedia` __CODE128__, __CODE39__ and __CODABAR__. The library is also capable of using
to get direct access to the user's camera stream. Although the code relies on `getUserMedia` to get direct access to the user's camera stream. Although the
heavy image-processing even recent smartphones are capable of locating and code relies on heavy image-processing even recent smartphones are capable of
decoding barcodes in real-time. locating and decoding barcodes in real-time.
Try some [examples](http://serratus.github.io/quaggaJS/examples) and check out Try some [examples](http://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])
@ -297,6 +297,10 @@ work.
## <a name="changelog">Changelog</a> ## <a name="changelog">Changelog</a>
### 2015-04-16
- Features
- Added support for [Codabar][codabar_wiki] barcodes
### 2015-03-16 ### 2015-03-16
- Improvements - Improvements
- now includes minified version (23.3KB gzipped) - now includes minified version (23.3KB gzipped)
@ -340,5 +344,6 @@ introduced to the API.
[mochaUrl]: https://github.com/mochajs/mocha [mochaUrl]: https://github.com/mochajs/mocha
[karmaUrl]: http://karma-runner.github.io/ [karmaUrl]: http://karma-runner.github.io/
[code39_wiki]: http://en.wikipedia.org/wiki/Code_39 [code39_wiki]: http://en.wikipedia.org/wiki/Code_39
[codabar_wiki]: http://en.wikipedia.org/wiki/Codabar
[oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/ [oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/
[github_examples]: http://serratus.github.io/quaggaJS/examples [github_examples]: http://serratus.github.io/quaggaJS/examples

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Loading…
Cancel
Save