diff --git a/README.md b/README.md
index ccf7280..54b7981 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,17 @@
quaggaJS
========
-- [Changelog](#changelog) (2015-07-08)
+- [Changelog](#changelog) (2015-08-13)
## What is QuaggaJS?
QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real-
time localization and decoding of various types of barcodes such as __EAN__,
-__CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__ and __CODABAR__.
-The library is also capable of using `getUserMedia` to get direct access to
-the user's camera stream. Although the code relies on heavy image-processing
-even recent smartphones are capable of locating and decoding barcodes in
-real-time.
+__CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__, __I2of5__ and
+__CODABAR__. The library is also capable of using `getUserMedia` to get direct
+access to the user's camera stream. Although the code relies on heavy image-
+processing even recent smartphones are capable of locating and decoding
+barcodes in real-time.
Try some [examples](http://serratus.github.io/quaggaJS/examples) and check out
the blog post ([How barcode-localization works in QuaggaJS][oberhofer_co_how])
@@ -141,6 +141,16 @@ In contrast to the calls described above, this method does not rely on
`getUserMedia` and operates on a single image instead. The provided callback
is the same as in `onDetected` and contains the result `data` object.
+### Quagga.offProcessed(handler)
+
+In case the `onProcessed` event is no longer relevant, `offProcessed` removes
+the given `handler` from the event-queue.
+
+### Quagga.offDetected(handler)
+
+In case the `onDetected` event is no longer relevant, `offDetected` removes
+the given `handler` from the event-queue.
+
## The result object
The callbacks passed into `onProcessed`, `onDetected` and `decodeSingle`
@@ -367,6 +377,15 @@ on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.
## Changelog
+### 2015-08-13
+- Improvements
+ - Added `offProcessed` and `offDetected` methods for detaching event-
+ listeners from the event-queue.
+
+### 2015-07-29
+- Features
+ - Added basic support for [ITF][i2of5_wiki] barcodes (`i2of5_reader`)
+
### 2015-07-08
- Improvements
- Parameter tweaking to reduce false-positives significantly (for the
@@ -479,3 +498,4 @@ introduced to the API.
[ean_8_wiki]: http://en.wikipedia.org/wiki/EAN-8
[oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/
[github_examples]: http://serratus.github.io/quaggaJS/examples
+[i2of5_wiki]: https://en.wikipedia.org/wiki/Interleaved_2_of_5
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..e563ced
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,68 @@
+{
+ "name": "quagga",
+ "version": "0.6.14",
+ "description": "An advanced barcode-scanner written in JavaScript",
+ "main": "dist/quagga.js",
+ "ignore": [
+ "build",
+ "doc",
+ "spec",
+ "src",
+ "tasks",
+ "test",
+ ".gitignore",
+ ".npmignore",
+ "Gruntfile.js",
+ "karma-integration.conf.js",
+ "karma.conf.js",
+ "package.json",
+ "test-main.js"
+ ],
+ "devDependencies": {
+ "async": "^0.9.0",
+ "grunt": "~0.4.5",
+ "grunt-contrib-jshint": "~0.10.0",
+ "grunt-contrib-nodeunit": "~0.4.1",
+ "grunt-contrib-uglify": "~0.5.0",
+ "grunt-karma": "^0.9.0",
+ "grunt-requirejs": "^0.4.2",
+ "karma": "latest",
+ "karma-chai": "latest",
+ "karma-chrome-launcher": "^0.1.12",
+ "karma-coverage": "^0.3.1",
+ "karma-mocha": "latest",
+ "karma-phantomjs-launcher": "^0.1.4",
+ "karma-requirejs": "^0.2.2",
+ "karma-sinon": "^1.0.4",
+ "karma-sinon-chai": "^0.2.0",
+ "sinon": "^1.12.1"
+ },
+ "directories": {
+ "doc": "doc"
+ },
+ "scripts": {
+ "test": "karma start"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/serratus/quaggaJS.git"
+ },
+ "bugs": {
+ "url": "https://github.com/serratus/quaggaJS/issues"
+ },
+ "keywords": [
+ "quagga",
+ "quaggajs",
+ "barcode",
+ "ean",
+ "code128",
+ "code39",
+ "codabar",
+ "i2of5",
+ "upc",
+ "getusermedia",
+ "imageprocessing"
+ ],
+ "author": "Christoph Oberhofer ",
+ "license": "MIT"
+}
diff --git a/dist/quagga.js b/dist/quagga.js
index a2db04c..95f9cb4 100644
--- a/dist/quagga.js
+++ b/dist/quagga.js
@@ -435,1356 +435,931 @@ define("almond", function(){});
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
-define(
- 'barcode_reader',[],function() {
- "use strict";
-
- function BarcodeReader() {
- this._row = [];
- return this;
- }
-
- BarcodeReader.prototype._nextUnset = function(line, start) {
- var i;
+define('image_loader',[],function() {
+ "use strict";
+
+ var ImageLoader = {};
+ ImageLoader.load = function(directory, callback, offset, size, sequence) {
+ var htmlImagesSrcArray = new Array(size),
+ htmlImagesArray = new Array(htmlImagesSrcArray.length),
+ i,
+ img,
+ num;
- if (start === undefined) {
- start = 0;
+ if (sequence === false) {
+ htmlImagesSrcArray[0] = directory;
+ } else {
+ for ( i = 0; i < htmlImagesSrcArray.length; i++) {
+ num = (offset + i);
+ htmlImagesSrcArray[i] = directory + "image-" + ("00" + num).slice(-3) + ".jpg";
}
- for (i = start; i < line.length; i++) {
- if (!line[i]) {
- return i;
+ }
+ htmlImagesArray.notLoaded = [];
+ htmlImagesArray.addImage = function(img) {
+ htmlImagesArray.notLoaded.push(img);
+ };
+ htmlImagesArray.loaded = function(loadedImg) {
+ var notloadedImgs = htmlImagesArray.notLoaded;
+ for (var x = 0; x < notloadedImgs.length; x++) {
+ if (notloadedImgs[x] == loadedImg) {
+ notloadedImgs.splice(x, 1);
+ for (var y = 0; y < htmlImagesSrcArray.length; y++) {
+ var imgName = htmlImagesSrcArray[y].substr(htmlImagesSrcArray[y].lastIndexOf("/"));
+ if (loadedImg.src.lastIndexOf(imgName) != -1) {
+ htmlImagesArray[y] = loadedImg;
+ break;
+ }
+ }
+ break;
}
}
- return line.length;
+ if (notloadedImgs.length === 0) {
+ console.log("Images loaded");
+ callback.apply(null, [htmlImagesArray]);
+ }
};
- BarcodeReader.prototype._matchPattern = function(counter, code) {
- var i,
- error = 0,
- singleError = 0,
- modulo = this.MODULO,
- maxSingleError = this.SINGLE_CODE_ERROR || 1;
-
- for (i = 0; i < counter.length; i++) {
- singleError = Math.abs(code[i] - counter[i]);
- if (singleError > maxSingleError) {
- return Number.MAX_VALUE;
- }
- error += singleError;
- }
- return error/modulo;
+ for ( i = 0; i < htmlImagesSrcArray.length; i++) {
+ img = new Image();
+ htmlImagesArray.addImage(img);
+ addOnloadHandler(img, htmlImagesArray);
+ img.src = htmlImagesSrcArray[i];
+ }
+ };
+
+ function addOnloadHandler(img, htmlImagesArray) {
+ img.onload = function() {
+ htmlImagesArray.loaded(this);
};
+ }
- BarcodeReader.prototype._nextSet = function(line, offset) {
- var i;
+ return (ImageLoader);
+});
- offset = offset || 0;
- for (i = offset; i < line.length; i++) {
- if (line[i]) {
- return i;
- }
- }
- return line.length;
- };
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
- BarcodeReader.prototype._normalize = function(counter, modulo) {
- var i,
- self = this,
- sum = 0,
- ratio,
- numOnes = 0,
- normalized = [],
- norm = 0;
-
- if (!modulo) {
- modulo = self.MODULO;
- }
- for (i = 0; i < counter.length; i++) {
- if (counter[i] === 1) {
- numOnes++;
- } else {
- sum += counter[i];
- }
- }
- ratio = sum / (modulo - numOnes);
- if (ratio > 1.0) {
- for (i = 0; i < counter.length; i++) {
- norm = counter[i] === 1 ? counter[i] : counter[i] / ratio;
- normalized.push(norm);
- }
- } else {
- ratio = (sum + numOnes)/modulo;
- for (i = 0; i < counter.length; i++) {
- norm = counter[i] / ratio;
- normalized.push(norm);
- }
- }
- return normalized;
- };
+define('input_stream',["image_loader"], function(ImageLoader) {
+ "use strict";
- BarcodeReader.prototype._matchTrace = function(cmpCounter, epsilon) {
- var counter = [],
- i,
- self = this,
- offset = self._nextSet(self._row),
- isWhite = !self._row[offset],
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : 0
- },
- error;
+ var InputStream = {};
+ InputStream.createVideoStream = function(video) {
+ var that = {},
+ _config = null,
+ _eventNames = ['canrecord', 'ended'],
+ _eventHandlers = {},
+ _calculatedWidth,
+ _calculatedHeight,
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
- if (cmpCounter) {
- for ( i = 0; i < cmpCounter.length; i++) {
- counter.push(0);
- }
- for ( i = offset; i < self._row.length; i++) {
- if (self._row[i] ^ isWhite) {
- counter[counterPos]++;
- } else {
- if (counterPos === counter.length - 1) {
- error = self._matchPattern(counter, cmpCounter);
+ function initSize() {
+ var width = video.videoWidth,
+ height = video.videoHeight;
- if (error < epsilon) {
- bestMatch.start = i - offset;
- bestMatch.end = i;
- bestMatch.counter = counter;
- return bestMatch;
- } else {
- return null;
- }
- } else {
- counterPos++;
- }
- counter[counterPos] = 1;
- isWhite = !isWhite;
- }
- }
- } else {
- counter.push(0);
- for ( i = offset; i < self._row.length; i++) {
- if (self._row[i] ^ isWhite) {
- counter[counterPos]++;
- } else {
- counterPos++;
- counter.push(0);
- counter[counterPos] = 1;
- isWhite = !isWhite;
- }
- }
- }
+ _calculatedWidth = _config.size ? width/height > 1 ? _config.size : Math.floor((width/height) * _config.size) : width;
+ _calculatedHeight = _config.size ? width/height > 1 ? Math.floor((height/width) * _config.size) : _config.size : height;
- // if cmpCounter was not given
- bestMatch.start = offset;
- bestMatch.end = self._row.length - 1;
- bestMatch.counter = counter;
- return bestMatch;
- };
-
- BarcodeReader.prototype.decodePattern = function(pattern) {
- var self = this,
- result;
-
- self._row = pattern;
- result = self._decode();
- if (result === null) {
- self._row.reverse();
- result = self._decode();
- if (result) {
- result.direction = BarcodeReader.DIRECTION.REVERSE;
- result.start = self._row.length - result.start;
- result.end = self._row.length - result.end;
- }
- } else {
- result.direction = BarcodeReader.DIRECTION.FORWARD;
- }
- if (result) {
- result.format = self.FORMAT;
- }
- return result;
+ _canvasSize.x = _calculatedWidth;
+ _canvasSize.y = _calculatedHeight;
+ }
+
+ that.getRealWidth = function() {
+ return video.videoWidth;
};
- BarcodeReader.prototype._matchRange = function(start, end, value) {
- var i;
+ that.getRealHeight = function() {
+ return video.videoHeight;
+ };
- start = start < 0 ? 0 : start;
- for (i = start; i < end; i++) {
- if (this._row[i] !== value) {
- return false;
- }
- }
- return true;
+ that.getWidth = function() {
+ return _calculatedWidth;
};
- Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
- value: 'unknown',
- writeable: false
- });
-
- BarcodeReader.DIRECTION = {
- FORWARD : 1,
- REVERSE : -1
+ that.getHeight = function() {
+ return _calculatedHeight;
};
-
- BarcodeReader.Exception = {
- StartNotFoundException : "Start-Info was not found!",
- CodeNotFoundException : "Code could not be found!",
- PatternNotFoundException : "Pattern could not be found!"
+
+ that.setWidth = function(width) {
+ _calculatedWidth = width;
};
-
- return (BarcodeReader);
- }
-);
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
+ that.setHeight = function(height) {
+ _calculatedHeight = height;
+ };
-define(
- 'code_128_reader',[
- "./barcode_reader"
- ],
- function(BarcodeReader) {
- "use strict";
-
- function Code128Reader() {
- BarcodeReader.call(this);
- }
-
- var properties = {
- CODE_SHIFT : {value: 98},
- CODE_C : {value: 99},
- CODE_B : {value: 100},
- CODE_A : {value: 101},
- START_CODE_A : {value: 103},
- START_CODE_B : {value: 104},
- START_CODE_C : {value: 105},
- STOP_CODE : {value: 106},
- MODULO : {value: 11},
- CODE_PATTERN : {value: [
- [2, 1, 2, 2, 2, 2],
- [2, 2, 2, 1, 2, 2],
- [2, 2, 2, 2, 2, 1],
- [1, 2, 1, 2, 2, 3],
- [1, 2, 1, 3, 2, 2],
- [1, 3, 1, 2, 2, 2],
- [1, 2, 2, 2, 1, 3],
- [1, 2, 2, 3, 1, 2],
- [1, 3, 2, 2, 1, 2],
- [2, 2, 1, 2, 1, 3],
- [2, 2, 1, 3, 1, 2],
- [2, 3, 1, 2, 1, 2],
- [1, 1, 2, 2, 3, 2],
- [1, 2, 2, 1, 3, 2],
- [1, 2, 2, 2, 3, 1],
- [1, 1, 3, 2, 2, 2],
- [1, 2, 3, 1, 2, 2],
- [1, 2, 3, 2, 2, 1],
- [2, 2, 3, 2, 1, 1],
- [2, 2, 1, 1, 3, 2],
- [2, 2, 1, 2, 3, 1],
- [2, 1, 3, 2, 1, 2],
- [2, 2, 3, 1, 1, 2],
- [3, 1, 2, 1, 3, 1],
- [3, 1, 1, 2, 2, 2],
- [3, 2, 1, 1, 2, 2],
- [3, 2, 1, 2, 2, 1],
- [3, 1, 2, 2, 1, 2],
- [3, 2, 2, 1, 1, 2],
- [3, 2, 2, 2, 1, 1],
- [2, 1, 2, 1, 2, 3],
- [2, 1, 2, 3, 2, 1],
- [2, 3, 2, 1, 2, 1],
- [1, 1, 1, 3, 2, 3],
- [1, 3, 1, 1, 2, 3],
- [1, 3, 1, 3, 2, 1],
- [1, 1, 2, 3, 1, 3],
- [1, 3, 2, 1, 1, 3],
- [1, 3, 2, 3, 1, 1],
- [2, 1, 1, 3, 1, 3],
- [2, 3, 1, 1, 1, 3],
- [2, 3, 1, 3, 1, 1],
- [1, 1, 2, 1, 3, 3],
- [1, 1, 2, 3, 3, 1],
- [1, 3, 2, 1, 3, 1],
- [1, 1, 3, 1, 2, 3],
- [1, 1, 3, 3, 2, 1],
- [1, 3, 3, 1, 2, 1],
- [3, 1, 3, 1, 2, 1],
- [2, 1, 1, 3, 3, 1],
- [2, 3, 1, 1, 3, 1],
- [2, 1, 3, 1, 1, 3],
- [2, 1, 3, 3, 1, 1],
- [2, 1, 3, 1, 3, 1],
- [3, 1, 1, 1, 2, 3],
- [3, 1, 1, 3, 2, 1],
- [3, 3, 1, 1, 2, 1],
- [3, 1, 2, 1, 1, 3],
- [3, 1, 2, 3, 1, 1],
- [3, 3, 2, 1, 1, 1],
- [3, 1, 4, 1, 1, 1],
- [2, 2, 1, 4, 1, 1],
- [4, 3, 1, 1, 1, 1],
- [1, 1, 1, 2, 2, 4],
- [1, 1, 1, 4, 2, 2],
- [1, 2, 1, 1, 2, 4],
- [1, 2, 1, 4, 2, 1],
- [1, 4, 1, 1, 2, 2],
- [1, 4, 1, 2, 2, 1],
- [1, 1, 2, 2, 1, 4],
- [1, 1, 2, 4, 1, 2],
- [1, 2, 2, 1, 1, 4],
- [1, 2, 2, 4, 1, 1],
- [1, 4, 2, 1, 1, 2],
- [1, 4, 2, 2, 1, 1],
- [2, 4, 1, 2, 1, 1],
- [2, 2, 1, 1, 1, 4],
- [4, 1, 3, 1, 1, 1],
- [2, 4, 1, 1, 1, 2],
- [1, 3, 4, 1, 1, 1],
- [1, 1, 1, 2, 4, 2],
- [1, 2, 1, 1, 4, 2],
- [1, 2, 1, 2, 4, 1],
- [1, 1, 4, 2, 1, 2],
- [1, 2, 4, 1, 1, 2],
- [1, 2, 4, 2, 1, 1],
- [4, 1, 1, 2, 1, 2],
- [4, 2, 1, 1, 1, 2],
- [4, 2, 1, 2, 1, 1],
- [2, 1, 2, 1, 4, 1],
- [2, 1, 4, 1, 2, 1],
- [4, 1, 2, 1, 2, 1],
- [1, 1, 1, 1, 4, 3],
- [1, 1, 1, 3, 4, 1],
- [1, 3, 1, 1, 4, 1],
- [1, 1, 4, 1, 1, 3],
- [1, 1, 4, 3, 1, 1],
- [4, 1, 1, 1, 1, 3],
- [4, 1, 1, 3, 1, 1],
- [1, 1, 3, 1, 4, 1],
- [1, 1, 4, 1, 3, 1],
- [3, 1, 1, 1, 4, 1],
- [4, 1, 1, 1, 3, 1],
- [2, 1, 1, 4, 1, 2],
- [2, 1, 1, 2, 1, 4],
- [2, 1, 1, 2, 3, 2],
- [2, 3, 3, 1, 1, 1, 2]
- ]},
- SINGLE_CODE_ERROR: {value: 1},
- AVG_CODE_ERROR: {value: 0.5},
- FORMAT: {value: "code_128", writeable: false}
+ that.setInputStream = function(config) {
+ _config = config;
+ video.src = (typeof config.src !== 'undefined') ? config.src : '';
};
-
- Code128Reader.prototype = Object.create(BarcodeReader.prototype, properties);
- Code128Reader.prototype.constructor = Code128Reader;
-
- Code128Reader.prototype._decodeCode = function(start) {
- var counter = [0, 0, 0, 0, 0, 0],
- i,
- self = this,
- offset = start,
- isWhite = !self._row[offset],
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : start,
- end : start
- },
- code,
- error,
- normalized;
- for ( i = offset; i < self._row.length; i++) {
- if (self._row[i] ^ isWhite) {
- counter[counterPos]++;
- } else {
- if (counterPos === counter.length - 1) {
- normalized = self._normalize(counter);
- if (normalized) {
- for (code = 0; code < self.CODE_PATTERN.length; code++) {
- error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
- if (error < bestMatch.error) {
- bestMatch.code = code;
- bestMatch.error = error;
- }
- }
- bestMatch.end = i;
- return bestMatch;
- }
- } else {
- counterPos++;
- }
- counter[counterPos] = 1;
- isWhite = !isWhite;
+ that.ended = function() {
+ return video.ended;
+ };
+
+ that.getConfig = function() {
+ return _config;
+ };
+
+ that.setAttribute = function(name, value) {
+ video.setAttribute(name, value);
+ };
+
+ that.pause = function() {
+ video.pause();
+ };
+
+ that.play = function() {
+ video.play();
+ };
+
+ that.setCurrentTime = function(time) {
+ if (_config.type !== "LiveStream")
+ video.currentTime = time;
+ };
+
+ that.addEventListener = function(event, f, bool) {
+ if (_eventNames.indexOf(event) !== -1) {
+ if (!_eventHandlers[event]) {
+ _eventHandlers[event] = [];
}
+ _eventHandlers[event].push(f);
+ } else {
+ video.addEventListener(event, f, bool);
}
- return null;
};
- Code128Reader.prototype._findStart = function() {
- var counter = [0, 0, 0, 0, 0, 0],
- i,
- self = this,
- offset = self._nextSet(self._row),
- isWhite = false,
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : 0,
- end : 0
- },
- code,
- error,
- j,
- sum,
- normalized;
-
- 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];
- }
- normalized = self._normalize(counter);
- if (normalized) {
- for (code = self.START_CODE_A; code <= self.START_CODE_C; code++) {
- error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
- if (error < bestMatch.error) {
- bestMatch.code = code;
- bestMatch.error = error;
- }
- }
- if (bestMatch.error < self.AVG_CODE_ERROR) {
- bestMatch.start = i - sum;
- bestMatch.end = i;
- return bestMatch;
- }
- }
-
- 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;
+ that.clearEventHandlers = function() {
+ _eventNames.forEach(function(eventName) {
+ var handlers = _eventHandlers[eventName];
+ if (handlers && handlers.length > 0) {
+ handlers.forEach(function(handler) {
+ video.removeEventListener(eventName, handler);
+ });
}
- }
- return null;
+ });
};
- Code128Reader.prototype._decode = function() {
- var self = this,
- startInfo = self._findStart(),
- code = null,
- done = false,
- result = [],
- multiplier = 0,
- checksum = 0,
- codeset,
- rawResult = [],
- decodedCodes = [],
- shiftNext = false,
- unshift,
- lastCharacterWasPrintable;
+ that.trigger = function(eventName, args) {
+ var j,
+ handlers = _eventHandlers[eventName];
- if (startInfo === null) {
- return null;
- }
- code = {
- code : startInfo.code,
- start : startInfo.start,
- end : startInfo.end
- };
- decodedCodes.push(code);
- checksum = code.code;
- switch(code.code) {
- case self.START_CODE_A:
- codeset = self.CODE_A;
- break;
- case self.START_CODE_B:
- codeset = self.CODE_B;
- break;
- case self.START_CODE_C:
- codeset = self.CODE_C;
- break;
- default:
- return null;
+ if (eventName === 'canrecord') {
+ initSize();
}
-
- while (!done) {
- unshift = shiftNext;
- shiftNext = false;
- code = self._decodeCode(code.end);
- if (code !== null) {
- if (code.code !== self.STOP_CODE) {
- rawResult.push(code.code);
- multiplier++;
- checksum += multiplier * code.code;
- }
- decodedCodes.push(code);
-
- switch(codeset) {
- case self.CODE_A:
- if (code.code < 64) {
- result.push(String.fromCharCode(32 + code.code));
- } else if (code.code < 96) {
- result.push(String.fromCharCode(code.code - 64));
- } else {
- switch (code.code) {
- case self.CODE_SHIFT:
- shiftNext = true;
- codeset = self.CODE_B;
- break;
- case self.CODE_B:
- codeset = self.CODE_B;
- break;
- case self.CODE_C:
- codeset = self.CODE_C;
- break;
- case self.STOP_CODE:
- done = true;
- break;
- }
- }
- break;
- case self.CODE_B:
- if (code.code < 96) {
- result.push(String.fromCharCode(32 + code.code));
- } else {
- if (code.code != self.STOP_CODE) {
- lastCharacterWasPrintable = false;
- }
- switch (code.code) {
- case self.CODE_SHIFT:
- shiftNext = true;
- codeset = self.CODE_A;
- break;
- case self.CODE_A:
- codeset = self.CODE_A;
- break;
- case self.CODE_C:
- codeset = self.CODE_C;
- break;
- case self.STOP_CODE:
- done = true;
- break;
- }
- }
- break;
- case self.CODE_C:
- if (code.code < 100) {
- result.push(code.code < 10 ? "0" + code.code : code.code);
- }
- switch (code.code) {
- case self.CODE_A:
- codeset = self.CODE_A;
- break;
- case self.CODE_B:
- codeset = self.CODE_B;
- break;
- case self.STOP_CODE:
- done = true;
- break;
- }
- break;
- }
- } else {
- done = true;
- }
- if (unshift) {
- codeset = codeset == self.CODE_A ? self.CODE_B : self.CODE_A;
+ if (handlers && handlers.length > 0) {
+ for ( j = 0; j < handlers.length; j++) {
+ handlers[j].apply(that, args);
}
}
+ };
- if (code === null) {
- return null;
- }
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
+ };
- // find end bar
- code.end = self._nextUnset(self._row, code.end);
- if(!self._verifyTrailingWhitespace(code)){
- return null;
- }
+ that.getTopRight = function() {
+ return _topRight;
+ };
- // checksum
- // Does not work correctly yet!!! startcode - endcode?
- checksum -= multiplier * rawResult[rawResult.length - 1];
- if (checksum % 103 != rawResult[rawResult.length - 1]) {
- return null;
- }
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
+ };
- if (!result.length) {
- return null;
- }
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
- // remove last code from result (checksum)
- result.splice(result.length - 1, 1);
+ that.getFrame = function() {
+ return video;
+ };
+ return that;
+ };
+ InputStream.createLiveStream = function(video) {
+ video.setAttribute("autoplay", true);
+ var that = InputStream.createVideoStream(video);
- return {
- code : result.join(""),
- start : startInfo.start,
- end : code.end,
- codeset : codeset,
- startInfo : startInfo,
- decodedCodes : decodedCodes,
- endInfo : code
- };
+ that.ended = function() {
+ return false;
};
+ return that;
+ };
- BarcodeReader.prototype._verifyTrailingWhitespace = function(endInfo) {
- var self = this,
- trailingWhitespaceEnd;
+ InputStream.createImageStream = function() {
+ var that = {};
+ var _config = null;
- trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
- if (trailingWhitespaceEnd < self._row.length) {
- if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
- return endInfo;
- }
- }
- return null;
- };
-
- return (Code128Reader);
- }
-);
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
+ var width = 0,
+ height = 0,
+ frameIdx = 0,
+ paused = true,
+ loaded = false,
+ imgArray = null,
+ size = 0,
+ offset = 1,
+ baseUrl = null,
+ ended = false,
+ calculatedWidth,
+ calculatedHeight,
+ _eventNames = ['canrecord', 'ended'],
+ _eventHandlers = {},
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
-define(
- 'ean_reader',[
- "./barcode_reader"
- ],
- function(BarcodeReader) {
- "use strict";
-
- function EANReader(opts) {
- BarcodeReader.call(this, opts);
+ function loadImages() {
+ loaded = false;
+ ImageLoader.load(baseUrl, function(imgs) {
+ imgArray = imgs;
+ width = imgs[0].width;
+ height = imgs[0].height;
+ calculatedWidth = _config.size ? width/height > 1 ? _config.size : Math.floor((width/height) * _config.size) : width;
+ calculatedHeight = _config.size ? width/height > 1 ? Math.floor((height/width) * _config.size) : _config.size : height;
+ _canvasSize.x = calculatedWidth;
+ _canvasSize.y = calculatedHeight;
+ loaded = true;
+ frameIdx = 0;
+ setTimeout(function() {
+ publishEvent("canrecord", []);
+ }, 0);
+ }, offset, size, _config.sequence);
}
-
- var properties = {
- CODE_L_START : {value: 0},
- MODULO : {value: 7},
- CODE_G_START : {value: 10},
- START_PATTERN : {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]},
- STOP_PATTERN : {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]},
- MIDDLE_PATTERN : {value: [1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7]},
- CODE_PATTERN : {value: [
- [3, 2, 1, 1],
- [2, 2, 2, 1],
- [2, 1, 2, 2],
- [1, 4, 1, 1],
- [1, 1, 3, 2],
- [1, 2, 3, 1],
- [1, 1, 1, 4],
- [1, 3, 1, 2],
- [1, 2, 1, 3],
- [3, 1, 1, 2],
- [1, 1, 2, 3],
- [1, 2, 2, 2],
- [2, 2, 1, 2],
- [1, 1, 4, 1],
- [2, 3, 1, 1],
- [1, 3, 2, 1],
- [4, 1, 1, 1],
- [2, 1, 3, 1],
- [3, 1, 2, 1],
- [2, 1, 1, 3]
- ]},
- CODE_FREQUENCY : {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
- SINGLE_CODE_ERROR: {value: 0.67},
- AVG_CODE_ERROR: {value: 0.27},
- FORMAT: {value: "ean_13", writeable: false}
- };
-
- EANReader.prototype = Object.create(BarcodeReader.prototype, properties);
- EANReader.prototype.constructor = EANReader;
-
- EANReader.prototype._decodeCode = function(start, coderange) {
- var counter = [0, 0, 0, 0],
- i,
- self = this,
- offset = start,
- isWhite = !self._row[offset],
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : start,
- end : start
- },
- code,
- error,
- normalized;
-
- if (!coderange) {
- coderange = self.CODE_PATTERN.length;
- }
- for ( i = offset; i < self._row.length; i++) {
- if (self._row[i] ^ isWhite) {
- counter[counterPos]++;
- } else {
- if (counterPos === counter.length - 1) {
- normalized = self._normalize(counter);
- if (normalized) {
- for (code = 0; code < coderange; code++) {
- error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
- if (error < bestMatch.error) {
- bestMatch.code = code;
- bestMatch.error = error;
- }
- }
- bestMatch.end = i;
- if (bestMatch.error > self.AVG_CODE_ERROR) {
- return null;
- }
- return bestMatch;
- }
- } else {
- counterPos++;
- }
- counter[counterPos] = 1;
- isWhite = !isWhite;
+ function publishEvent(eventName, args) {
+ var j,
+ handlers = _eventHandlers[eventName];
+
+ if (handlers && handlers.length > 0) {
+ for ( j = 0; j < handlers.length; j++) {
+ handlers[j].apply(that, args);
}
}
- return null;
- };
-
- EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder, epsilon) {
- var counter = [],
- self = this,
- i,
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : 0,
- end : 0
- },
- error,
- j,
- sum,
- normalized;
+ }
- if (!offset) {
- offset = self._nextSet(self._row);
- }
- if (isWhite === undefined) {
- isWhite = false;
- }
+ that.trigger = publishEvent;
- if (tryHarder === undefined) {
- tryHarder = true;
- }
+ that.getWidth = function() {
+ return calculatedWidth;
+ };
- if ( epsilon === undefined) {
- epsilon = self.AVG_CODE_ERROR;
- }
+ that.getHeight = function() {
+ return calculatedHeight;
+ };
- for ( i = 0; i < pattern.length; i++) {
- counter[i] = 0;
- }
+ that.setWidth = function(width) {
+ calculatedWidth = width;
+ };
- 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];
- }
- normalized = self._normalize(counter);
- if (normalized) {
- error = self._matchPattern(normalized, pattern);
+ that.setHeight = function(height) {
+ calculatedHeight = height;
+ };
- 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;
+ that.getRealWidth = function() {
+ return width;
};
- EANReader.prototype._findStart = function() {
- var self = this,
- leadingWhitespaceStart,
- offset = self._nextSet(self._row),
- startInfo;
+ that.getRealHeight = function() {
+ return height;
+ };
- while(!startInfo) {
- startInfo = self._findPattern(self.START_PATTERN, offset);
- if (!startInfo) {
- return null;
- }
- leadingWhitespaceStart = startInfo.start - (startInfo.end - startInfo.start);
- if (leadingWhitespaceStart >= 0) {
- if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
- return startInfo;
- }
- }
- offset = startInfo.end;
- startInfo = null;
+ that.setInputStream = function(stream) {
+ _config = stream;
+ if (stream.sequence === false) {
+ baseUrl = stream.src;
+ size = 1;
+ } else {
+ baseUrl = stream.src;
+ size = stream.length;
}
+ loadImages();
};
- EANReader.prototype._verifyTrailingWhitespace = function(endInfo) {
- var self = this,
- trailingWhitespaceEnd;
-
- trailingWhitespaceEnd = endInfo.end + (endInfo.end - endInfo.start);
- if (trailingWhitespaceEnd < self._row.length) {
- if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
- return endInfo;
- }
- }
- return null;
+ that.ended = function() {
+ return ended;
};
- EANReader.prototype._findEnd = function(offset, isWhite) {
- var self = this,
- endInfo = self._findPattern(self.STOP_PATTERN, offset, isWhite, false);
+ that.setAttribute = function() {};
- return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
+ that.getConfig = function() {
+ return _config;
};
- EANReader.prototype._calculateFirstDigit = function(codeFrequency) {
- var i,
- self = this;
+ that.pause = function() {
+ paused = true;
+ };
- for ( i = 0; i < self.CODE_FREQUENCY.length; i++) {
- if (codeFrequency === self.CODE_FREQUENCY[i]) {
- return i;
- }
- }
- return null;
+ that.play = function() {
+ paused = false;
};
- EANReader.prototype._decodePayload = function(code, result, decodedCodes) {
- var i,
- self = this,
- codeFrequency = 0x0,
- firstDigit;
-
- for ( i = 0; i < 6; i++) {
- code = self._decodeCode(code.end);
- if (!code) {
- return null;
- }
- if (code.code >= self.CODE_G_START) {
- code.code = code.code - self.CODE_G_START;
- codeFrequency |= 1 << (5 - i);
- } else {
- codeFrequency |= 0 << (5 - i);
- }
- result.push(code.code);
- decodedCodes.push(code);
- }
-
- firstDigit = self._calculateFirstDigit(codeFrequency);
- if (firstDigit === null) {
- return null;
- }
- result.unshift(firstDigit);
-
- code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
- if (code === null) {
- return null;
- }
- decodedCodes.push(code);
+ that.setCurrentTime = function(time) {
+ frameIdx = time;
+ };
- for ( i = 0; i < 6; i++) {
- code = self._decodeCode(code.end, self.CODE_G_START);
- if (!code) {
- return null;
+ that.addEventListener = function(event, f) {
+ if (_eventNames.indexOf(event) !== -1) {
+ if (!_eventHandlers[event]) {
+ _eventHandlers[event] = [];
}
- decodedCodes.push(code);
- result.push(code.code);
+ _eventHandlers[event].push(f);
}
-
- return code;
};
- EANReader.prototype._decode = function() {
- var startInfo,
- self = this,
- code,
- result = [],
- decodedCodes = [];
-
- startInfo = self._findStart();
- if (!startInfo) {
- return null;
- }
- code = {
- code : startInfo.code,
- start : startInfo.start,
- end : startInfo.end
- };
- decodedCodes.push(code);
- code = self._decodePayload(code, result, decodedCodes);
- if (!code) {
- return null;
- }
- code = self._findEnd(code.end, false);
- if (!code){
- return null;
- }
-
- decodedCodes.push(code);
-
- // Checksum
- if (!self._checksum(result)) {
- return null;
- }
-
- return {
- code : result.join(""),
- start : startInfo.start,
- end : code.end,
- codeset : "",
- startInfo : startInfo,
- decodedCodes : decodedCodes
- };
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
};
- EANReader.prototype._checksum = function(result) {
- var sum = 0, i;
+ that.getTopRight = function() {
+ return _topRight;
+ };
- for ( i = result.length - 2; i >= 0; i -= 2) {
- sum += result[i];
- }
- sum *= 3;
- for ( i = result.length - 1; i >= 0; i -= 2) {
- sum += result[i];
- }
- return sum % 10 === 0;
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
};
-
- return (EANReader);
- }
-);
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-define('image_loader',[],function() {
- "use strict";
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
- var ImageLoader = {};
- ImageLoader.load = function(directory, callback, offset, size, sequence) {
- var htmlImagesSrcArray = new Array(size),
- htmlImagesArray = new Array(htmlImagesSrcArray.length),
- i,
- img,
- num;
+ that.getFrame = function() {
+ var frame;
- if (sequence === false) {
- htmlImagesSrcArray[0] = directory;
- } else {
- for ( i = 0; i < htmlImagesSrcArray.length; i++) {
- num = (offset + i);
- htmlImagesSrcArray[i] = directory + "image-" + ("00" + num).slice(-3) + ".jpg";
+ if (!loaded){
+ return null;
}
- }
- htmlImagesArray.notLoaded = [];
- htmlImagesArray.addImage = function(img) {
- htmlImagesArray.notLoaded.push(img);
- };
- htmlImagesArray.loaded = function(loadedImg) {
- var notloadedImgs = htmlImagesArray.notLoaded;
- for (var x = 0; x < notloadedImgs.length; x++) {
- if (notloadedImgs[x] == loadedImg) {
- notloadedImgs.splice(x, 1);
- for (var y = 0; y < htmlImagesSrcArray.length; y++) {
- var imgName = htmlImagesSrcArray[y].substr(htmlImagesSrcArray[y].lastIndexOf("/"));
- if (loadedImg.src.lastIndexOf(imgName) != -1) {
- htmlImagesArray[y] = loadedImg;
- break;
- }
- }
- break;
+ if (!paused) {
+ frame = imgArray[frameIdx];
+ if (frameIdx < (size - 1)) {
+ frameIdx++;
+ } else {
+ setTimeout(function() {
+ ended = true;
+ publishEvent("ended", []);
+ }, 0);
}
}
- if (notloadedImgs.length === 0) {
- console.log("Images loaded");
- callback.apply(null, [htmlImagesArray]);
- }
+ return frame;
};
-
- for ( i = 0; i < htmlImagesSrcArray.length; i++) {
- img = new Image();
- htmlImagesArray.addImage(img);
- addOnloadHandler(img, htmlImagesArray);
- img.src = htmlImagesSrcArray[i];
- }
+
+ return that;
};
-
- function addOnloadHandler(img, htmlImagesArray) {
- img.onload = function() {
- htmlImagesArray.loaded(this);
- };
- }
- return (ImageLoader);
+ return (InputStream);
});
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-
-define('input_stream',["image_loader"], function(ImageLoader) {
- "use strict";
-
- var InputStream = {};
- InputStream.createVideoStream = function(video) {
- var that = {},
- _config = null,
- _eventNames = ['canrecord', 'ended'],
- _eventHandlers = {},
- _calculatedWidth,
- _calculatedHeight,
- _topRight = {x: 0, y: 0},
- _canvasSize = {x: 0, y: 0};
-
- function initSize() {
- var width = video.videoWidth,
- height = video.videoHeight;
+/*
+ * typedefs.js
+ * Normalizes browser-specific prefixes
+ */
- _calculatedWidth = _config.size ? width/height > 1 ? _config.size : Math.floor((width/height) * _config.size) : width;
- _calculatedHeight = _config.size ? width/height > 1 ? Math.floor((height/width) * _config.size) : _config.size : height;
+glMatrixArrayType = Float32Array;
+if (typeof window !== 'undefined') {
+ window.requestAnimFrame = (function () {
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function (/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
+ window.setTimeout(callback, 1000 / 60);
+ };
+ })();
- _canvasSize.x = _calculatedWidth;
- _canvasSize.y = _calculatedHeight;
- }
+ navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+ window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
+}
- that.getRealWidth = function() {
- return video.videoWidth;
- };
+define("typedefs", (function (global) {
+ return function () {
+ var ret, fn;
+ return ret || global.typedefs;
+ };
+}(this)));
- that.getRealHeight = function() {
- return video.videoHeight;
- };
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
- that.getWidth = function() {
- return _calculatedWidth;
- };
+define('subImage',["typedefs"], function() {
+ "use strict";
- that.getHeight = function() {
- return _calculatedHeight;
- };
-
- that.setWidth = function(width) {
- _calculatedWidth = width;
- };
-
- that.setHeight = function(height) {
- _calculatedHeight = height;
- };
+ /**
+ * Construct representing a part of another {ImageWrapper}. Shares data
+ * between the parent and the child.
+ * @param from {ImageRef} The position where to start the {SubImage} from. (top-left corner)
+ * @param size {ImageRef} The size of the resulting image
+ * @param I {ImageWrapper} The {ImageWrapper} to share from
+ * @returns {SubImage} A shared part of the original image
+ */
+ function SubImage(from, size, I) {
+ if (!I) {
+ I = {
+ data : null,
+ size : size
+ };
+ }
+ this.data = I.data;
+ this.originalSize = I.size;
+ this.I = I;
- that.setInputStream = function(config) {
- _config = config;
- video.src = (typeof config.src !== 'undefined') ? config.src : '';
- };
+ this.from = from;
+ this.size = size;
+ }
- that.ended = function() {
- return video.ended;
- };
+ /**
+ * Displays the {SubImage} in a given canvas
+ * @param canvas {Canvas} The canvas element to write to
+ * @param scale {Number} Scale which is applied to each pixel-value
+ */
+ SubImage.prototype.show = function(canvas, scale) {
+ var ctx,
+ frame,
+ data,
+ current,
+ y,
+ x,
+ pixel;
+
+ if (!scale) {
+ scale = 1.0;
+ }
+ ctx = canvas.getContext('2d');
+ canvas.width = this.size.x;
+ canvas.height = this.size.y;
+ frame = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ data = frame.data;
+ current = 0;
+ for (y = 0; y < this.size.y; y++) {
+ for (x = 0; x < this.size.x; x++) {
+ pixel = y * this.size.x + x;
+ current = this.get(x, y) * scale;
+ data[pixel * 4 + 0] = current;
+ data[pixel * 4 + 1] = current;
+ data[pixel * 4 + 2] = current;
+ data[pixel * 4 + 3] = 255;
+ }
+ }
+ frame.data = data;
+ ctx.putImageData(frame, 0, 0);
+ };
- that.getConfig = function() {
- return _config;
- };
+ /**
+ * Retrieves a given pixel position from the {SubImage}
+ * @param x {Number} The x-position
+ * @param y {Number} The y-position
+ * @returns {Number} The grayscale value at the pixel-position
+ */
+ SubImage.prototype.get = function(x, y) {
+ return this.data[(this.from.y + y) * this.originalSize.x + this.from.x + x];
+ };
- that.setAttribute = function(name, value) {
- video.setAttribute(name, value);
- };
+ /**
+ * Updates the underlying data from a given {ImageWrapper}
+ * @param image {ImageWrapper} The updated image
+ */
+ SubImage.prototype.updateData = function(image) {
+ this.originalSize = image.size;
+ this.data = image.data;
+ };
- that.pause = function() {
- video.pause();
- };
+ /**
+ * Updates the position of the shared area
+ * @param from {x,y} The new location
+ * @returns {SubImage} returns {this} for possible chaining
+ */
+ SubImage.prototype.updateFrom = function(from) {
+ this.from = from;
+ return this;
+ };
+
+ return (SubImage);
+});
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define, vec2 */
- that.play = function() {
- video.play();
- };
+define('cluster',[],function() {
+ "use strict";
+
+ /**
+ * Creates a cluster for grouping similar orientations of datapoints
+ */
+ var Cluster = {
+ create : function(point, threshold) {
+ var points = [], center = {
+ rad : 0,
+ vec : vec2.create([0, 0])
+ }, pointMap = {};
- that.setCurrentTime = function(time) {
- if (_config.type !== "LiveStream")
- video.currentTime = time;
- };
+ function init() {
+ add(point);
+ updateCenter();
+ }
- that.addEventListener = function(event, f, bool) {
- if (_eventNames.indexOf(event) !== -1) {
- if (!_eventHandlers[event]) {
- _eventHandlers[event] = [];
- }
- _eventHandlers[event].push(f);
- } else {
- video.addEventListener(event, f, bool);
+ function add(point) {
+ pointMap[point.id] = point;
+ points.push(point);
}
- };
- that.clearEventHandlers = function() {
- _eventNames.forEach(function(eventName) {
- var handlers = _eventHandlers[eventName];
- if (handlers && handlers.length > 0) {
- handlers.forEach(function(handler) {
- video.removeEventListener(eventName, handler);
- });
+ function updateCenter() {
+ var i, sum = 0;
+ for ( i = 0; i < points.length; i++) {
+ sum += points[i].rad;
}
- });
- };
+ center.rad = sum / points.length;
+ center.vec = vec2.create([Math.cos(center.rad), Math.sin(center.rad)]);
+ }
- that.trigger = function(eventName, args) {
- var j,
- handlers = _eventHandlers[eventName];
+ init();
- if (eventName === 'canrecord') {
- initSize();
- }
- if (handlers && handlers.length > 0) {
- for ( j = 0; j < handlers.length; j++) {
- handlers[j].apply(that, args);
+ return {
+ add : function(point) {
+ if (!pointMap[point.id]) {
+ add(point);
+ updateCenter();
+ }
+ },
+ fits : function(point) {
+ // check cosine similarity to center-angle
+ var similarity = Math.abs(vec2.dot(point.point.vec, center.vec));
+ if (similarity > threshold) {
+ return true;
+ }
+ return false;
+ },
+ getPoints : function() {
+ return points;
+ },
+ getCenter : function() {
+ return center;
}
- }
- };
+ };
+ },
+ createPoint : function(point, id, property) {
+ return {
+ rad : point[property],
+ point : point,
+ id : id
+ };
+ }
+ };
- that.setTopRight = function(topRight) {
- _topRight.x = topRight.x;
- _topRight.y = topRight.y;
- };
+ return (Cluster);
+});
- that.getTopRight = function() {
- return _topRight;
- };
+/*
+ * glMatrix.js - High performance matrix and vector operations for WebGL
+ * version 0.9.6
+ */
+
+/*
+ * Copyright (c) 2011 Brandon Jones
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
- that.setCanvasSize = function(size) {
- _canvasSize.x = size.x;
- _canvasSize.y = size.y;
- };
- that.getCanvasSize = function() {
- return _canvasSize;
- };
- that.getFrame = function() {
- return video;
- };
+/*
+ * vec3 - 3 Dimensional Vector
+ */
+var vec3 = {};
- return that;
- };
+/*
+ * vec3.create
+ * Creates a new instance of a vec3 using the default array type
+ * Any javascript array containing at least 3 numeric elements can serve as a vec3
+ *
+ * Params:
+ * vec - Optional, vec3 containing values to initialize with
+ *
+ * Returns:
+ * New vec3
+ */
+vec3.create = function(vec) {
+ var dest;
+ if(vec) {
+ dest = new glMatrixArrayType(3);
+ dest[0] = vec[0];
+ dest[1] = vec[1];
+ dest[2] = vec[2];
+ } else {
+ if(glMatrixArrayType === Array)
+ dest = new glMatrixArrayType([0,0,0]);
+ else
+ dest = new glMatrixArrayType(3);
+ }
+
+ return dest;
+};
- InputStream.createLiveStream = function(video) {
- video.setAttribute("autoplay", true);
- var that = InputStream.createVideoStream(video);
+/*
+ * vec3.set
+ * Copies the values of one vec3 to another
+ *
+ * Params:
+ * vec - vec3 containing values to copy
+ * dest - vec3 receiving copied values
+ *
+ * Returns:
+ * dest
+ */
+vec3.set = function(vec, dest) {
+ dest[0] = vec[0];
+ dest[1] = vec[1];
+ dest[2] = vec[2];
+
+ return dest;
+};
- that.ended = function() {
- return false;
- };
+/*
+ * vec3.add
+ * Performs a vector addition
+ *
+ * Params:
+ * vec - vec3, first operand
+ * vec2 - vec3, second operand
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.add = function(vec, vec2, dest) {
+ if(!dest || vec == dest) {
+ vec[0] += vec2[0];
+ vec[1] += vec2[1];
+ vec[2] += vec2[2];
+ return vec;
+ }
+
+ dest[0] = vec[0] + vec2[0];
+ dest[1] = vec[1] + vec2[1];
+ dest[2] = vec[2] + vec2[2];
+ return dest;
+};
- return that;
- };
+/*
+ * vec3.subtract
+ * Performs a vector subtraction
+ *
+ * Params:
+ * vec - vec3, first operand
+ * vec2 - vec3, second operand
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.subtract = function(vec, vec2, dest) {
+ if(!dest || vec == dest) {
+ vec[0] -= vec2[0];
+ vec[1] -= vec2[1];
+ vec[2] -= vec2[2];
+ return vec;
+ }
+
+ dest[0] = vec[0] - vec2[0];
+ dest[1] = vec[1] - vec2[1];
+ dest[2] = vec[2] - vec2[2];
+ return dest;
+};
- InputStream.createImageStream = function() {
- var that = {};
- var _config = null;
-
- var width = 0,
- height = 0,
- frameIdx = 0,
- paused = true,
- loaded = false,
- imgArray = null,
- size = 0,
- offset = 1,
- baseUrl = null,
- ended = false,
- calculatedWidth,
- calculatedHeight,
- _eventNames = ['canrecord', 'ended'],
- _eventHandlers = {},
- _topRight = {x: 0, y: 0},
- _canvasSize = {x: 0, y: 0};
-
- function loadImages() {
- loaded = false;
- ImageLoader.load(baseUrl, function(imgs) {
- imgArray = imgs;
- width = imgs[0].width;
- height = imgs[0].height;
- calculatedWidth = _config.size ? width/height > 1 ? _config.size : Math.floor((width/height) * _config.size) : width;
- calculatedHeight = _config.size ? width/height > 1 ? Math.floor((height/width) * _config.size) : _config.size : height;
- _canvasSize.x = calculatedWidth;
- _canvasSize.y = calculatedHeight;
- loaded = true;
- frameIdx = 0;
- setTimeout(function() {
- publishEvent("canrecord", []);
- }, 0);
- }, offset, size, _config.sequence);
- }
-
- function publishEvent(eventName, args) {
- var j,
- handlers = _eventHandlers[eventName];
-
- if (handlers && handlers.length > 0) {
- for ( j = 0; j < handlers.length; j++) {
- handlers[j].apply(that, args);
- }
- }
- }
-
-
- that.trigger = publishEvent;
-
- that.getWidth = function() {
- return calculatedWidth;
- };
-
- that.getHeight = function() {
- return calculatedHeight;
- };
-
- that.setWidth = function(width) {
- calculatedWidth = width;
- };
-
- that.setHeight = function(height) {
- calculatedHeight = height;
- };
-
- that.getRealWidth = function() {
- return width;
- };
-
- that.getRealHeight = function() {
- return height;
- };
-
- that.setInputStream = function(stream) {
- _config = stream;
- if (stream.sequence === false) {
- baseUrl = stream.src;
- size = 1;
- } else {
- baseUrl = stream.src;
- size = stream.length;
- }
- loadImages();
- };
-
- that.ended = function() {
- return ended;
- };
-
- that.setAttribute = function() {};
-
- that.getConfig = function() {
- return _config;
- };
-
- that.pause = function() {
- paused = true;
- };
-
- that.play = function() {
- paused = false;
- };
-
- that.setCurrentTime = function(time) {
- frameIdx = time;
- };
+/*
+ * vec3.negate
+ * Negates the components of a vec3
+ *
+ * Params:
+ * vec - vec3 to negate
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.negate = function(vec, dest) {
+ if(!dest) { dest = vec; }
+
+ dest[0] = -vec[0];
+ dest[1] = -vec[1];
+ dest[2] = -vec[2];
+ return dest;
+};
- that.addEventListener = function(event, f) {
- if (_eventNames.indexOf(event) !== -1) {
- if (!_eventHandlers[event]) {
- _eventHandlers[event] = [];
- }
- _eventHandlers[event].push(f);
- }
- };
+/*
+ * vec3.scale
+ * Multiplies the components of a vec3 by a scalar value
+ *
+ * Params:
+ * vec - vec3 to scale
+ * val - Numeric value to scale by
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.scale = function(vec, val, dest) {
+ if(!dest || vec == dest) {
+ vec[0] *= val;
+ vec[1] *= val;
+ vec[2] *= val;
+ return vec;
+ }
+
+ dest[0] = vec[0]*val;
+ dest[1] = vec[1]*val;
+ dest[2] = vec[2]*val;
+ return dest;
+};
- that.setTopRight = function(topRight) {
- _topRight.x = topRight.x;
- _topRight.y = topRight.y;
- };
+/*
+ * vec3.normalize
+ * Generates a unit vector of the same direction as the provided vec3
+ * If vector length is 0, returns [0, 0, 0]
+ *
+ * Params:
+ * vec - vec3 to normalize
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.normalize = function(vec, dest) {
+ if(!dest) { dest = vec; }
+
+ var x = vec[0], y = vec[1], z = vec[2];
+ var len = Math.sqrt(x*x + y*y + z*z);
+
+ if (!len) {
+ dest[0] = 0;
+ dest[1] = 0;
+ dest[2] = 0;
+ return dest;
+ } else if (len == 1) {
+ dest[0] = x;
+ dest[1] = y;
+ dest[2] = z;
+ return dest;
+ }
+
+ len = 1 / len;
+ dest[0] = x*len;
+ dest[1] = y*len;
+ dest[2] = z*len;
+ return dest;
+};
- that.getTopRight = function() {
- return _topRight;
- };
+/*
+ * vec3.cross
+ * Generates the cross product of two vec3s
+ *
+ * Params:
+ * vec - vec3, first operand
+ * vec2 - vec3, second operand
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.cross = function(vec, vec2, dest){
+ if(!dest) { dest = vec; }
+
+ var x = vec[0], y = vec[1], z = vec[2];
+ var x2 = vec2[0], y2 = vec2[1], z2 = vec2[2];
+
+ dest[0] = y*z2 - z*y2;
+ dest[1] = z*x2 - x*z2;
+ dest[2] = x*y2 - y*x2;
+ return dest;
+};
- that.setCanvasSize = function(size) {
- _canvasSize.x = size.x;
- _canvasSize.y = size.y;
- };
+/*
+ * vec3.length
+ * Caclulates the length of a vec3
+ *
+ * Params:
+ * vec - vec3 to calculate length of
+ *
+ * Returns:
+ * Length of vec
+ */
+vec3.length = function(vec){
+ var x = vec[0], y = vec[1], z = vec[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
- that.getCanvasSize = function() {
- return _canvasSize;
- };
+/*
+ * vec3.dot
+ * Caclulates the dot product of two vec3s
+ *
+ * Params:
+ * vec - vec3, first operand
+ * vec2 - vec3, second operand
+ *
+ * Returns:
+ * Dot product of vec and vec2
+ */
+vec3.dot = function(vec, vec2){
+ return vec[0]*vec2[0] + vec[1]*vec2[1] + vec[2]*vec2[2];
+};
- that.getFrame = function() {
- var frame;
-
- if (!loaded){
- return null;
- }
- if (!paused) {
- frame = imgArray[frameIdx];
- if (frameIdx < (size - 1)) {
- frameIdx++;
- } else {
- setTimeout(function() {
- ended = true;
- publishEvent("ended", []);
- }, 0);
- }
- }
- return frame;
- };
+/*
+ * vec3.direction
+ * Generates a unit vector pointing from one vector to another
+ *
+ * Params:
+ * vec - origin vec3
+ * vec2 - vec3 to point to
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.direction = function(vec, vec2, dest) {
+ if(!dest) { dest = vec; }
+
+ var x = vec[0] - vec2[0];
+ var y = vec[1] - vec2[1];
+ var z = vec[2] - vec2[2];
+
+ var len = Math.sqrt(x*x + y*y + z*z);
+ if (!len) {
+ dest[0] = 0;
+ dest[1] = 0;
+ dest[2] = 0;
+ return dest;
+ }
+
+ len = 1 / len;
+ dest[0] = x * len;
+ dest[1] = y * len;
+ dest[2] = z * len;
+ return dest;
+};
- return that;
- };
+/*
+ * vec3.lerp
+ * Performs a linear interpolation between two vec3
+ *
+ * Params:
+ * vec - vec3, first vector
+ * vec2 - vec3, second vector
+ * lerp - interpolation amount between the two inputs
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+vec3.lerp = function(vec, vec2, lerp, dest){
+ if(!dest) { dest = vec; }
+
+ dest[0] = vec[0] + lerp * (vec2[0] - vec[0]);
+ dest[1] = vec[1] + lerp * (vec2[1] - vec[1]);
+ dest[2] = vec[2] + lerp * (vec2[2] - vec[2]);
+
+ return dest;
+};
- return (InputStream);
-});
+/*
+ * vec3.str
+ * Returns a string representation of a vector
+ *
+ * Params:
+ * vec - vec3 to represent as a string
+ *
+ * Returns:
+ * string representation of vec
+ */
+vec3.str = function(vec) {
+ return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']';
+};
/*
- * typedefs.js
- * Normalizes browser-specific prefixes
+ * mat3 - 3x3 Matrix
*/
+var mat3 = {};
+<<<<<<< HEAD
glMatrixArrayType = Float32Array;
if (typeof window !== 'undefined') {
window.requestAnimFrame = (function () {
@@ -3606,11 +3181,79 @@ mat2.invert = function(out, a) {
/**
* Calculates the adjugate of a mat2
+=======
+/*
+ * mat3.create
+ * Creates a new instance of a mat3 using the default array type
+ * Any javascript array containing at least 9 numeric elements can serve as a mat3
+ *
+ * Params:
+ * mat - Optional, mat3 containing values to initialize with
+ *
+ * Returns:
+ * New mat3
+ */
+mat3.create = function(mat) {
+ var dest;
+
+ if(mat) {
+ dest = new glMatrixArrayType(9);
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+ dest[8] = mat[8];
+ } else {
+ if(glMatrixArrayType === Array)
+ dest = new glMatrixArrayType([0,0,0,0,0,0,0,0,0]);
+ else
+ dest = new glMatrixArrayType(9);
+ }
+
+ return dest;
+};
+
+/*
+ * mat3.set
+ * Copies the values of one mat3 to another
+ *
+ * Params:
+ * mat - mat3 containing values to copy
+ * dest - mat3 receiving copied values
+ *
+ * Returns:
+ * dest
+ */
+mat3.set = function(mat, dest) {
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+ dest[8] = mat[8];
+ return dest;
+};
+
+/*
+ * mat3.identity
+ * Sets a mat3 to an identity matrix
+ *
+ * Params:
+ * dest - mat3 to set
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
+<<<<<<< HEAD
mat2.adjoint = function(out, a) {
// Caching this value is nessecary if out == a
var a0 = a[0];
@@ -5421,49 +5064,1258 @@ quat.setAxisAngle = function(out, axis, rad) {
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
+=======
+mat3.identity = function(dest) {
+ dest[0] = 1;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ dest[4] = 1;
+ dest[5] = 0;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
};
-/**
- * Adds two quat's
+/*
+ * mat4.transpose
+ * Transposes a mat3 (flips the values over the diagonal)
+ *
+ * Params:
+ * mat - mat3 to transpose
+ * dest - Optional, mat3 receiving transposed values. If not specified result is written to mat
+ *
+ * Returns:
+ * dest is specified, mat otherwise
+ */
+mat3.transpose = function(mat, dest) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if(!dest || mat == dest) {
+ var a01 = mat[1], a02 = mat[2];
+ var a12 = mat[5];
+
+ mat[1] = mat[3];
+ mat[2] = mat[6];
+ mat[3] = a01;
+ mat[5] = mat[7];
+ mat[6] = a02;
+ mat[7] = a12;
+ return mat;
+ }
+
+ dest[0] = mat[0];
+ dest[1] = mat[3];
+ dest[2] = mat[6];
+ dest[3] = mat[1];
+ dest[4] = mat[4];
+ dest[5] = mat[7];
+ dest[6] = mat[2];
+ dest[7] = mat[5];
+ dest[8] = mat[8];
+ return dest;
+};
+
+/*
+ * mat3.toMat4
+ * Copies the elements of a mat3 into the upper 3x3 elements of a mat4
+ *
+ * Params:
+ * mat - mat3 containing values to copy
+ * dest - Optional, mat4 receiving copied values
+ *
+ * Returns:
+ * dest if specified, a new mat4 otherwise
+ */
+mat3.toMat4 = function(mat, dest) {
+ if(!dest) { dest = mat4.create(); }
+
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = 0;
+
+ dest[4] = mat[3];
+ dest[5] = mat[4];
+ dest[6] = mat[5];
+ dest[7] = 0;
+
+ dest[8] = mat[6];
+ dest[9] = mat[7];
+ dest[10] = mat[8];
+ dest[11] = 0;
+
+ dest[12] = 0;
+ dest[13] = 0;
+ dest[14] = 0;
+ dest[15] = 1;
+
+ return dest;
+};
+
+/*
+ * mat3.str
+ * Returns a string representation of a mat3
*
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
- * @function
+ * Params:
+ * mat - mat3 to represent as a string
+ *
+ * Returns:
+ * string representation of mat
*/
-quat.add = vec4.add;
+mat3.str = function(mat) {
+ return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] +
+ ', ' + mat[3] + ', '+ mat[4] + ', ' + mat[5] +
+ ', ' + mat[6] + ', ' + mat[7] + ', '+ mat[8] + ']';
+};
-/**
- * Multiplies two quat's
- *
- * @param {quat} out the receiving quaternion
- * @param {quat} a the first operand
- * @param {quat} b the second operand
- * @returns {quat} out
+/*
+ * mat4 - 4x4 Matrix
*/
-quat.multiply = function(out, a, b) {
- var ax = a[0], ay = a[1], az = a[2], aw = a[3],
- bx = b[0], by = b[1], bz = b[2], bw = b[3];
+var mat4 = {};
- out[0] = ax * bw + aw * bx + ay * bz - az * by;
- out[1] = ay * bw + aw * by + az * bx - ax * bz;
- out[2] = az * bw + aw * bz + ax * by - ay * bx;
- out[3] = aw * bw - ax * bx - ay * by - az * bz;
- return out;
+/*
+ * mat4.create
+ * Creates a new instance of a mat4 using the default array type
+ * Any javascript array containing at least 16 numeric elements can serve as a mat4
+ *
+ * Params:
+ * mat - Optional, mat4 containing values to initialize with
+ *
+ * Returns:
+ * New mat4
+ */
+mat4.create = function(mat) {
+ var dest;
+
+ if(mat) {
+ dest = new glMatrixArrayType(16);
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+ dest[8] = mat[8];
+ dest[9] = mat[9];
+ dest[10] = mat[10];
+ dest[11] = mat[11];
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ } else {
+ if(glMatrixArrayType === Array)
+ dest = new glMatrixArrayType([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
+ else
+ dest = new glMatrixArrayType(16);
+ }
+
+ return dest;
};
-/**
- * Alias for {@link quat.multiply}
- * @function
- */
-quat.mul = quat.multiply;
+/*
+ * mat4.set
+ * Copies the values of one mat4 to another
+ *
+ * Params:
+ * mat - mat4 containing values to copy
+ * dest - mat4 receiving copied values
+ *
+ * Returns:
+ * dest
+ */
+mat4.set = function(mat, dest) {
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+ dest[8] = mat[8];
+ dest[9] = mat[9];
+ dest[10] = mat[10];
+ dest[11] = mat[11];
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ return dest;
+};
-/**
- * Scales a quat by a scalar number
- *
- * @param {quat} out the receiving vector
- * @param {quat} a the vector to scale
+/*
+ * mat4.identity
+ * Sets a mat4 to an identity matrix
+ *
+ * Params:
+ * dest - mat4 to set
+ *
+ * Returns:
+ * dest
+ */
+mat4.identity = function(dest) {
+ dest[0] = 1;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ dest[4] = 0;
+ dest[5] = 1;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 0;
+ dest[9] = 0;
+ dest[10] = 1;
+ dest[11] = 0;
+ dest[12] = 0;
+ dest[13] = 0;
+ dest[14] = 0;
+ dest[15] = 1;
+ return dest;
+};
+
+/*
+ * mat4.transpose
+ * Transposes a mat4 (flips the values over the diagonal)
+ *
+ * Params:
+ * mat - mat4 to transpose
+ * dest - Optional, mat4 receiving transposed values. If not specified result is written to mat
+ *
+ * Returns:
+ * dest is specified, mat otherwise
+ */
+mat4.transpose = function(mat, dest) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if(!dest || mat == dest) {
+ var a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a12 = mat[6], a13 = mat[7];
+ var a23 = mat[11];
+
+ mat[1] = mat[4];
+ mat[2] = mat[8];
+ mat[3] = mat[12];
+ mat[4] = a01;
+ mat[6] = mat[9];
+ mat[7] = mat[13];
+ mat[8] = a02;
+ mat[9] = a12;
+ mat[11] = mat[14];
+ mat[12] = a03;
+ mat[13] = a13;
+ mat[14] = a23;
+ return mat;
+ }
+
+ dest[0] = mat[0];
+ dest[1] = mat[4];
+ dest[2] = mat[8];
+ dest[3] = mat[12];
+ dest[4] = mat[1];
+ dest[5] = mat[5];
+ dest[6] = mat[9];
+ dest[7] = mat[13];
+ dest[8] = mat[2];
+ dest[9] = mat[6];
+ dest[10] = mat[10];
+ dest[11] = mat[14];
+ dest[12] = mat[3];
+ dest[13] = mat[7];
+ dest[14] = mat[11];
+ dest[15] = mat[15];
+ return dest;
+};
+
+/*
+ * mat4.determinant
+ * Calculates the determinant of a mat4
+ *
+ * Params:
+ * mat - mat4 to calculate determinant of
+ *
+ * Returns:
+ * determinant of mat
+ */
+mat4.determinant = function(mat) {
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+ var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
+
+ return a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
+ a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
+ a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
+ a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
+ a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
+ a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
+};
+
+/*
+ * mat4.inverse
+ * Calculates the inverse matrix of a mat4
+ *
+ * Params:
+ * mat - mat4 to calculate inverse of
+ * dest - Optional, mat4 receiving inverse matrix. If not specified result is written to mat
+ *
+ * Returns:
+ * dest is specified, mat otherwise
+ */
+mat4.inverse = function(mat, dest) {
+ if(!dest) { dest = mat; }
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+ var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
+
+ var b00 = a00*a11 - a01*a10;
+ var b01 = a00*a12 - a02*a10;
+ var b02 = a00*a13 - a03*a10;
+ var b03 = a01*a12 - a02*a11;
+ var b04 = a01*a13 - a03*a11;
+ var b05 = a02*a13 - a03*a12;
+ var b06 = a20*a31 - a21*a30;
+ var b07 = a20*a32 - a22*a30;
+ var b08 = a20*a33 - a23*a30;
+ var b09 = a21*a32 - a22*a31;
+ var b10 = a21*a33 - a23*a31;
+ var b11 = a22*a33 - a23*a32;
+
+ // Calculate the determinant (inlined to avoid double-caching)
+ var invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
+
+ dest[0] = (a11*b11 - a12*b10 + a13*b09)*invDet;
+ dest[1] = (-a01*b11 + a02*b10 - a03*b09)*invDet;
+ dest[2] = (a31*b05 - a32*b04 + a33*b03)*invDet;
+ dest[3] = (-a21*b05 + a22*b04 - a23*b03)*invDet;
+ dest[4] = (-a10*b11 + a12*b08 - a13*b07)*invDet;
+ dest[5] = (a00*b11 - a02*b08 + a03*b07)*invDet;
+ dest[6] = (-a30*b05 + a32*b02 - a33*b01)*invDet;
+ dest[7] = (a20*b05 - a22*b02 + a23*b01)*invDet;
+ dest[8] = (a10*b10 - a11*b08 + a13*b06)*invDet;
+ dest[9] = (-a00*b10 + a01*b08 - a03*b06)*invDet;
+ dest[10] = (a30*b04 - a31*b02 + a33*b00)*invDet;
+ dest[11] = (-a20*b04 + a21*b02 - a23*b00)*invDet;
+ dest[12] = (-a10*b09 + a11*b07 - a12*b06)*invDet;
+ dest[13] = (a00*b09 - a01*b07 + a02*b06)*invDet;
+ dest[14] = (-a30*b03 + a31*b01 - a32*b00)*invDet;
+ dest[15] = (a20*b03 - a21*b01 + a22*b00)*invDet;
+
+ return dest;
+};
+
+/*
+ * mat4.toRotationMat
+ * Copies the upper 3x3 elements of a mat4 into another mat4
+ *
+ * Params:
+ * mat - mat4 containing values to copy
+ * dest - Optional, mat4 receiving copied values
+ *
+ * Returns:
+ * dest is specified, a new mat4 otherwise
+ */
+mat4.toRotationMat = function(mat, dest) {
+ if(!dest) { dest = mat4.create(); }
+
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+ dest[8] = mat[8];
+ dest[9] = mat[9];
+ dest[10] = mat[10];
+ dest[11] = mat[11];
+ dest[12] = 0;
+ dest[13] = 0;
+ dest[14] = 0;
+ dest[15] = 1;
+
+ return dest;
+};
+
+/*
+ * mat4.toMat3
+ * Copies the upper 3x3 elements of a mat4 into a mat3
+ *
+ * Params:
+ * mat - mat4 containing values to copy
+ * dest - Optional, mat3 receiving copied values
+ *
+ * Returns:
+ * dest is specified, a new mat3 otherwise
+ */
+mat4.toMat3 = function(mat, dest) {
+ if(!dest) { dest = mat3.create(); }
+
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[4];
+ dest[4] = mat[5];
+ dest[5] = mat[6];
+ dest[6] = mat[8];
+ dest[7] = mat[9];
+ dest[8] = mat[10];
+
+ return dest;
+};
+
+/*
+ * mat4.toInverseMat3
+ * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3
+ * The resulting matrix is useful for calculating transformed normals
+ *
+ * Params:
+ * mat - mat4 containing values to invert and copy
+ * dest - Optional, mat3 receiving values
+ *
+ * Returns:
+ * dest is specified, a new mat3 otherwise
+ */
+mat4.toInverseMat3 = function(mat, dest) {
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10];
+
+ var b01 = a22*a11-a12*a21;
+ var b11 = -a22*a10+a12*a20;
+ var b21 = a21*a10-a11*a20;
+
+ var d = a00*b01 + a01*b11 + a02*b21;
+ if (!d) { return null; }
+ var id = 1/d;
+
+ if(!dest) { dest = mat3.create(); }
+
+ dest[0] = b01*id;
+ dest[1] = (-a22*a01 + a02*a21)*id;
+ dest[2] = (a12*a01 - a02*a11)*id;
+ dest[3] = b11*id;
+ dest[4] = (a22*a00 - a02*a20)*id;
+ dest[5] = (-a12*a00 + a02*a10)*id;
+ dest[6] = b21*id;
+ dest[7] = (-a21*a00 + a01*a20)*id;
+ dest[8] = (a11*a00 - a01*a10)*id;
+
+ return dest;
+};
+
+/*
+ * mat4.multiply
+ * Performs a matrix multiplication
+ *
+ * Params:
+ * mat - mat4, first operand
+ * mat2 - mat4, second operand
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.multiply = function(mat, mat2, dest) {
+ if(!dest) { dest = mat; }
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+ var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15];
+
+ var b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3];
+ var b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7];
+ var b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11];
+ var b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15];
+
+ dest[0] = b00*a00 + b01*a10 + b02*a20 + b03*a30;
+ dest[1] = b00*a01 + b01*a11 + b02*a21 + b03*a31;
+ dest[2] = b00*a02 + b01*a12 + b02*a22 + b03*a32;
+ dest[3] = b00*a03 + b01*a13 + b02*a23 + b03*a33;
+ dest[4] = b10*a00 + b11*a10 + b12*a20 + b13*a30;
+ dest[5] = b10*a01 + b11*a11 + b12*a21 + b13*a31;
+ dest[6] = b10*a02 + b11*a12 + b12*a22 + b13*a32;
+ dest[7] = b10*a03 + b11*a13 + b12*a23 + b13*a33;
+ dest[8] = b20*a00 + b21*a10 + b22*a20 + b23*a30;
+ dest[9] = b20*a01 + b21*a11 + b22*a21 + b23*a31;
+ dest[10] = b20*a02 + b21*a12 + b22*a22 + b23*a32;
+ dest[11] = b20*a03 + b21*a13 + b22*a23 + b23*a33;
+ dest[12] = b30*a00 + b31*a10 + b32*a20 + b33*a30;
+ dest[13] = b30*a01 + b31*a11 + b32*a21 + b33*a31;
+ dest[14] = b30*a02 + b31*a12 + b32*a22 + b33*a32;
+ dest[15] = b30*a03 + b31*a13 + b32*a23 + b33*a33;
+
+ return dest;
+};
+
+/*
+ * mat4.multiplyVec3
+ * Transforms a vec3 with the given matrix
+ * 4th vector component is implicitly '1'
+ *
+ * Params:
+ * mat - mat4 to transform the vector with
+ * vec - vec3 to transform
+ * dest - Optional, vec3 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+mat4.multiplyVec3 = function(mat, vec, dest) {
+ if(!dest) { dest = vec; }
+
+ var x = vec[0], y = vec[1], z = vec[2];
+
+ dest[0] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12];
+ dest[1] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13];
+ dest[2] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14];
+
+ return dest;
+};
+
+/*
+ * mat4.multiplyVec4
+ * Transforms a vec4 with the given matrix
+ *
+ * Params:
+ * mat - mat4 to transform the vector with
+ * vec - vec4 to transform
+ * dest - Optional, vec4 receiving operation result. If not specified result is written to vec
+ *
+ * Returns:
+ * dest if specified, vec otherwise
+ */
+mat4.multiplyVec4 = function(mat, vec, dest) {
+ if(!dest) { dest = vec; }
+
+ var x = vec[0], y = vec[1], z = vec[2], w = vec[3];
+
+ dest[0] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12]*w;
+ dest[1] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13]*w;
+ dest[2] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14]*w;
+ dest[3] = mat[3]*x + mat[7]*y + mat[11]*z + mat[15]*w;
+
+ return dest;
+};
+
+/*
+ * mat4.translate
+ * Translates a matrix by the given vector
+ *
+ * Params:
+ * mat - mat4 to translate
+ * vec - vec3 specifying the translation
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.translate = function(mat, vec, dest) {
+ var x = vec[0], y = vec[1], z = vec[2];
+
+ if(!dest || mat == dest) {
+ mat[12] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12];
+ mat[13] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13];
+ mat[14] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14];
+ mat[15] = mat[3]*x + mat[7]*y + mat[11]*z + mat[15];
+ return mat;
+ }
+
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+
+ dest[0] = a00;
+ dest[1] = a01;
+ dest[2] = a02;
+ dest[3] = a03;
+ dest[4] = a10;
+ dest[5] = a11;
+ dest[6] = a12;
+ dest[7] = a13;
+ dest[8] = a20;
+ dest[9] = a21;
+ dest[10] = a22;
+ dest[11] = a23;
+
+ dest[12] = a00*x + a10*y + a20*z + mat[12];
+ dest[13] = a01*x + a11*y + a21*z + mat[13];
+ dest[14] = a02*x + a12*y + a22*z + mat[14];
+ dest[15] = a03*x + a13*y + a23*z + mat[15];
+ return dest;
+};
+
+/*
+ * mat4.scale
+ * Scales a matrix by the given vector
+ *
+ * Params:
+ * mat - mat4 to scale
+ * vec - vec3 specifying the scale for each axis
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.scale = function(mat, vec, dest) {
+ var x = vec[0], y = vec[1], z = vec[2];
+
+ if(!dest || mat == dest) {
+ mat[0] *= x;
+ mat[1] *= x;
+ mat[2] *= x;
+ mat[3] *= x;
+ mat[4] *= y;
+ mat[5] *= y;
+ mat[6] *= y;
+ mat[7] *= y;
+ mat[8] *= z;
+ mat[9] *= z;
+ mat[10] *= z;
+ mat[11] *= z;
+ return mat;
+ }
+
+ dest[0] = mat[0]*x;
+ dest[1] = mat[1]*x;
+ dest[2] = mat[2]*x;
+ dest[3] = mat[3]*x;
+ dest[4] = mat[4]*y;
+ dest[5] = mat[5]*y;
+ dest[6] = mat[6]*y;
+ dest[7] = mat[7]*y;
+ dest[8] = mat[8]*z;
+ dest[9] = mat[9]*z;
+ dest[10] = mat[10]*z;
+ dest[11] = mat[11]*z;
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ return dest;
+};
+
+/*
+ * mat4.rotate
+ * Rotates a matrix by the given angle around the specified axis
+ * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance
+ *
+ * Params:
+ * mat - mat4 to rotate
+ * angle - angle (in radians) to rotate
+ * axis - vec3 representing the axis to rotate around
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.rotate = function(mat, angle, axis, dest) {
+ var x = axis[0], y = axis[1], z = axis[2];
+ var len = Math.sqrt(x*x + y*y + z*z);
+ if (!len) { return null; }
+ if (len != 1) {
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+ }
+
+ var s = Math.sin(angle);
+ var c = Math.cos(angle);
+ var t = 1-c;
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+
+ // Construct the elements of the rotation matrix
+ var b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s;
+ var b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s;
+ var b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c;
+
+ if(!dest) {
+ dest = mat;
+ } else if(mat != dest) { // If the source and destination differ, copy the unchanged last row
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ }
+
+ // Perform rotation-specific matrix multiplication
+ dest[0] = a00*b00 + a10*b01 + a20*b02;
+ dest[1] = a01*b00 + a11*b01 + a21*b02;
+ dest[2] = a02*b00 + a12*b01 + a22*b02;
+ dest[3] = a03*b00 + a13*b01 + a23*b02;
+
+ dest[4] = a00*b10 + a10*b11 + a20*b12;
+ dest[5] = a01*b10 + a11*b11 + a21*b12;
+ dest[6] = a02*b10 + a12*b11 + a22*b12;
+ dest[7] = a03*b10 + a13*b11 + a23*b12;
+
+ dest[8] = a00*b20 + a10*b21 + a20*b22;
+ dest[9] = a01*b20 + a11*b21 + a21*b22;
+ dest[10] = a02*b20 + a12*b21 + a22*b22;
+ dest[11] = a03*b20 + a13*b21 + a23*b22;
+ return dest;
+};
+
+/*
+ * mat4.rotateX
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * Params:
+ * mat - mat4 to rotate
+ * angle - angle (in radians) to rotate
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.rotateX = function(mat, angle, dest) {
+ var s = Math.sin(angle);
+ var c = Math.cos(angle);
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+
+ if(!dest) {
+ dest = mat;
+ } else if(mat != dest) { // If the source and destination differ, copy the unchanged rows
+ dest[0] = mat[0];
+ dest[1] = mat[1];
+ dest[2] = mat[2];
+ dest[3] = mat[3];
+
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ dest[4] = a10*c + a20*s;
+ dest[5] = a11*c + a21*s;
+ dest[6] = a12*c + a22*s;
+ dest[7] = a13*c + a23*s;
+
+ dest[8] = a10*-s + a20*c;
+ dest[9] = a11*-s + a21*c;
+ dest[10] = a12*-s + a22*c;
+ dest[11] = a13*-s + a23*c;
+ return dest;
+};
+
+/*
+ * mat4.rotateY
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * Params:
+ * mat - mat4 to rotate
+ * angle - angle (in radians) to rotate
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.rotateY = function(mat, angle, dest) {
+ var s = Math.sin(angle);
+ var c = Math.cos(angle);
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11];
+
+ if(!dest) {
+ dest = mat;
+ } else if(mat != dest) { // If the source and destination differ, copy the unchanged rows
+ dest[4] = mat[4];
+ dest[5] = mat[5];
+ dest[6] = mat[6];
+ dest[7] = mat[7];
+
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ dest[0] = a00*c + a20*-s;
+ dest[1] = a01*c + a21*-s;
+ dest[2] = a02*c + a22*-s;
+ dest[3] = a03*c + a23*-s;
+
+ dest[8] = a00*s + a20*c;
+ dest[9] = a01*s + a21*c;
+ dest[10] = a02*s + a22*c;
+ dest[11] = a03*s + a23*c;
+ return dest;
+};
+
+/*
+ * mat4.rotateZ
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * Params:
+ * mat - mat4 to rotate
+ * angle - angle (in radians) to rotate
+ * dest - Optional, mat4 receiving operation result. If not specified result is written to mat
+ *
+ * Returns:
+ * dest if specified, mat otherwise
+ */
+mat4.rotateZ = function(mat, angle, dest) {
+ var s = Math.sin(angle);
+ var c = Math.cos(angle);
+
+ // Cache the matrix values (makes for huge speed increases!)
+ var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3];
+ var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7];
+
+ if(!dest) {
+ dest = mat;
+ } else if(mat != dest) { // If the source and destination differ, copy the unchanged last row
+ dest[8] = mat[8];
+ dest[9] = mat[9];
+ dest[10] = mat[10];
+ dest[11] = mat[11];
+
+ dest[12] = mat[12];
+ dest[13] = mat[13];
+ dest[14] = mat[14];
+ dest[15] = mat[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ dest[0] = a00*c + a10*s;
+ dest[1] = a01*c + a11*s;
+ dest[2] = a02*c + a12*s;
+ dest[3] = a03*c + a13*s;
+
+ dest[4] = a00*-s + a10*c;
+ dest[5] = a01*-s + a11*c;
+ dest[6] = a02*-s + a12*c;
+ dest[7] = a03*-s + a13*c;
+
+ return dest;
+};
+
+/*
+ * mat4.frustum
+ * Generates a frustum matrix with the given bounds
+ *
+ * Params:
+ * left, right - scalar, left and right bounds of the frustum
+ * bottom, top - scalar, bottom and top bounds of the frustum
+ * near, far - scalar, near and far bounds of the frustum
+ * dest - Optional, mat4 frustum matrix will be written into
+ *
+ * Returns:
+ * dest if specified, a new mat4 otherwise
+ */
+mat4.frustum = function(left, right, bottom, top, near, far, dest) {
+ if(!dest) { dest = mat4.create(); }
+ var rl = (right - left);
+ var tb = (top - bottom);
+ var fn = (far - near);
+ dest[0] = (near*2) / rl;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ dest[4] = 0;
+ dest[5] = (near*2) / tb;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = (right + left) / rl;
+ dest[9] = (top + bottom) / tb;
+ dest[10] = -(far + near) / fn;
+ dest[11] = -1;
+ dest[12] = 0;
+ dest[13] = 0;
+ dest[14] = -(far*near*2) / fn;
+ dest[15] = 0;
+ return dest;
+};
+
+/*
+ * mat4.perspective
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * Params:
+ * fovy - scalar, vertical field of view
+ * aspect - scalar, aspect ratio. typically viewport width/height
+ * near, far - scalar, near and far bounds of the frustum
+ * dest - Optional, mat4 frustum matrix will be written into
+ *
+ * Returns:
+ * dest if specified, a new mat4 otherwise
+ */
+mat4.perspective = function(fovy, aspect, near, far, dest) {
+ var top = near*Math.tan(fovy*Math.PI / 360.0);
+ var right = top*aspect;
+ return mat4.frustum(-right, right, -top, top, near, far, dest);
+};
+
+/*
+ * mat4.ortho
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * Params:
+ * left, right - scalar, left and right bounds of the frustum
+ * bottom, top - scalar, bottom and top bounds of the frustum
+ * near, far - scalar, near and far bounds of the frustum
+ * dest - Optional, mat4 frustum matrix will be written into
+ *
+ * Returns:
+ * dest if specified, a new mat4 otherwise
+ */
+mat4.ortho = function(left, right, bottom, top, near, far, dest) {
+ if(!dest) { dest = mat4.create(); }
+ var rl = (right - left);
+ var tb = (top - bottom);
+ var fn = (far - near);
+ dest[0] = 2 / rl;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ dest[4] = 0;
+ dest[5] = 2 / tb;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 0;
+ dest[9] = 0;
+ dest[10] = -2 / fn;
+ dest[11] = 0;
+ dest[12] = -(left + right) / rl;
+ dest[13] = -(top + bottom) / tb;
+ dest[14] = -(far + near) / fn;
+ dest[15] = 1;
+ return dest;
+};
+
+/*
+ * mat4.ortho
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * Params:
+ * eye - vec3, position of the viewer
+ * center - vec3, point the viewer is looking at
+ * up - vec3 pointing "up"
+ * dest - Optional, mat4 frustum matrix will be written into
+ *
+ * Returns:
+ * dest if specified, a new mat4 otherwise
+ */
+mat4.lookAt = function(eye, center, up, dest) {
+ if(!dest) { dest = mat4.create(); }
+
+ var eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (eyex == centerx && eyey == centery && eyez == centerz) {
+ return mat4.identity(dest);
+ }
+
+ var z0,z1,z2,x0,x1,x2,y0,y1,y2,len;
+
+ //vec3.direction(eye, center, z);
+ z0 = eyex - center[0];
+ z1 = eyey - center[1];
+ z2 = eyez - center[2];
+
+ // normalize (no check needed for 0 because of early return)
+ len = 1/Math.sqrt(z0*z0 + z1*z1 + z2*z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ //vec3.normalize(vec3.cross(up, z, x));
+ x0 = upy*z2 - upz*z1;
+ x1 = upz*z0 - upx*z2;
+ x2 = upx*z1 - upy*z0;
+ len = Math.sqrt(x0*x0 + x1*x1 + x2*x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1/len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ };
+
+ //vec3.normalize(vec3.cross(z, x, y));
+ y0 = z1*x2 - z2*x1;
+ y1 = z2*x0 - z0*x2;
+ y2 = z0*x1 - z1*x0;
+
+ len = Math.sqrt(y0*y0 + y1*y1 + y2*y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1/len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ dest[0] = x0;
+ dest[1] = y0;
+ dest[2] = z0;
+ dest[3] = 0;
+ dest[4] = x1;
+ dest[5] = y1;
+ dest[6] = z1;
+ dest[7] = 0;
+ dest[8] = x2;
+ dest[9] = y2;
+ dest[10] = z2;
+ dest[11] = 0;
+ dest[12] = -(x0*eyex + x1*eyey + x2*eyez);
+ dest[13] = -(y0*eyex + y1*eyey + y2*eyez);
+ dest[14] = -(z0*eyex + z1*eyey + z2*eyez);
+ dest[15] = 1;
+
+ return dest;
+};
+
+/*
+ * mat4.str
+ * Returns a string representation of a mat4
+ *
+ * Params:
+ * mat - mat4 to represent as a string
+ *
+ * Returns:
+ * string representation of mat
+ */
+mat4.str = function(mat) {
+ return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] +
+ ',\n '+ mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] +
+ ',\n '+ mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] +
+ ',\n '+ mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']';
+};
+
+/*
+ * quat4 - Quaternions
+ */
+quat4 = {};
+
+/*
+ * quat4.create
+ * Creates a new instance of a quat4 using the default array type
+ * Any javascript array containing at least 4 numeric elements can serve as a quat4
+ *
+ * Params:
+ * quat - Optional, quat4 containing values to initialize with
+ *
+ * Returns:
+ * New quat4
+ */
+quat4.create = function(quat) {
+ var dest;
+
+ if(quat) {
+ dest = new glMatrixArrayType(4);
+ dest[0] = quat[0];
+ dest[1] = quat[1];
+ dest[2] = quat[2];
+ dest[3] = quat[3];
+ } else {
+ if(glMatrixArrayType === Array)
+ dest = new glMatrixArrayType([0,0,0,0]);
+ else
+ dest = new glMatrixArrayType(4);
+ }
+
+ return dest;
+};
+
+/*
+ * quat4.set
+ * Copies the values of one quat4 to another
+ *
+ * Params:
+ * quat - quat4 containing values to copy
+ * dest - quat4 receiving copied values
+ *
+ * Returns:
+ * dest
+ */
+quat4.set = function(quat, dest) {
+ dest[0] = quat[0];
+ dest[1] = quat[1];
+ dest[2] = quat[2];
+ dest[3] = quat[3];
+
+ return dest;
+};
+
+/*
+ * quat4.calculateW
+ * Calculates the W component of a quat4 from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * Params:
+ * quat - quat4 to calculate W component of
+ * dest - Optional, quat4 receiving calculated values. If not specified result is written to quat
+ *
+ * Returns:
+ * dest if specified, quat otherwise
+ */
+quat4.calculateW = function(quat, dest) {
+ var x = quat[0], y = quat[1], z = quat[2];
+
+ if(!dest || quat == dest) {
+ quat[3] = -Math.sqrt(Math.abs(1.0 - x*x - y*y - z*z));
+ return quat;
+ }
+ dest[0] = x;
+ dest[1] = y;
+ dest[2] = z;
+ dest[3] = -Math.sqrt(Math.abs(1.0 - x*x - y*y - z*z));
+ return dest;
+};
+
+/*
+ * quat4.inverse
+ * Calculates the inverse of a quat4
+ *
+ * Params:
+ * quat - quat4 to calculate inverse of
+ * dest - Optional, quat4 receiving inverse values. If not specified result is written to quat
+ *
+ * Returns:
+ * dest if specified, quat otherwise
+ */
+quat4.inverse = function(quat, dest) {
+ if(!dest || quat == dest) {
+ quat[0] *= -1;
+ quat[1] *= -1;
+ quat[2] *= -1;
+ return quat;
+ }
+ dest[0] = -quat[0];
+ dest[1] = -quat[1];
+ dest[2] = -quat[2];
+ dest[3] = quat[3];
+ return dest;
+};
+
+/*
+ * quat4.length
+ * Calculates the length of a quat4
+ *
+ * Params:
+ * quat - quat4 to calculate length of
+ *
+ * Returns:
+ * Length of quat
+ */
+quat4.length = function(quat) {
+ var x = quat[0], y = quat[1], z = quat[2], w = quat[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/*
+ * quat4.normalize
+ * Generates a unit quaternion of the same direction as the provided quat4
+ * If quaternion length is 0, returns [0, 0, 0, 0]
+ *
+ * Params:
+ * quat - quat4 to normalize
+ * dest - Optional, quat4 receiving operation result. If not specified result is written to quat
+ *
+ * Returns:
+ * dest if specified, quat otherwise
+ */
+quat4.normalize = function(quat, dest) {
+ if(!dest) { dest = quat; }
+
+ var x = quat[0], y = quat[1], z = quat[2], w = quat[3];
+ var len = Math.sqrt(x*x + y*y + z*z + w*w);
+ if(len == 0) {
+ dest[0] = 0;
+ dest[1] = 0;
+ dest[2] = 0;
+ dest[3] = 0;
+ return dest;
+ }
+ len = 1/len;
+ dest[0] = x * len;
+ dest[1] = y * len;
+ dest[2] = z * len;
+ dest[3] = w * len;
+
+ return dest;
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
@@ -7385,19 +8237,698 @@ define('rasterizer',["tracer"], function(Tracer) {
}
}
}
- };
+ };
+ }
+ };
+
+ return (Rasterizer);
+});
+
+/* jshint undef: true, unused: true, browser:true, devel: true, -W041: false */
+/* global define */
+
+define('skeletonizer',[],function() {
+ "use strict";
+
+ /* @preserve ASM BEGIN */
+ function Skeletonizer(stdlib, foreign, buffer) {
+ "use asm";
+
+ var images = new stdlib.Uint8Array(buffer),
+ size = foreign.size | 0,
+ imul = stdlib.Math.imul;
+
+ function erode(inImagePtr, outImagePtr) {
+ inImagePtr = inImagePtr | 0;
+ outImagePtr = outImagePtr | 0;
+
+ var v = 0,
+ u = 0,
+ sum = 0,
+ yStart1 = 0,
+ yStart2 = 0,
+ xStart1 = 0,
+ xStart2 = 0,
+ offset = 0;
+
+ for ( v = 1; (v | 0) < ((size - 1) | 0); v = (v + 1) | 0) {
+ offset = (offset + size) | 0;
+ for ( u = 1; (u | 0) < ((size - 1) | 0); u = (u + 1) | 0) {
+ yStart1 = (offset - size) | 0;
+ yStart2 = (offset + size) | 0;
+ xStart1 = (u - 1) | 0;
+ xStart2 = (u + 1) | 0;
+ sum = ((images[(inImagePtr + yStart1 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart1 + xStart2) | 0] | 0) + (images[(inImagePtr + offset + u) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart2) | 0] | 0)) | 0;
+ if ((sum | 0) == (5 | 0)) {
+ images[(outImagePtr + offset + u) | 0] = 1;
+ } else {
+ images[(outImagePtr + offset + u) | 0] = 0;
+ }
+ }
+ }
+ return;
+ }
+
+ function subtract(aImagePtr, bImagePtr, outImagePtr) {
+ aImagePtr = aImagePtr | 0;
+ bImagePtr = bImagePtr | 0;
+ outImagePtr = outImagePtr | 0;
+
+ var length = 0;
+
+ length = imul(size, size) | 0;
+
+ while ((length | 0) > 0) {
+ length = (length - 1) | 0;
+ images[(outImagePtr + length) | 0] = ((images[(aImagePtr + length) | 0] | 0) - (images[(bImagePtr + length) | 0] | 0)) | 0;
+ }
+ }
+
+ function bitwiseOr(aImagePtr, bImagePtr, outImagePtr) {
+ aImagePtr = aImagePtr | 0;
+ bImagePtr = bImagePtr | 0;
+ outImagePtr = outImagePtr | 0;
+
+ var length = 0;
+
+ length = imul(size, size) | 0;
+
+ while ((length | 0) > 0) {
+ length = (length - 1) | 0;
+ images[(outImagePtr + length) | 0] = ((images[(aImagePtr + length) | 0] | 0) | (images[(bImagePtr + length) | 0] | 0)) | 0;
+ }
+ }
+
+ function countNonZero(imagePtr) {
+ imagePtr = imagePtr | 0;
+
+ var sum = 0,
+ length = 0;
+
+ length = imul(size, size) | 0;
+
+ while ((length | 0) > 0) {
+ length = (length - 1) | 0;
+ sum = ((sum | 0) + (images[(imagePtr + length) | 0] | 0)) | 0;
+ }
+
+ return (sum | 0);
+ }
+
+ function init(imagePtr, value) {
+ imagePtr = imagePtr | 0;
+ value = value | 0;
+
+ var length = 0;
+
+ length = imul(size, size) | 0;
+
+ while ((length | 0) > 0) {
+ length = (length - 1) | 0;
+ images[(imagePtr + length) | 0] = value;
+ }
+ }
+
+ function dilate(inImagePtr, outImagePtr) {
+ inImagePtr = inImagePtr | 0;
+ outImagePtr = outImagePtr | 0;
+
+ var v = 0,
+ u = 0,
+ sum = 0,
+ yStart1 = 0,
+ yStart2 = 0,
+ xStart1 = 0,
+ xStart2 = 0,
+ offset = 0;
+
+ for ( v = 1; (v | 0) < ((size - 1) | 0); v = (v + 1) | 0) {
+ offset = (offset + size) | 0;
+ for ( u = 1; (u | 0) < ((size - 1) | 0); u = (u + 1) | 0) {
+ yStart1 = (offset - size) | 0;
+ yStart2 = (offset + size) | 0;
+ xStart1 = (u - 1) | 0;
+ xStart2 = (u + 1) | 0;
+ sum = ((images[(inImagePtr + yStart1 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart1 + xStart2) | 0] | 0) + (images[(inImagePtr + offset + u) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart2) | 0] | 0)) | 0;
+ if ((sum | 0) > (0 | 0)) {
+ images[(outImagePtr + offset + u) | 0] = 1;
+ } else {
+ images[(outImagePtr + offset + u) | 0] = 0;
+ }
+ }
+ }
+ return;
+ }
+
+ function memcpy(srcImagePtr, dstImagePtr) {
+ srcImagePtr = srcImagePtr | 0;
+ dstImagePtr = dstImagePtr | 0;
+
+ var length = 0;
+
+ length = imul(size, size) | 0;
+
+ while ((length | 0) > 0) {
+ length = (length - 1) | 0;
+ images[(dstImagePtr + length) | 0] = (images[(srcImagePtr + length) | 0] | 0);
+ }
+ }
+
+ function zeroBorder(imagePtr) {
+ imagePtr = imagePtr | 0;
+
+ var x = 0,
+ y = 0;
+
+ for ( x = 0; (x | 0) < ((size - 1) | 0); x = (x + 1) | 0) {
+ images[(imagePtr + x) | 0] = 0;
+ images[(imagePtr + y) | 0] = 0;
+ y = ((y + size) - 1) | 0;
+ images[(imagePtr + y) | 0] = 0;
+ y = (y + 1) | 0;
+ }
+ for ( x = 0; (x | 0) < (size | 0); x = (x + 1) | 0) {
+ images[(imagePtr + y) | 0] = 0;
+ y = (y + 1) | 0;
+ }
+ }
+
+ function skeletonize() {
+ var subImagePtr = 0,
+ erodedImagePtr = 0,
+ tempImagePtr = 0,
+ skelImagePtr = 0,
+ sum = 0,
+ done = 0;
+
+ erodedImagePtr = imul(size, size) | 0;
+ tempImagePtr = (erodedImagePtr + erodedImagePtr) | 0;
+ skelImagePtr = (tempImagePtr + erodedImagePtr) | 0;
+
+ // init skel-image
+ init(skelImagePtr, 0);
+ zeroBorder(subImagePtr);
+
+ do {
+ erode(subImagePtr, erodedImagePtr);
+ dilate(erodedImagePtr, tempImagePtr);
+ subtract(subImagePtr, tempImagePtr, tempImagePtr);
+ bitwiseOr(skelImagePtr, tempImagePtr, skelImagePtr);
+ memcpy(erodedImagePtr, subImagePtr);
+ sum = countNonZero(subImagePtr) | 0;
+ done = ((sum | 0) == 0 | 0);
+ } while(!done);
+ }
+
+ return {
+ skeletonize : skeletonize
+ };
+ }
+ /* @preserve ASM END */
+
+ return Skeletonizer;
+});
+
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define('image_debug',[],function() {
+ "use strict";
+
+ return {
+ drawRect: function(pos, size, ctx, style){
+ ctx.strokeStyle = style.color;
+ ctx.fillStyle = style.color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.strokeRect(pos.x, pos.y, size.x, size.y);
+ },
+ drawPath: function(path, def, ctx, style) {
+ ctx.strokeStyle = style.color;
+ ctx.fillStyle = style.color;
+ ctx.lineWidth = style.lineWidth;
+ ctx.beginPath();
+ ctx.moveTo(path[0][def.x], path[0][def.y]);
+ for (var j = 1; j < path.length; j++) {
+ ctx.lineTo(path[j][def.x], path[j][def.y]);
+ }
+ ctx.closePath();
+ ctx.stroke();
+ },
+ drawImage: function(imageData, size, ctx) {
+ var canvasData = ctx.getImageData(0, 0, size.x, size.y),
+ data = canvasData.data,
+ imageDataPos = imageData.length,
+ canvasDataPos = data.length,
+ value;
+
+ if (canvasDataPos/imageDataPos !== 4) {
+ return false;
+ }
+ while(imageDataPos--){
+ value = imageData[imageDataPos];
+ data[--canvasDataPos] = 255;
+ data[--canvasDataPos] = value;
+ data[--canvasDataPos] = value;
+ data[--canvasDataPos] = value;
+ }
+ ctx.putImageData(canvasData, 0, 0);
+ return true;
+ }
+ };
+
+});
+
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define, mat2, vec2 */
+
+define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug"],
+function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug) {
+
+ var _config,
+ _currentImageWrapper,
+ _skelImageWrapper,
+ _subImageWrapper,
+ _labelImageWrapper,
+ _patchGrid,
+ _patchLabelGrid,
+ _imageToPatchGrid,
+ _binaryImageWrapper,
+ _patchSize,
+ _canvasContainer = {
+ ctx : {
+ binary : null
+ },
+ dom : {
+ binary : null
+ }
+ },
+ _numPatches = {x: 0, y: 0},
+ _inputImageWrapper,
+ _skeletonizer,
+ self = this;
+
+ function initBuffers() {
+ var skeletonImageData;
+
+ if (_config.halfSample) {
+ _currentImageWrapper = new ImageWrapper({
+ x : _inputImageWrapper.size.x / 2 | 0,
+ y : _inputImageWrapper.size.y / 2 | 0
+ });
+ } else {
+ _currentImageWrapper = _inputImageWrapper;
+ }
+
+ _patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
+
+ _numPatches.x = _currentImageWrapper.size.x / _patchSize.x | 0;
+ _numPatches.y = _currentImageWrapper.size.y / _patchSize.y | 0;
+
+ _binaryImageWrapper = new ImageWrapper(_currentImageWrapper.size, undefined, Uint8Array, false);
+
+ _labelImageWrapper = new ImageWrapper(_patchSize, undefined, Array, true);
+
+ skeletonImageData = new ArrayBuffer(64*1024);
+ _subImageWrapper = new ImageWrapper(_patchSize, new Uint8Array(skeletonImageData, 0, _patchSize.x * _patchSize.y));
+ _skelImageWrapper = new ImageWrapper(_patchSize, new Uint8Array(skeletonImageData, _patchSize.x * _patchSize.y * 3, _patchSize.x * _patchSize.y), undefined, true);
+ _skeletonizer = skeletonizer(self, {
+ size : _patchSize.x
+ }, skeletonImageData);
+
+ _imageToPatchGrid = new ImageWrapper({
+ x : (_currentImageWrapper.size.x / _subImageWrapper.size.x) | 0,
+ y : (_currentImageWrapper.size.y / _subImageWrapper.size.y) | 0
+ }, undefined, Array, true);
+ _patchGrid = new ImageWrapper(_imageToPatchGrid.size, undefined, undefined, true);
+ _patchLabelGrid = new ImageWrapper(_imageToPatchGrid.size, undefined, Int32Array, true);
+ }
+
+ function initCanvas() {
+ if (_config.useWorker || typeof document === 'undefined') {
+ return;
+ }
+ _canvasContainer.dom.binary = document.createElement("canvas");
+ _canvasContainer.dom.binary.className = "binaryBuffer";
+ if (_config.showCanvas === true) {
+ document.querySelector("#debug").appendChild(_canvasContainer.dom.binary);
+ }
+ _canvasContainer.ctx.binary = _canvasContainer.dom.binary.getContext("2d");
+ _canvasContainer.dom.binary.width = _binaryImageWrapper.size.x;
+ _canvasContainer.dom.binary.height = _binaryImageWrapper.size.y;
+ }
+
+ /**
+ * Creates a bounding box which encloses all the given patches
+ * @returns {Array} The minimal bounding box
+ */
+ function boxFromPatches(patches) {
+ var overAvg, i, j, patch, transMat, minx = _binaryImageWrapper.size.x, miny = _binaryImageWrapper.size.y, maxx = -_binaryImageWrapper.size.x, maxy = -_binaryImageWrapper.size.y, box, scale;
+
+ // draw all patches which are to be taken into consideration
+ overAvg = 0;
+ for ( i = 0; i < patches.length; i++) {
+ patch = patches[i];
+ overAvg += patch.rad;
+ if (_config.showPatches) {
+ ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "red"});
+ }
+ }
+
+ overAvg /= patches.length;
+ overAvg = (overAvg * 180 / Math.PI + 90) % 180 - 90;
+ if (overAvg < 0) {
+ overAvg += 180;
+ }
+
+ //console.log(overAvg);
+ overAvg = (180 - overAvg) * Math.PI / 180;
+ transMat = mat2.create([Math.cos(overAvg), -Math.sin(overAvg), Math.sin(overAvg), Math.cos(overAvg)]);
+
+ // iterate over patches and rotate by angle
+ for ( i = 0; i < patches.length; i++) {
+ patch = patches[i];
+ for ( j = 0; j < 4; j++) {
+ mat2.xVec2(transMat, patch.box[j]);
+ }
+
+ if (_config.boxFromPatches.showTransformed) {
+ ImageDebug.drawPath(patch.box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#99ff00', lineWidth: 2});
+ }
+ }
+
+ // find bounding box
+ for ( i = 0; i < patches.length; i++) {
+ patch = patches[i];
+ for ( j = 0; j < 4; j++) {
+ if (patch.box[j][0] < minx) {
+ minx = patch.box[j][0];
+ }
+ if (patch.box[j][0] > maxx) {
+ maxx = patch.box[j][0];
+ }
+ if (patch.box[j][1] < miny) {
+ miny = patch.box[j][1];
+ }
+ if (patch.box[j][1] > maxy) {
+ maxy = patch.box[j][1];
+ }
+ }
+ }
+
+ box = [[minx, miny], [maxx, miny], [maxx, maxy], [minx, maxy]];
+
+ if (_config.boxFromPatches.showTransformedBox) {
+ ImageDebug.drawPath(box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#ff0000', lineWidth: 2});
+ }
+
+ scale = _config.halfSample ? 2 : 1;
+ // reverse rotation;
+ transMat = mat2.inverse(transMat);
+ for ( j = 0; j < 4; j++) {
+ mat2.xVec2(transMat, box[j]);
+ }
+
+ if (_config.boxFromPatches.showBB) {
+ ImageDebug.drawPath(box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#ff0000', lineWidth: 2});
+ }
+
+ for ( j = 0; j < 4; j++) {
+ vec2.scale(box[j], scale);
+ }
+
+ return box;
+ }
+
+ /**
+ * Creates a binary image of the current image
+ */
+ function binarizeImage() {
+ CVUtils.otsuThreshold(_currentImageWrapper, _binaryImageWrapper);
+ _binaryImageWrapper.zeroBorder();
+ if (_config.showCanvas) {
+ _binaryImageWrapper.show(_canvasContainer.dom.binary, 255);
+ }
+ }
+
+ /**
+ * Iterate over the entire image
+ * extract patches
+ */
+ function findPatches() {
+ var i,
+ j,
+ x,
+ y,
+ moments,
+ patchesFound = [],
+ rasterizer,
+ rasterResult,
+ patch;
+ for ( i = 0; i < _numPatches.x; i++) {
+ for ( j = 0; j < _numPatches.y; j++) {
+
+ x = _subImageWrapper.size.x * i;
+ y = _subImageWrapper.size.y * j;
+
+ // seperate parts
+ skeletonize(x, y);
+
+ // Rasterize, find individual bars
+ _skelImageWrapper.zeroBorder();
+ ArrayHelper.init(_labelImageWrapper.data, 0);
+ rasterizer = Rasterizer.create(_skelImageWrapper, _labelImageWrapper);
+ rasterResult = rasterizer.rasterize(0);
+
+ if (_config.showLabels) {
+ _labelImageWrapper.overlay(_canvasContainer.dom.binary, Math.floor(360 / rasterResult.count), {x : x, y : y});
+ }
+
+ // calculate moments from the skeletonized patch
+ moments = _labelImageWrapper.moments(rasterResult.count);
+
+ // extract eligible patches
+ patchesFound = patchesFound.concat(describePatch(moments, [i, j], x, y));
+ }
+ }
+
+ if (_config.showFoundPatches) {
+ for ( i = 0; i < patchesFound.length; i++) {
+ patch = patchesFound[i];
+ ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "#99ff00", lineWidth: 2});
+ }
+ }
+
+ return patchesFound;
+ }
+
+ /**
+ * Finds those connected areas which contain at least 6 patches
+ * and returns them ordered DESC by the number of contained patches
+ * @param {Number} maxLabel
+ */
+ function findBiggestConnectedAreas(maxLabel){
+ var i,
+ sum,
+ labelHist = [],
+ topLabels = [];
+
+ for ( i = 0; i < maxLabel; i++) {
+ labelHist.push(0);
+ }
+ sum = _patchLabelGrid.data.length;
+ while (sum--) {
+ if (_patchLabelGrid.data[sum] > 0) {
+ labelHist[_patchLabelGrid.data[sum] - 1]++;
+ }
+ }
+
+ labelHist = labelHist.map(function(val, idx) {
+ return {
+ val : val,
+ label : idx + 1
+ };
+ });
+
+ labelHist.sort(function(a, b) {
+ return b.val - a.val;
+ });
+
+ // extract top areas with at least 6 patches present
+ topLabels = labelHist.filter(function(el) {
+ return el.val >= 5;
+ });
+
+ return topLabels;
+ }
+
+ /**
+ *
+ */
+ function findBoxes(topLabels, maxLabel) {
+ var i,
+ j,
+ sum,
+ patches = [],
+ patch,
+ box,
+ boxes = [],
+ hsv = [0, 1, 1],
+ rgb = [0, 0, 0];
+
+ for ( i = 0; i < topLabels.length; i++) {
+ sum = _patchLabelGrid.data.length;
+ patches.length = 0;
+ while (sum--) {
+ if (_patchLabelGrid.data[sum] === topLabels[i].label) {
+ patch = _imageToPatchGrid.data[sum];
+ patches.push(patch);
+ }
+ }
+ box = boxFromPatches(patches);
+ if (box) {
+ boxes.push(box);
+
+ // draw patch-labels if requested
+ if (_config.showRemainingPatchLabels) {
+ for ( j = 0; j < patches.length; j++) {
+ patch = patches[j];
+ hsv[0] = (topLabels[i].label / (maxLabel + 1)) * 360;
+ CVUtils.hsv2rgb(hsv, rgb);
+ ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
+ }
+ }
+ }
+ }
+ return boxes;
+ }
+
+ /**
+ * Find similar moments (via cluster)
+ * @param {Object} moments
+ */
+ function similarMoments(moments) {
+ var clusters = CVUtils.cluster(moments, 0.90);
+ var topCluster = CVUtils.topGeneric(clusters, 1, function(e) {
+ return e.getPoints().length;
+ });
+ var points = [], result = [];
+ if (topCluster.length === 1) {
+ points = topCluster[0].item.getPoints();
+ for (var i = 0; i < points.length; i++) {
+ result.push(points[i].point);
+ }
+ }
+ return result;
+ }
+
+ function skeletonize(x, y) {
+ _binaryImageWrapper.subImageAsCopy(_subImageWrapper, CVUtils.imageRef(x, y));
+ _skeletonizer.skeletonize();
+
+ // Show skeleton if requested
+ if (_config.showSkeleton) {
+ _skelImageWrapper.overlay(_canvasContainer.dom.binary, 360, CVUtils.imageRef(x, y));
+ }
+ }
+
+ /**
+ * Extracts and describes those patches which seem to contain a barcode pattern
+ * @param {Array} moments
+ * @param {Object} patchPos,
+ * @param {Number} x
+ * @param {Number} y
+ * @returns {Array} list of patches
+ */
+ function describePatch(moments, patchPos, x, y) {
+ var k,
+ avg,
+ sum = 0,
+ eligibleMoments = [],
+ matchingMoments,
+ patch,
+ patchesFound = [],
+ minComponentWeight = Math.ceil(_patchSize.x/3);
+
+ if (moments.length >= 2) {
+ // only collect moments which's area covers at least minComponentWeight pixels.
+ for ( k = 0; k < moments.length; k++) {
+ if (moments[k].m00 > minComponentWeight) {
+ eligibleMoments.push(moments[k]);
+ }
+ }
+
+ // if at least 2 moments are found which have at least minComponentWeights covered
+ if (eligibleMoments.length >= 2) {
+ sum = eligibleMoments.length;
+ matchingMoments = similarMoments(eligibleMoments);
+ avg = 0;
+ // determine the similarity of the moments
+ for ( k = 0; k < matchingMoments.length; k++) {
+ avg += matchingMoments[k].rad;
+ }
+
+ // Only two of the moments are allowed not to fit into the equation
+ // add the patch to the set
+ if (matchingMoments.length > 1 && matchingMoments.length >= (eligibleMoments.length / 4) * 3 && matchingMoments.length > moments.length / 4) {
+ avg /= matchingMoments.length;
+ patch = {
+ index : patchPos[1] * _numPatches.x + patchPos[0],
+ pos : {
+ x : x,
+ y : y
+ },
+ box : [vec2.create([x, y]), vec2.create([x + _subImageWrapper.size.x, y]), vec2.create([x + _subImageWrapper.size.x, y + _subImageWrapper.size.y]), vec2.create([x, y + _subImageWrapper.size.y])],
+ moments : matchingMoments,
+ rad : avg,
+ vec : vec2.create([Math.cos(avg), Math.sin(avg)])
+ };
+ patchesFound.push(patch);
+ }
+ }
}
- };
+ return patchesFound;
+ }
- return (Rasterizer);
-});
+ /**
+ * finds patches which are connected and share the same orientation
+ * @param {Object} patchesFound
+ */
+ function rasterizeAngularSimilarity(patchesFound) {
+ var label = 0,
+ threshold = 0.95,
+ currIdx = 0,
+ j,
+ patch,
+ hsv = [0, 1, 1],
+ rgb = [0, 0, 0];
-/* jshint undef: true, unused: true, browser:true, devel: true, -W041: false */
-/* global define */
+ function notYetProcessed() {
+ var i;
+ for ( i = 0; i < _patchLabelGrid.data.length; i++) {
+ if (_patchLabelGrid.data[i] === 0 && _patchGrid.data[i] === 1) {
+ return i;
+ }
+ }
+ return _patchLabelGrid.length;
+ }
-define('skeletonizer',[],function() {
- "use strict";
+ function trace(currentIdx) {
+ var x, y, currentPatch, patch, idx, dir, current = {
+ x : currentIdx % _patchLabelGrid.size.x,
+ y : (currentIdx / _patchLabelGrid.size.x) | 0
+ }, similarity;
+
+ if (currentIdx < _patchLabelGrid.data.length) {
+ currentPatch = _imageToPatchGrid.data[currentIdx];
+ // assign label
+ _patchLabelGrid.data[currentIdx] = label;
+ for ( dir = 0; dir < Tracer.searchDirections.length; dir++) {
+ y = current.y + Tracer.searchDirections[dir][0];
+ x = current.x + Tracer.searchDirections[dir][1];
+ idx = y * _patchLabelGrid.size.x + x;
+<<<<<<< HEAD
Math.imul = Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
@@ -7411,254 +8942,360 @@ define('skeletonizer',[],function() {
/* @preserve ASM BEGIN */
function Skeletonizer(stdlib, foreign, buffer) {
"use asm";
+=======
+ // continue if patch empty
+ if (_patchGrid.data[idx] === 0) {
+ _patchLabelGrid.data[idx] = Number.MAX_VALUE;
+ continue;
+ }
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
- var images = new stdlib.Uint8Array(buffer),
- size = foreign.size | 0,
- imul = stdlib.Math.imul;
+ patch = _imageToPatchGrid.data[idx];
+ if (_patchLabelGrid.data[idx] === 0) {
+ similarity = Math.abs(vec2.dot(patch.vec, currentPatch.vec));
+ if (similarity > threshold) {
+ trace(idx);
+ }
+ }
+ }
+ }
+ }
+
+ // prepare for finding the right patches
+ ArrayHelper.init(_patchGrid.data, 0);
+ ArrayHelper.init(_patchLabelGrid.data, 0);
+ ArrayHelper.init(_imageToPatchGrid.data, null);
- function erode(inImagePtr, outImagePtr) {
- inImagePtr = inImagePtr | 0;
- outImagePtr = outImagePtr | 0;
+ for ( j = 0; j < patchesFound.length; j++) {
+ patch = patchesFound[j];
+ _imageToPatchGrid.data[patch.index] = patch;
+ _patchGrid.data[patch.index] = 1;
+ }
- var v = 0,
- u = 0,
- sum = 0,
- yStart1 = 0,
- yStart2 = 0,
- xStart1 = 0,
- xStart2 = 0,
- offset = 0;
+ // rasterize the patches found to determine area
+ _patchGrid.zeroBorder();
- for ( v = 1; (v | 0) < ((size - 1) | 0); v = (v + 1) | 0) {
- offset = (offset + size) | 0;
- for ( u = 1; (u | 0) < ((size - 1) | 0); u = (u + 1) | 0) {
- yStart1 = (offset - size) | 0;
- yStart2 = (offset + size) | 0;
- xStart1 = (u - 1) | 0;
- xStart2 = (u + 1) | 0;
- sum = ((images[(inImagePtr + yStart1 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart1 + xStart2) | 0] | 0) + (images[(inImagePtr + offset + u) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart2) | 0] | 0)) | 0;
- if ((sum | 0) == (5 | 0)) {
- images[(outImagePtr + offset + u) | 0] = 1;
- } else {
- images[(outImagePtr + offset + u) | 0] = 0;
- }
+ while (( currIdx = notYetProcessed()) < _patchLabelGrid.data.length) {
+ label++;
+ trace(currIdx);
+ }
+
+ // draw patch-labels if requested
+ if (_config.showPatchLabels) {
+ for ( j = 0; j < _patchLabelGrid.data.length; j++) {
+ if (_patchLabelGrid.data[j] > 0 && _patchLabelGrid.data[j] <= label) {
+ patch = _imageToPatchGrid.data[j];
+ hsv[0] = (_patchLabelGrid.data[j] / (label + 1)) * 360;
+ CVUtils.hsv2rgb(hsv, rgb);
+ ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
}
}
- return;
}
+
+ return label;
+ }
- function subtract(aImagePtr, bImagePtr, outImagePtr) {
- aImagePtr = aImagePtr | 0;
- bImagePtr = bImagePtr | 0;
- outImagePtr = outImagePtr | 0;
+ return {
+ init : function(inputImageWrapper, config) {
+ _config = config;
+ _inputImageWrapper = inputImageWrapper;
- var length = 0;
+ initBuffers();
+ initCanvas();
+ },
- length = imul(size, size) | 0;
+ locate : function() {
+ var patchesFound,
+ topLabels,
+ boxes;
- while ((length | 0) > 0) {
- length = (length - 1) | 0;
- images[(outImagePtr + length) | 0] = ((images[(aImagePtr + length) | 0] | 0) - (images[(bImagePtr + length) | 0] | 0)) | 0;
+ if (_config.halfSample) {
+ CVUtils.halfSample(_inputImageWrapper, _currentImageWrapper);
}
- }
- function bitwiseOr(aImagePtr, bImagePtr, outImagePtr) {
- aImagePtr = aImagePtr | 0;
- bImagePtr = bImagePtr | 0;
- outImagePtr = outImagePtr | 0;
+ binarizeImage();
+ patchesFound = findPatches();
+ // return unless 5% or more patches are found
+ if (patchesFound.length < _numPatches.x * _numPatches.y * 0.05) {
+ return null;
+ }
- var length = 0;
+ // rasterrize area by comparing angular similarity;
+ var maxLabel = rasterizeAngularSimilarity(patchesFound);
+ if (maxLabel < 1) {
+ return null;
+ }
- length = imul(size, size) | 0;
+ // search for area with the most patches (biggest connected area)
+ topLabels = findBiggestConnectedAreas(maxLabel);
+ if (topLabels.length === 0) {
+ return null;
+ }
- while ((length | 0) > 0) {
- length = (length - 1) | 0;
- images[(outImagePtr + length) | 0] = ((images[(aImagePtr + length) | 0] | 0) | (images[(bImagePtr + length) | 0] | 0)) | 0;
+ boxes = findBoxes(topLabels, maxLabel);
+ return boxes;
+ },
+
+ checkImageConstraints: function(inputStream, config) {
+ var patchSize,
+ width = inputStream.getWidth(),
+ height = inputStream.getHeight(),
+ halfSample = config.halfSample ? 0.5 : 1,
+ size,
+ area;
+
+ // calculate width and height based on area
+ if (inputStream.getConfig().area) {
+ area = CVUtils.computeImageArea(width, height, inputStream.getConfig().area);
+ inputStream.setTopRight({x: area.sx, y: area.sy});
+ inputStream.setCanvasSize({x: width, y: height});
+ width = area.sw;
+ height = area.sh;
}
- }
- function countNonZero(imagePtr) {
- imagePtr = imagePtr | 0;
+ size = {
+ x: Math.floor(width * halfSample),
+ y: Math.floor(height * halfSample)
+ };
- var sum = 0,
- length = 0;
+ patchSize = CVUtils.calculatePatchSize(config.patchSize, size);
+ console.log("Patch-Size: " + JSON.stringify(patchSize));
- length = imul(size, size) | 0;
+ inputStream.setWidth(Math.floor(Math.floor(size.x/patchSize.x)*(1/halfSample)*patchSize.x));
+ inputStream.setHeight(Math.floor(Math.floor(size.y/patchSize.y)*(1/halfSample)*patchSize.y));
- while ((length | 0) > 0) {
- length = (length - 1) | 0;
- sum = ((sum | 0) + (images[(imagePtr + length) | 0] | 0)) | 0;
+ if ((inputStream.getWidth() % patchSize.x) === 0 && (inputStream.getHeight() % patchSize.y) === 0) {
+ return true;
}
- return (sum | 0);
+ throw new Error("Image dimensions do not comply with the current settings: Width (" +
+ width + " )and height (" + height +
+ ") must a multiple of " + patchSize.x);
+ }
+ };
+});
+
+
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define('bresenham',["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper) {
+ "use strict";
+ var Bresenham = {};
+
+ var Slope = {
+ DIR : {
+ UP : 1,
+ DOWN : -1
+ }
+ };
+ /**
+ * Scans a line of the given image from point p1 to p2 and returns a result object containing
+ * gray-scale values (0-255) of the underlying pixels in addition to the min
+ * and max values.
+ * @param {Object} imageWrapper
+ * @param {Object} p1 The start point {x,y}
+ * @param {Object} p2 The end point {x,y}
+ * @returns {line, min, max}
+ */
+ Bresenham.getBarcodeLine = function(imageWrapper, p1, p2) {
+ var x0 = p1.x | 0,
+ y0 = p1.y | 0,
+ x1 = p2.x | 0,
+ y1 = p2.y | 0,
+ steep = Math.abs(y1 - y0) > Math.abs(x1 - x0),
+ deltax,
+ deltay,
+ error,
+ ystep,
+ y,
+ tmp,
+ x,
+ line = [],
+ imageData = imageWrapper.data,
+ width = imageWrapper.size.x,
+ sum = 0,
+ val,
+ min = 255,
+ max = 0;
+
+ function read(a, b) {
+ val = imageData[b * width + a];
+ sum += val;
+ min = val < min ? val : min;
+ max = val > max ? val : max;
+ line.push(val);
}
- function init(imagePtr, value) {
- imagePtr = imagePtr | 0;
- value = value | 0;
-
- var length = 0;
-
- length = imul(size, size) | 0;
+ if (steep) {
+ tmp = x0;
+ x0 = y0;
+ y0 = tmp;
- while ((length | 0) > 0) {
- length = (length - 1) | 0;
- images[(imagePtr + length) | 0] = value;
- }
+ tmp = x1;
+ x1 = y1;
+ y1 = tmp;
}
+ if (x0 > x1) {
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp;
- function dilate(inImagePtr, outImagePtr) {
- inImagePtr = inImagePtr | 0;
- outImagePtr = outImagePtr | 0;
-
- var v = 0,
- u = 0,
- sum = 0,
- yStart1 = 0,
- yStart2 = 0,
- xStart1 = 0,
- xStart2 = 0,
- offset = 0;
-
- for ( v = 1; (v | 0) < ((size - 1) | 0); v = (v + 1) | 0) {
- offset = (offset + size) | 0;
- for ( u = 1; (u | 0) < ((size - 1) | 0); u = (u + 1) | 0) {
- yStart1 = (offset - size) | 0;
- yStart2 = (offset + size) | 0;
- xStart1 = (u - 1) | 0;
- xStart2 = (u + 1) | 0;
- sum = ((images[(inImagePtr + yStart1 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart1 + xStart2) | 0] | 0) + (images[(inImagePtr + offset + u) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart1) | 0] | 0) + (images[(inImagePtr + yStart2 + xStart2) | 0] | 0)) | 0;
- if ((sum | 0) > (0 | 0)) {
- images[(outImagePtr + offset + u) | 0] = 1;
- } else {
- images[(outImagePtr + offset + u) | 0] = 0;
- }
- }
+ tmp = y0;
+ y0 = y1;
+ y1 = tmp;
+ }
+ deltax = x1 - x0;
+ deltay = Math.abs(y1 - y0);
+ error = (deltax / 2) | 0;
+ y = y0;
+ ystep = y0 < y1 ? 1 : -1;
+ for ( x = x0; x < x1; x++) {
+ if(steep){
+ read(y, x);
+ } else {
+ read(x, y);
+ }
+ error = error - deltay;
+ if (error < 0) {
+ y = y + ystep;
+ error = error + deltax;
}
- return;
}
- function memcpy(srcImagePtr, dstImagePtr) {
- srcImagePtr = srcImagePtr | 0;
- dstImagePtr = dstImagePtr | 0;
-
- var length = 0;
+ return {
+ line : line,
+ min : min,
+ max : max
+ };
+ };
- length = imul(size, size) | 0;
+ Bresenham.toOtsuBinaryLine = function(result) {
+ var line = result.line,
+ image = new ImageWrapper({x: line.length - 1, y: 1}, line),
+ threshold = CVUtils.determineOtsuThreshold(image, 5);
- while ((length | 0) > 0) {
- length = (length - 1) | 0;
- images[(dstImagePtr + length) | 0] = (images[(srcImagePtr + length) | 0] | 0);
- }
- }
+ line = CVUtils.sharpenLine(line);
+ CVUtils.thresholdImage(image, threshold);
- function zeroBorder(imagePtr) {
- imagePtr = imagePtr | 0;
+ return {
+ line: line,
+ threshold: threshold
+ };
+ };
+
+ /**
+ * Converts the result from getBarcodeLine into a binary representation
+ * also considering the frequency and slope of the signal for more robust results
+ * @param {Object} result {line, min, max}
+ */
+ Bresenham.toBinaryLine = function(result) {
- var x = 0,
- y = 0;
+ var min = result.min,
+ max = result.max,
+ line = result.line,
+ slope,
+ slope2,
+ center = min + (max - min) / 2,
+ extrema = [],
+ currentDir,
+ dir,
+ threshold = (max - min) / 12,
+ rThreshold = -threshold,
+ i,
+ j;
- for ( x = 0; (x | 0) < ((size - 1) | 0); x = (x + 1) | 0) {
- images[(imagePtr + x) | 0] = 0;
- images[(imagePtr + y) | 0] = 0;
- y = ((y + size) - 1) | 0;
- images[(imagePtr + y) | 0] = 0;
- y = (y + 1) | 0;
+ // 1. find extrema
+ currentDir = line[0] > center ? Slope.DIR.UP : Slope.DIR.DOWN;
+ extrema.push({
+ pos : 0,
+ val : line[0]
+ });
+ for ( i = 0; i < line.length - 2; i++) {
+ slope = (line[i + 1] - line[i]);
+ slope2 = (line[i + 2] - line[i + 1]);
+ if ((slope + slope2) < rThreshold && line[i + 1] < (center*1.5)) {
+ dir = Slope.DIR.DOWN;
+ } else if ((slope + slope2) > threshold && line[i + 1] > (center*0.5)) {
+ dir = Slope.DIR.UP;
+ } else {
+ dir = currentDir;
}
- for ( x = 0; (x | 0) < (size | 0); x = (x + 1) | 0) {
- images[(imagePtr + y) | 0] = 0;
- y = (y + 1) | 0;
+
+ if (currentDir !== dir) {
+ extrema.push({
+ pos : i,
+ val : line[i]
+ });
+ currentDir = dir;
}
}
+ extrema.push({
+ pos : line.length,
+ val : line[line.length - 1]
+ });
- function skeletonize() {
- var subImagePtr = 0,
- erodedImagePtr = 0,
- tempImagePtr = 0,
- skelImagePtr = 0,
- sum = 0,
- done = 0;
-
- erodedImagePtr = imul(size, size) | 0;
- tempImagePtr = (erodedImagePtr + erodedImagePtr) | 0;
- skelImagePtr = (tempImagePtr + erodedImagePtr) | 0;
+ for ( j = extrema[0].pos; j < extrema[1].pos; j++) {
+ line[j] = line[j] > center ? 0 : 1;
+ }
- // init skel-image
- init(skelImagePtr, 0);
- zeroBorder(subImagePtr);
+ // iterate over extrema and convert to binary based on avg between minmax
+ for ( i = 1; i < extrema.length - 1; i++) {
+ if (extrema[i + 1].val > extrema[i].val) {
+ threshold = (extrema[i].val + ((extrema[i + 1].val - extrema[i].val) / 3) * 2) | 0;
+ } else {
+ threshold = (extrema[i + 1].val + ((extrema[i].val - extrema[i + 1].val) / 3)) | 0;
+ }
- do {
- erode(subImagePtr, erodedImagePtr);
- dilate(erodedImagePtr, tempImagePtr);
- subtract(subImagePtr, tempImagePtr, tempImagePtr);
- bitwiseOr(skelImagePtr, tempImagePtr, skelImagePtr);
- memcpy(erodedImagePtr, subImagePtr);
- sum = countNonZero(subImagePtr) | 0;
- done = ((sum | 0) == 0 | 0);
- } while(!done);
+ for ( j = extrema[i].pos; j < extrema[i + 1].pos; j++) {
+ line[j] = line[j] > threshold ? 0 : 1;
+ }
}
return {
- skeletonize : skeletonize
+ line : line,
+ threshold : threshold
};
- }
- /* @preserve ASM END */
-
- return Skeletonizer;
-});
-
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-
-define('image_debug',[],function() {
- "use strict";
+ };
+
+ /**
+ * Used for development only
+ */
+ Bresenham.debug = {
+ printFrequency: function(line, canvas) {
+ var i,
+ ctx = canvas.getContext("2d");
+ canvas.width = line.length;
+ canvas.height = 256;
- return {
- drawRect: function(pos, size, ctx, style){
- ctx.strokeStyle = style.color;
- ctx.fillStyle = style.color;
- ctx.lineWidth = 1;
- ctx.beginPath();
- ctx.strokeRect(pos.x, pos.y, size.x, size.y);
- },
- drawPath: function(path, def, ctx, style) {
- ctx.strokeStyle = style.color;
- ctx.fillStyle = style.color;
- ctx.lineWidth = style.lineWidth;
ctx.beginPath();
- ctx.moveTo(path[0][def.x], path[0][def.y]);
- for (var j = 1; j < path.length; j++) {
- ctx.lineTo(path[j][def.x], path[j][def.y]);
- }
- ctx.closePath();
- ctx.stroke();
- },
- drawImage: function(imageData, size, ctx) {
- var canvasData = ctx.getImageData(0, 0, size.x, size.y),
- data = canvasData.data,
- imageDataPos = imageData.length,
- canvasDataPos = data.length,
- value;
-
- if (canvasDataPos/imageDataPos !== 4) {
- return false;
+ ctx.strokeStyle = "blue";
+ for ( i = 0; i < line.length; i++) {
+ ctx.moveTo(i, 255);
+ ctx.lineTo(i, 255 - line[i]);
}
- while(imageDataPos--){
- value = imageData[imageDataPos];
- data[--canvasDataPos] = 255;
- data[--canvasDataPos] = value;
- data[--canvasDataPos] = value;
- data[--canvasDataPos] = value;
+ ctx.stroke();
+ ctx.closePath();
+ },
+
+ printPattern: function(line, canvas) {
+ var ctx = canvas.getContext("2d"), i;
+
+ canvas.width = line.length;
+ ctx.fillColor = "black";
+ for ( i = 0; i < line.length; i++) {
+ if (line[i] === 1) {
+ ctx.fillRect(i, 0, 1, 100);
+ }
}
- ctx.putImageData(canvasData, 0, 0);
- return true;
}
};
-
-});
+ return (Bresenham);
+});
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
+<<<<<<< HEAD
define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug", "gl-matrix"],
function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug, glMatrix) {
@@ -7687,346 +9324,679 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
vec2 = glMatrix.vec2,
mat2 = glMatrix.mat2,
self = this;
+=======
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
- function initBuffers() {
- var skeletonImageData;
+define(
+ 'barcode_reader',[],function() {
+ "use strict";
- if (_config.halfSample) {
- _currentImageWrapper = new ImageWrapper({
- x : _inputImageWrapper.size.x / 2 | 0,
- y : _inputImageWrapper.size.y / 2 | 0
- });
- } else {
- _currentImageWrapper = _inputImageWrapper;
+ function BarcodeReader(config) {
+ this._row = [];
+ this.config = config || {};
+ return this;
}
+
+ BarcodeReader.prototype._nextUnset = function(line, start) {
+ var i;
+
+ if (start === undefined) {
+ start = 0;
+ }
+ for (i = start; i < line.length; i++) {
+ if (!line[i]) {
+ return i;
+ }
+ }
+ return line.length;
+ };
+
+ BarcodeReader.prototype._matchPattern = function(counter, code) {
+ var i,
+ error = 0,
+ singleError = 0,
+ modulo = this.MODULO,
+ maxSingleError = this.SINGLE_CODE_ERROR || 1;
+
+ for (i = 0; i < counter.length; i++) {
+ singleError = Math.abs(code[i] - counter[i]);
+ if (singleError > maxSingleError) {
+ return Number.MAX_VALUE;
+ }
+ error += singleError;
+ }
+ return error/modulo;
+ };
- _patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
-
- _numPatches.x = _currentImageWrapper.size.x / _patchSize.x | 0;
- _numPatches.y = _currentImageWrapper.size.y / _patchSize.y | 0;
+ BarcodeReader.prototype._nextSet = function(line, offset) {
+ var i;
- _binaryImageWrapper = new ImageWrapper(_currentImageWrapper.size, undefined, Uint8Array, false);
+ offset = offset || 0;
+ for (i = offset; i < line.length; i++) {
+ if (line[i]) {
+ return i;
+ }
+ }
+ return line.length;
+ };
- _labelImageWrapper = new ImageWrapper(_patchSize, undefined, Array, true);
+ BarcodeReader.prototype._normalize = function(counter, modulo) {
+ var i,
+ self = this,
+ sum = 0,
+ ratio,
+ numOnes = 0,
+ normalized = [],
+ norm = 0;
+
+ if (!modulo) {
+ modulo = self.MODULO;
+ }
+ for (i = 0; i < counter.length; i++) {
+ if (counter[i] === 1) {
+ numOnes++;
+ } else {
+ sum += counter[i];
+ }
+ }
+ ratio = sum / (modulo - numOnes);
+ if (ratio > 1.0) {
+ for (i = 0; i < counter.length; i++) {
+ norm = counter[i] === 1 ? counter[i] : counter[i] / ratio;
+ normalized.push(norm);
+ }
+ } else {
+ ratio = (sum + numOnes)/modulo;
+ for (i = 0; i < counter.length; i++) {
+ norm = counter[i] / ratio;
+ normalized.push(norm);
+ }
+ }
+ return normalized;
+ };
- skeletonImageData = new ArrayBuffer(64*1024);
- _subImageWrapper = new ImageWrapper(_patchSize, new Uint8Array(skeletonImageData, 0, _patchSize.x * _patchSize.y));
- _skelImageWrapper = new ImageWrapper(_patchSize, new Uint8Array(skeletonImageData, _patchSize.x * _patchSize.y * 3, _patchSize.x * _patchSize.y), undefined, true);
- _skeletonizer = skeletonizer(self, {
- size : _patchSize.x
- }, skeletonImageData);
+ BarcodeReader.prototype._matchTrace = function(cmpCounter, epsilon) {
+ var counter = [],
+ i,
+ self = this,
+ offset = self._nextSet(self._row),
+ isWhite = !self._row[offset],
+ counterPos = 0,
+ bestMatch = {
+ error : Number.MAX_VALUE,
+ code : -1,
+ start : 0
+ },
+ error;
- _imageToPatchGrid = new ImageWrapper({
- x : (_currentImageWrapper.size.x / _subImageWrapper.size.x) | 0,
- y : (_currentImageWrapper.size.y / _subImageWrapper.size.y) | 0
- }, undefined, Array, true);
- _patchGrid = new ImageWrapper(_imageToPatchGrid.size, undefined, undefined, true);
- _patchLabelGrid = new ImageWrapper(_imageToPatchGrid.size, undefined, Int32Array, true);
- }
+ if (cmpCounter) {
+ for ( i = 0; i < cmpCounter.length; i++) {
+ counter.push(0);
+ }
+ for ( i = offset; i < self._row.length; i++) {
+ if (self._row[i] ^ isWhite) {
+ counter[counterPos]++;
+ } else {
+ if (counterPos === counter.length - 1) {
+ error = self._matchPattern(counter, cmpCounter);
- function initCanvas() {
- if (_config.useWorker || typeof document === 'undefined') {
- return;
+ if (error < epsilon) {
+ bestMatch.start = i - offset;
+ bestMatch.end = i;
+ bestMatch.counter = counter;
+ return bestMatch;
+ } else {
+ return null;
+ }
+ } else {
+ counterPos++;
+ }
+ counter[counterPos] = 1;
+ isWhite = !isWhite;
+ }
+ }
+ } else {
+ counter.push(0);
+ for ( i = offset; i < self._row.length; i++) {
+ if (self._row[i] ^ isWhite) {
+ counter[counterPos]++;
+ } else {
+ counterPos++;
+ counter.push(0);
+ counter[counterPos] = 1;
+ isWhite = !isWhite;
+ }
+ }
+ }
+<<<<<<< HEAD
}
- _canvasContainer.dom.binary = document.createElement("canvas");
- _canvasContainer.dom.binary.className = "binaryBuffer";
- if (_config.showCanvas === true) {
- document.querySelector("#debug").appendChild(_canvasContainer.dom.binary);
+
+ overAvg /= patches.length;
+ overAvg = (overAvg * 180 / Math.PI + 90) % 180 - 90;
+ if (overAvg < 0) {
+ overAvg += 180;
}
- _canvasContainer.ctx.binary = _canvasContainer.dom.binary.getContext("2d");
- _canvasContainer.dom.binary.width = _binaryImageWrapper.size.x;
- _canvasContainer.dom.binary.height = _binaryImageWrapper.size.y;
- }
- /**
- * Creates a bounding box which encloses all the given patches
- * @returns {Array} The minimal bounding box
- */
- function boxFromPatches(patches) {
- var overAvg, i, j, patch, transMat, minx = _binaryImageWrapper.size.x, miny = _binaryImageWrapper.size.y, maxx = -_binaryImageWrapper.size.x, maxy = -_binaryImageWrapper.size.y, box, scale;
+ overAvg = (180 - overAvg) * Math.PI / 180;
+ transMat = mat2.clone([Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]);
+
+ // iterate over patches and rotate by angle
+ for ( i = 0; i < patches.length; i++) {
+ patch = patches[i];
+ for ( j = 0; j < 4; j++) {
+ vec2.transformMat2(patch.box[j], patch.box[j], transMat);
+=======
+
+ // if cmpCounter was not given
+ bestMatch.start = offset;
+ bestMatch.end = self._row.length - 1;
+ bestMatch.counter = counter;
+ return bestMatch;
+ };
+
+ BarcodeReader.prototype.decodePattern = function(pattern) {
+ var self = this,
+ result;
+
+ self._row = pattern;
+ result = self._decode();
+ if (result === null) {
+ self._row.reverse();
+ result = self._decode();
+ if (result) {
+ result.direction = BarcodeReader.DIRECTION.REVERSE;
+ result.start = self._row.length - result.start;
+ result.end = self._row.length - result.end;
+ }
+ } else {
+ result.direction = BarcodeReader.DIRECTION.FORWARD;
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
+ }
+ if (result) {
+ result.format = self.FORMAT;
+ }
+ return result;
+ };
+
+ BarcodeReader.prototype._matchRange = function(start, end, value) {
+ var i;
+
+ start = start < 0 ? 0 : start;
+ for (i = start; i < end; i++) {
+ if (this._row[i] !== value) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ BarcodeReader.prototype._fillCounters = function(offset, end, isWhite) {
+ var self = this,
+ counterPos = 0,
+ i,
+ counters = [];
+
+ isWhite = (typeof isWhite !== 'undefined') ? isWhite : true;
+ offset = (typeof offset !== 'undefined') ? offset : self._nextUnset(self._row);
+ end = end || self._row.length;
- // draw all patches which are to be taken into consideration
- overAvg = 0;
- for ( i = 0; i < patches.length; i++) {
- patch = patches[i];
- overAvg += patch.rad;
- if (_config.showPatches) {
- ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "red"});
- }
+<<<<<<< HEAD
+ scale = _config.halfSample ? 2 : 1;
+ // reverse rotation;
+ transMat = mat2.invert(transMat, transMat);
+ for ( j = 0; j < 4; j++) {
+ vec2.transformMat2(box[j], box[j], transMat);
}
+=======
+ counters[counterPos] = 0;
+ for (i = offset; i < end; i++) {
+ if (self._row[i] ^ isWhite) {
+ counters[counterPos]++;
+ } else {
+ counterPos++;
+ counters[counterPos] = 1;
+ isWhite = !isWhite;
+ }
+ }
+ return counters;
+ };
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
- overAvg /= patches.length;
- overAvg = (overAvg * 180 / Math.PI + 90) % 180 - 90;
- if (overAvg < 0) {
- overAvg += 180;
+ Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
+ value: 'unknown',
+ writeable: false
+ });
+
+<<<<<<< HEAD
+ for ( j = 0; j < 4; j++) {
+ vec2.scale(box[j], box[j], scale);
}
+=======
+ BarcodeReader.DIRECTION = {
+ FORWARD : 1,
+ REVERSE : -1
+ };
+
+ BarcodeReader.Exception = {
+ StartNotFoundException : "Start-Info was not found!",
+ CodeNotFoundException : "Code could not be found!",
+ PatternNotFoundException : "Pattern could not be found!"
+ };
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
- overAvg = (180 - overAvg) * Math.PI / 180;
- transMat = mat2.clone([Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]);
+ BarcodeReader.CONFIG_KEYS = {};
+
+ return (BarcodeReader);
+ }
+);
- // iterate over patches and rotate by angle
- for ( i = 0; i < patches.length; i++) {
- patch = patches[i];
- for ( j = 0; j < 4; j++) {
- vec2.transformMat2(patch.box[j], patch.box[j], transMat);
- }
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
- if (_config.boxFromPatches.showTransformed) {
- ImageDebug.drawPath(patch.box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#99ff00', lineWidth: 2});
- }
+define(
+ 'code_128_reader',[
+ "./barcode_reader"
+ ],
+ function(BarcodeReader) {
+ "use strict";
+
+ function Code128Reader() {
+ BarcodeReader.call(this);
}
+
+ var properties = {
+ CODE_SHIFT : {value: 98},
+ CODE_C : {value: 99},
+ CODE_B : {value: 100},
+ CODE_A : {value: 101},
+ START_CODE_A : {value: 103},
+ START_CODE_B : {value: 104},
+ START_CODE_C : {value: 105},
+ STOP_CODE : {value: 106},
+ MODULO : {value: 11},
+ CODE_PATTERN : {value: [
+ [2, 1, 2, 2, 2, 2],
+ [2, 2, 2, 1, 2, 2],
+ [2, 2, 2, 2, 2, 1],
+ [1, 2, 1, 2, 2, 3],
+ [1, 2, 1, 3, 2, 2],
+ [1, 3, 1, 2, 2, 2],
+ [1, 2, 2, 2, 1, 3],
+ [1, 2, 2, 3, 1, 2],
+ [1, 3, 2, 2, 1, 2],
+ [2, 2, 1, 2, 1, 3],
+ [2, 2, 1, 3, 1, 2],
+ [2, 3, 1, 2, 1, 2],
+ [1, 1, 2, 2, 3, 2],
+ [1, 2, 2, 1, 3, 2],
+ [1, 2, 2, 2, 3, 1],
+ [1, 1, 3, 2, 2, 2],
+ [1, 2, 3, 1, 2, 2],
+ [1, 2, 3, 2, 2, 1],
+ [2, 2, 3, 2, 1, 1],
+ [2, 2, 1, 1, 3, 2],
+ [2, 2, 1, 2, 3, 1],
+ [2, 1, 3, 2, 1, 2],
+ [2, 2, 3, 1, 1, 2],
+ [3, 1, 2, 1, 3, 1],
+ [3, 1, 1, 2, 2, 2],
+ [3, 2, 1, 1, 2, 2],
+ [3, 2, 1, 2, 2, 1],
+ [3, 1, 2, 2, 1, 2],
+ [3, 2, 2, 1, 1, 2],
+ [3, 2, 2, 2, 1, 1],
+ [2, 1, 2, 1, 2, 3],
+ [2, 1, 2, 3, 2, 1],
+ [2, 3, 2, 1, 2, 1],
+ [1, 1, 1, 3, 2, 3],
+ [1, 3, 1, 1, 2, 3],
+ [1, 3, 1, 3, 2, 1],
+ [1, 1, 2, 3, 1, 3],
+ [1, 3, 2, 1, 1, 3],
+ [1, 3, 2, 3, 1, 1],
+ [2, 1, 1, 3, 1, 3],
+ [2, 3, 1, 1, 1, 3],
+ [2, 3, 1, 3, 1, 1],
+ [1, 1, 2, 1, 3, 3],
+ [1, 1, 2, 3, 3, 1],
+ [1, 3, 2, 1, 3, 1],
+ [1, 1, 3, 1, 2, 3],
+ [1, 1, 3, 3, 2, 1],
+ [1, 3, 3, 1, 2, 1],
+ [3, 1, 3, 1, 2, 1],
+ [2, 1, 1, 3, 3, 1],
+ [2, 3, 1, 1, 3, 1],
+ [2, 1, 3, 1, 1, 3],
+ [2, 1, 3, 3, 1, 1],
+ [2, 1, 3, 1, 3, 1],
+ [3, 1, 1, 1, 2, 3],
+ [3, 1, 1, 3, 2, 1],
+ [3, 3, 1, 1, 2, 1],
+ [3, 1, 2, 1, 1, 3],
+ [3, 1, 2, 3, 1, 1],
+ [3, 3, 2, 1, 1, 1],
+ [3, 1, 4, 1, 1, 1],
+ [2, 2, 1, 4, 1, 1],
+ [4, 3, 1, 1, 1, 1],
+ [1, 1, 1, 2, 2, 4],
+ [1, 1, 1, 4, 2, 2],
+ [1, 2, 1, 1, 2, 4],
+ [1, 2, 1, 4, 2, 1],
+ [1, 4, 1, 1, 2, 2],
+ [1, 4, 1, 2, 2, 1],
+ [1, 1, 2, 2, 1, 4],
+ [1, 1, 2, 4, 1, 2],
+ [1, 2, 2, 1, 1, 4],
+ [1, 2, 2, 4, 1, 1],
+ [1, 4, 2, 1, 1, 2],
+ [1, 4, 2, 2, 1, 1],
+ [2, 4, 1, 2, 1, 1],
+ [2, 2, 1, 1, 1, 4],
+ [4, 1, 3, 1, 1, 1],
+ [2, 4, 1, 1, 1, 2],
+ [1, 3, 4, 1, 1, 1],
+ [1, 1, 1, 2, 4, 2],
+ [1, 2, 1, 1, 4, 2],
+ [1, 2, 1, 2, 4, 1],
+ [1, 1, 4, 2, 1, 2],
+ [1, 2, 4, 1, 1, 2],
+ [1, 2, 4, 2, 1, 1],
+ [4, 1, 1, 2, 1, 2],
+ [4, 2, 1, 1, 1, 2],
+ [4, 2, 1, 2, 1, 1],
+ [2, 1, 2, 1, 4, 1],
+ [2, 1, 4, 1, 2, 1],
+ [4, 1, 2, 1, 2, 1],
+ [1, 1, 1, 1, 4, 3],
+ [1, 1, 1, 3, 4, 1],
+ [1, 3, 1, 1, 4, 1],
+ [1, 1, 4, 1, 1, 3],
+ [1, 1, 4, 3, 1, 1],
+ [4, 1, 1, 1, 1, 3],
+ [4, 1, 1, 3, 1, 1],
+ [1, 1, 3, 1, 4, 1],
+ [1, 1, 4, 1, 3, 1],
+ [3, 1, 1, 1, 4, 1],
+ [4, 1, 1, 1, 3, 1],
+ [2, 1, 1, 4, 1, 2],
+ [2, 1, 1, 2, 1, 4],
+ [2, 1, 1, 2, 3, 2],
+ [2, 3, 3, 1, 1, 1, 2]
+ ]},
+ SINGLE_CODE_ERROR: {value: 1},
+ AVG_CODE_ERROR: {value: 0.5},
+ FORMAT: {value: "code_128", writeable: false}
+ };
+
+ Code128Reader.prototype = Object.create(BarcodeReader.prototype, properties);
+ Code128Reader.prototype.constructor = Code128Reader;
+
+ Code128Reader.prototype._decodeCode = function(start) {
+ var counter = [0, 0, 0, 0, 0, 0],
+ i,
+ self = this,
+ offset = start,
+ isWhite = !self._row[offset],
+ counterPos = 0,
+ bestMatch = {
+ error : Number.MAX_VALUE,
+ code : -1,
+ start : start,
+ end : start
+ },
+ code,
+ error,
+ normalized;
- // find bounding box
- for ( i = 0; i < patches.length; i++) {
- patch = patches[i];
- for ( j = 0; j < 4; j++) {
- if (patch.box[j][0] < minx) {
- minx = patch.box[j][0];
- }
- if (patch.box[j][0] > maxx) {
- maxx = patch.box[j][0];
- }
- if (patch.box[j][1] < miny) {
- miny = patch.box[j][1];
- }
- if (patch.box[j][1] > maxy) {
- maxy = patch.box[j][1];
+ for ( i = offset; i < self._row.length; i++) {
+ if (self._row[i] ^ isWhite) {
+ counter[counterPos]++;
+ } else {
+ if (counterPos === counter.length - 1) {
+ normalized = self._normalize(counter);
+ if (normalized) {
+ for (code = 0; code < self.CODE_PATTERN.length; code++) {
+ error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
+ if (error < bestMatch.error) {
+ bestMatch.code = code;
+ bestMatch.error = error;
+ }
+ }
+ bestMatch.end = i;
+ return bestMatch;
+ }
+ } else {
+ counterPos++;
+ }
+ counter[counterPos] = 1;
+ isWhite = !isWhite;
}
}
- }
-
- box = [[minx, miny], [maxx, miny], [maxx, maxy], [minx, maxy]];
-
- if (_config.boxFromPatches.showTransformedBox) {
- ImageDebug.drawPath(box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#ff0000', lineWidth: 2});
- }
-
- scale = _config.halfSample ? 2 : 1;
- // reverse rotation;
- transMat = mat2.invert(transMat, transMat);
- for ( j = 0; j < 4; j++) {
- vec2.transformMat2(box[j], box[j], transMat);
- }
-
- if (_config.boxFromPatches.showBB) {
- ImageDebug.drawPath(box, {x: 0, y: 1}, _canvasContainer.ctx.binary, {color: '#ff0000', lineWidth: 2});
- }
-
- for ( j = 0; j < 4; j++) {
- vec2.scale(box[j], box[j], scale);
- }
-
- return box;
- }
-
- /**
- * Creates a binary image of the current image
- */
- function binarizeImage() {
- CVUtils.otsuThreshold(_currentImageWrapper, _binaryImageWrapper);
- _binaryImageWrapper.zeroBorder();
- if (_config.showCanvas) {
- _binaryImageWrapper.show(_canvasContainer.dom.binary, 255);
- }
- }
-
- /**
- * Iterate over the entire image
- * extract patches
- */
- function findPatches() {
- var i,
- j,
- x,
- y,
- moments,
- patchesFound = [],
- rasterizer,
- rasterResult,
- patch;
- for ( i = 0; i < _numPatches.x; i++) {
- for ( j = 0; j < _numPatches.y; j++) {
-
- x = _subImageWrapper.size.x * i;
- y = _subImageWrapper.size.y * j;
-
- // seperate parts
- skeletonize(x, y);
+ return null;
+ };
- // Rasterize, find individual bars
- _skelImageWrapper.zeroBorder();
- ArrayHelper.init(_labelImageWrapper.data, 0);
- rasterizer = Rasterizer.create(_skelImageWrapper, _labelImageWrapper);
- rasterResult = rasterizer.rasterize(0);
+ Code128Reader.prototype._findStart = function() {
+ var counter = [0, 0, 0, 0, 0, 0],
+ i,
+ self = this,
+ offset = self._nextSet(self._row),
+ isWhite = false,
+ counterPos = 0,
+ bestMatch = {
+ error : Number.MAX_VALUE,
+ code : -1,
+ start : 0,
+ end : 0
+ },
+ code,
+ error,
+ j,
+ sum,
+ normalized;
+
+ 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];
+ }
+ normalized = self._normalize(counter);
+ if (normalized) {
+ for (code = self.START_CODE_A; code <= self.START_CODE_C; code++) {
+ error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
+ if (error < bestMatch.error) {
+ bestMatch.code = code;
+ bestMatch.error = error;
+ }
+ }
+ if (bestMatch.error < self.AVG_CODE_ERROR) {
+ bestMatch.start = i - sum;
+ bestMatch.end = i;
+ return bestMatch;
+ }
+ }
- if (_config.showLabels) {
- _labelImageWrapper.overlay(_canvasContainer.dom.binary, Math.floor(360 / rasterResult.count), {x : x, y : y});
+ 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;
+ };
- // calculate moments from the skeletonized patch
- moments = _labelImageWrapper.moments(rasterResult.count);
+ Code128Reader.prototype._decode = function() {
+ var self = this,
+ startInfo = self._findStart(),
+ code = null,
+ done = false,
+ result = [],
+ multiplier = 0,
+ checksum = 0,
+ codeset,
+ rawResult = [],
+ decodedCodes = [],
+ shiftNext = false,
+ unshift,
+ lastCharacterWasPrintable;
- // extract eligible patches
- patchesFound = patchesFound.concat(describePatch(moments, [i, j], x, y));
+ if (startInfo === null) {
+ return null;
}
- }
-
- if (_config.showFoundPatches) {
- for ( i = 0; i < patchesFound.length; i++) {
- patch = patchesFound[i];
- ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "#99ff00", lineWidth: 2});
+ code = {
+ code : startInfo.code,
+ start : startInfo.start,
+ end : startInfo.end
+ };
+ decodedCodes.push(code);
+ checksum = code.code;
+ switch(code.code) {
+ case self.START_CODE_A:
+ codeset = self.CODE_A;
+ break;
+ case self.START_CODE_B:
+ codeset = self.CODE_B;
+ break;
+ case self.START_CODE_C:
+ codeset = self.CODE_C;
+ break;
+ default:
+ return null;
}
- }
-
- return patchesFound;
- }
-
- /**
- * Finds those connected areas which contain at least 6 patches
- * and returns them ordered DESC by the number of contained patches
- * @param {Number} maxLabel
- */
- function findBiggestConnectedAreas(maxLabel){
- var i,
- sum,
- labelHist = [],
- topLabels = [];
-
- for ( i = 0; i < maxLabel; i++) {
- labelHist.push(0);
- }
- sum = _patchLabelGrid.data.length;
- while (sum--) {
- if (_patchLabelGrid.data[sum] > 0) {
- labelHist[_patchLabelGrid.data[sum] - 1]++;
+
+ while (!done) {
+ unshift = shiftNext;
+ shiftNext = false;
+ code = self._decodeCode(code.end);
+ if (code !== null) {
+ if (code.code !== self.STOP_CODE) {
+ rawResult.push(code.code);
+ multiplier++;
+ checksum += multiplier * code.code;
+ }
+ decodedCodes.push(code);
+
+ switch(codeset) {
+ case self.CODE_A:
+ if (code.code < 64) {
+ result.push(String.fromCharCode(32 + code.code));
+ } else if (code.code < 96) {
+ result.push(String.fromCharCode(code.code - 64));
+ } else {
+ switch (code.code) {
+ case self.CODE_SHIFT:
+ shiftNext = true;
+ codeset = self.CODE_B;
+ break;
+ case self.CODE_B:
+ codeset = self.CODE_B;
+ break;
+ case self.CODE_C:
+ codeset = self.CODE_C;
+ break;
+ case self.STOP_CODE:
+ done = true;
+ break;
+ }
+ }
+ break;
+ case self.CODE_B:
+ if (code.code < 96) {
+ result.push(String.fromCharCode(32 + code.code));
+ } else {
+ if (code.code != self.STOP_CODE) {
+ lastCharacterWasPrintable = false;
+ }
+ switch (code.code) {
+ case self.CODE_SHIFT:
+ shiftNext = true;
+ codeset = self.CODE_A;
+ break;
+ case self.CODE_A:
+ codeset = self.CODE_A;
+ break;
+ case self.CODE_C:
+ codeset = self.CODE_C;
+ break;
+ case self.STOP_CODE:
+ done = true;
+ break;
+ }
+ }
+ break;
+ case self.CODE_C:
+ if (code.code < 100) {
+ result.push(code.code < 10 ? "0" + code.code : code.code);
+ }
+ switch (code.code) {
+ case self.CODE_A:
+ codeset = self.CODE_A;
+ break;
+ case self.CODE_B:
+ codeset = self.CODE_B;
+ break;
+ case self.STOP_CODE:
+ done = true;
+ break;
+ }
+ break;
+ }
+ } else {
+ done = true;
+ }
+ if (unshift) {
+ codeset = codeset == self.CODE_A ? self.CODE_B : self.CODE_A;
+ }
}
- }
-
- labelHist = labelHist.map(function(val, idx) {
- return {
- val : val,
- label : idx + 1
- };
- });
- labelHist.sort(function(a, b) {
- return b.val - a.val;
- });
+ if (code === null) {
+ return null;
+ }
- // extract top areas with at least 6 patches present
- topLabels = labelHist.filter(function(el) {
- return el.val >= 5;
- });
-
- return topLabels;
- }
-
- /**
- *
- */
- function findBoxes(topLabels, maxLabel) {
- var i,
- j,
- sum,
- patches = [],
- patch,
- box,
- boxes = [],
- hsv = [0, 1, 1],
- rgb = [0, 0, 0];
-
- for ( i = 0; i < topLabels.length; i++) {
- sum = _patchLabelGrid.data.length;
- patches.length = 0;
- while (sum--) {
- if (_patchLabelGrid.data[sum] === topLabels[i].label) {
- patch = _imageToPatchGrid.data[sum];
- patches.push(patch);
- }
+ // find end bar
+ code.end = self._nextUnset(self._row, code.end);
+ if(!self._verifyTrailingWhitespace(code)){
+ return null;
}
- box = boxFromPatches(patches);
- if (box) {
- boxes.push(box);
- // draw patch-labels if requested
- if (_config.showRemainingPatchLabels) {
- for ( j = 0; j < patches.length; j++) {
- patch = patches[j];
- hsv[0] = (topLabels[i].label / (maxLabel + 1)) * 360;
- CVUtils.hsv2rgb(hsv, rgb);
- ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
- }
- }
+ // checksum
+ // Does not work correctly yet!!! startcode - endcode?
+ checksum -= multiplier * rawResult[rawResult.length - 1];
+ if (checksum % 103 != rawResult[rawResult.length - 1]) {
+ return null;
}
- }
- return boxes;
- }
- /**
- * Find similar moments (via cluster)
- * @param {Object} moments
- */
- function similarMoments(moments) {
- var clusters = CVUtils.cluster(moments, 0.90);
- var topCluster = CVUtils.topGeneric(clusters, 1, function(e) {
- return e.getPoints().length;
- });
- var points = [], result = [];
- if (topCluster.length === 1) {
- points = topCluster[0].item.getPoints();
- for (var i = 0; i < points.length; i++) {
- result.push(points[i].point);
+ if (!result.length) {
+ return null;
}
- }
- return result;
- }
- function skeletonize(x, y) {
- _binaryImageWrapper.subImageAsCopy(_subImageWrapper, CVUtils.imageRef(x, y));
- _skeletonizer.skeletonize();
-
- // Show skeleton if requested
- if (_config.showSkeleton) {
- _skelImageWrapper.overlay(_canvasContainer.dom.binary, 360, CVUtils.imageRef(x, y));
- }
- }
+ // remove last code from result (checksum)
+ result.splice(result.length - 1, 1);
- /**
- * Extracts and describes those patches which seem to contain a barcode pattern
- * @param {Array} moments
- * @param {Object} patchPos,
- * @param {Number} x
- * @param {Number} y
- * @returns {Array} list of patches
- */
- function describePatch(moments, patchPos, x, y) {
- var k,
- avg,
- sum = 0,
- eligibleMoments = [],
- matchingMoments,
- patch,
- patchesFound = [],
- minComponentWeight = Math.ceil(_patchSize.x/3);
- if (moments.length >= 2) {
- // only collect moments which's area covers at least minComponentWeight pixels.
- for ( k = 0; k < moments.length; k++) {
- if (moments[k].m00 > minComponentWeight) {
- eligibleMoments.push(moments[k]);
- }
- }
- // if at least 2 moments are found which have at least minComponentWeights covered
- if (eligibleMoments.length >= 2) {
- sum = eligibleMoments.length;
- matchingMoments = similarMoments(eligibleMoments);
- avg = 0;
- // determine the similarity of the moments
- for ( k = 0; k < matchingMoments.length; k++) {
- avg += matchingMoments[k].rad;
- }
+ return {
+ code : result.join(""),
+ start : startInfo.start,
+ end : code.end,
+ codeset : codeset,
+ startInfo : startInfo,
+ decodedCodes : decodedCodes,
+ endInfo : code
+ };
+ };
+<<<<<<< HEAD
// Only two of the moments are allowed not to fit into the equation
// add the patch to the set
if (matchingMoments.length > 1 && matchingMoments.length >= (eligibleMoments.length / 4) * 3 && matchingMoments.length > moments.length / 4) {
@@ -8048,394 +10018,362 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
}
return patchesFound;
}
+=======
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
- /**
- * finds patches which are connected and share the same orientation
- * @param {Object} patchesFound
- */
- function rasterizeAngularSimilarity(patchesFound) {
- var label = 0,
- threshold = 0.95,
- currIdx = 0,
- j,
- patch,
- hsv = [0, 1, 1],
- rgb = [0, 0, 0];
+ BarcodeReader.prototype._verifyTrailingWhitespace = function(endInfo) {
+ var self = this,
+ trailingWhitespaceEnd;
- function notYetProcessed() {
- var i;
- for ( i = 0; i < _patchLabelGrid.data.length; i++) {
- if (_patchLabelGrid.data[i] === 0 && _patchGrid.data[i] === 1) {
- return i;
+ trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
}
}
- return _patchLabelGrid.length;
- }
-
- function trace(currentIdx) {
- var x, y, currentPatch, patch, idx, dir, current = {
- x : currentIdx % _patchLabelGrid.size.x,
- y : (currentIdx / _patchLabelGrid.size.x) | 0
- }, similarity;
+ return null;
+ };
+
+ return (Code128Reader);
+ }
+);
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
- if (currentIdx < _patchLabelGrid.data.length) {
- currentPatch = _imageToPatchGrid.data[currentIdx];
- // assign label
- _patchLabelGrid.data[currentIdx] = label;
- for ( dir = 0; dir < Tracer.searchDirections.length; dir++) {
- y = current.y + Tracer.searchDirections[dir][0];
- x = current.x + Tracer.searchDirections[dir][1];
- idx = y * _patchLabelGrid.size.x + x;
+define(
+ 'ean_reader',[
+ "./barcode_reader"
+ ],
+ function(BarcodeReader) {
+ "use strict";
+
+ function EANReader(opts) {
+ BarcodeReader.call(this, opts);
+ }
+
+ var properties = {
+ CODE_L_START : {value: 0},
+ MODULO : {value: 7},
+ CODE_G_START : {value: 10},
+ START_PATTERN : {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]},
+ STOP_PATTERN : {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]},
+ MIDDLE_PATTERN : {value: [1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7]},
+ CODE_PATTERN : {value: [
+ [3, 2, 1, 1],
+ [2, 2, 2, 1],
+ [2, 1, 2, 2],
+ [1, 4, 1, 1],
+ [1, 1, 3, 2],
+ [1, 2, 3, 1],
+ [1, 1, 1, 4],
+ [1, 3, 1, 2],
+ [1, 2, 1, 3],
+ [3, 1, 1, 2],
+ [1, 1, 2, 3],
+ [1, 2, 2, 2],
+ [2, 2, 1, 2],
+ [1, 1, 4, 1],
+ [2, 3, 1, 1],
+ [1, 3, 2, 1],
+ [4, 1, 1, 1],
+ [2, 1, 3, 1],
+ [3, 1, 2, 1],
+ [2, 1, 1, 3]
+ ]},
+ CODE_FREQUENCY : {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
+ SINGLE_CODE_ERROR: {value: 0.67},
+ AVG_CODE_ERROR: {value: 0.27},
+ FORMAT: {value: "ean_13", writeable: false}
+ };
+
+ EANReader.prototype = Object.create(BarcodeReader.prototype, properties);
+ EANReader.prototype.constructor = EANReader;
+
+ EANReader.prototype._decodeCode = function(start, coderange) {
+ var counter = [0, 0, 0, 0],
+ i,
+ self = this,
+ offset = start,
+ isWhite = !self._row[offset],
+ counterPos = 0,
+ bestMatch = {
+ error : Number.MAX_VALUE,
+ code : -1,
+ start : start,
+ end : start
+ },
+ code,
+ error,
+ normalized;
- // continue if patch empty
- if (_patchGrid.data[idx] === 0) {
- _patchLabelGrid.data[idx] = Number.MAX_VALUE;
- continue;
- }
+ if (!coderange) {
+ coderange = self.CODE_PATTERN.length;
+ }
- patch = _imageToPatchGrid.data[idx];
- if (_patchLabelGrid.data[idx] === 0) {
- similarity = Math.abs(vec2.dot(patch.vec, currentPatch.vec));
- if (similarity > threshold) {
- trace(idx);
+ for ( i = offset; i < self._row.length; i++) {
+ if (self._row[i] ^ isWhite) {
+ counter[counterPos]++;
+ } else {
+ if (counterPos === counter.length - 1) {
+ normalized = self._normalize(counter);
+ if (normalized) {
+ for (code = 0; code < coderange; code++) {
+ error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
+ if (error < bestMatch.error) {
+ bestMatch.code = code;
+ bestMatch.error = error;
+ }
+ }
+ bestMatch.end = i;
+ if (bestMatch.error > self.AVG_CODE_ERROR) {
+ return null;
+ }
+ return bestMatch;
}
+ } else {
+ counterPos++;
}
+ counter[counterPos] = 1;
+ isWhite = !isWhite;
}
}
- }
-
- // prepare for finding the right patches
- ArrayHelper.init(_patchGrid.data, 0);
- ArrayHelper.init(_patchLabelGrid.data, 0);
- ArrayHelper.init(_imageToPatchGrid.data, null);
-
- for ( j = 0; j < patchesFound.length; j++) {
- patch = patchesFound[j];
- _imageToPatchGrid.data[patch.index] = patch;
- _patchGrid.data[patch.index] = 1;
- }
-
- // rasterize the patches found to determine area
- _patchGrid.zeroBorder();
-
- while (( currIdx = notYetProcessed()) < _patchLabelGrid.data.length) {
- label++;
- trace(currIdx);
- }
-
- // draw patch-labels if requested
- if (_config.showPatchLabels) {
- for ( j = 0; j < _patchLabelGrid.data.length; j++) {
- if (_patchLabelGrid.data[j] > 0 && _patchLabelGrid.data[j] <= label) {
- patch = _imageToPatchGrid.data[j];
- hsv[0] = (_patchLabelGrid.data[j] / (label + 1)) * 360;
- CVUtils.hsv2rgb(hsv, rgb);
- ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
- }
- }
- }
-
- return label;
- }
-
- return {
- init : function(inputImageWrapper, config) {
- _config = config;
- _inputImageWrapper = inputImageWrapper;
-
- initBuffers();
- initCanvas();
- },
-
- locate : function() {
- var patchesFound,
- topLabels,
- boxes;
+ return null;
+ };
- if (_config.halfSample) {
- CVUtils.halfSample(_inputImageWrapper, _currentImageWrapper);
- }
+ EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder, epsilon) {
+ var counter = [],
+ self = this,
+ i,
+ counterPos = 0,
+ bestMatch = {
+ error : Number.MAX_VALUE,
+ code : -1,
+ start : 0,
+ end : 0
+ },
+ error,
+ j,
+ sum,
+ normalized;
- binarizeImage();
- patchesFound = findPatches();
- // return unless 5% or more patches are found
- if (patchesFound.length < _numPatches.x * _numPatches.y * 0.05) {
- return null;
+ if (!offset) {
+ offset = self._nextSet(self._row);
}
- // rasterrize area by comparing angular similarity;
- var maxLabel = rasterizeAngularSimilarity(patchesFound);
- if (maxLabel < 1) {
- return null;
+ if (isWhite === undefined) {
+ isWhite = false;
}
- // search for area with the most patches (biggest connected area)
- topLabels = findBiggestConnectedAreas(maxLabel);
- if (topLabels.length === 0) {
- return null;
+ if (tryHarder === undefined) {
+ tryHarder = true;
}
- boxes = findBoxes(topLabels, maxLabel);
- return boxes;
- },
-
- checkImageConstraints: function(inputStream, config) {
- var patchSize,
- width = inputStream.getWidth(),
- height = inputStream.getHeight(),
- halfSample = config.halfSample ? 0.5 : 1,
- size,
- area;
-
- // calculate width and height based on area
- if (inputStream.getConfig().area) {
- area = CVUtils.computeImageArea(width, height, inputStream.getConfig().area);
- inputStream.setTopRight({x: area.sx, y: area.sy});
- inputStream.setCanvasSize({x: width, y: height});
- width = area.sw;
- height = area.sh;
+ if ( epsilon === undefined) {
+ epsilon = self.AVG_CODE_ERROR;
}
- size = {
- x: Math.floor(width * halfSample),
- y: Math.floor(height * halfSample)
- };
-
- patchSize = CVUtils.calculatePatchSize(config.patchSize, size);
- console.log("Patch-Size: " + JSON.stringify(patchSize));
-
- inputStream.setWidth(Math.floor(Math.floor(size.x/patchSize.x)*(1/halfSample)*patchSize.x));
- inputStream.setHeight(Math.floor(Math.floor(size.y/patchSize.y)*(1/halfSample)*patchSize.y));
-
- if ((inputStream.getWidth() % patchSize.x) === 0 && (inputStream.getHeight() % patchSize.y) === 0) {
- return true;
+ for ( i = 0; i < pattern.length; i++) {
+ counter[i] = 0;
}
- throw new Error("Image dimensions do not comply with the current settings: Width (" +
- width + " )and height (" + height +
- ") must a multiple of " + patchSize.x);
- }
- };
-});
-
-
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-
-define('bresenham',["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper) {
- "use strict";
- var Bresenham = {};
+ 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];
+ }
+ normalized = self._normalize(counter);
+ if (normalized) {
+ error = self._matchPattern(normalized, pattern);
- var Slope = {
- DIR : {
- UP : 1,
- DOWN : -1
- }
- };
- /**
- * Scans a line of the given image from point p1 to p2 and returns a result object containing
- * gray-scale values (0-255) of the underlying pixels in addition to the min
- * and max values.
- * @param {Object} imageWrapper
- * @param {Object} p1 The start point {x,y}
- * @param {Object} p2 The end point {x,y}
- * @returns {line, min, max}
- */
- Bresenham.getBarcodeLine = function(imageWrapper, p1, p2) {
- var x0 = p1.x | 0,
- y0 = p1.y | 0,
- x1 = p2.x | 0,
- y1 = p2.y | 0,
- steep = Math.abs(y1 - y0) > Math.abs(x1 - x0),
- deltax,
- deltay,
- error,
- ystep,
- y,
- tmp,
- x,
- line = [],
- imageData = imageWrapper.data,
- width = imageWrapper.size.x,
- sum = 0,
- val,
- min = 255,
- max = 0;
+ 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;
+ };
- function read(a, b) {
- val = imageData[b * width + a];
- sum += val;
- min = val < min ? val : min;
- max = val > max ? val : max;
- line.push(val);
- }
+ EANReader.prototype._findStart = function() {
+ var self = this,
+ leadingWhitespaceStart,
+ offset = self._nextSet(self._row),
+ startInfo;
- if (steep) {
- tmp = x0;
- x0 = y0;
- y0 = tmp;
+ while(!startInfo) {
+ startInfo = self._findPattern(self.START_PATTERN, offset);
+ if (!startInfo) {
+ return null;
+ }
+ leadingWhitespaceStart = startInfo.start - (startInfo.end - startInfo.start);
+ if (leadingWhitespaceStart >= 0) {
+ if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
+ return startInfo;
+ }
+ }
+ offset = startInfo.end;
+ startInfo = null;
+ }
+ };
- tmp = x1;
- x1 = y1;
- y1 = tmp;
- }
- if (x0 > x1) {
- tmp = x0;
- x0 = x1;
- x1 = tmp;
+ EANReader.prototype._verifyTrailingWhitespace = function(endInfo) {
+ var self = this,
+ trailingWhitespaceEnd;
- tmp = y0;
- y0 = y1;
- y1 = tmp;
- }
- deltax = x1 - x0;
- deltay = Math.abs(y1 - y0);
- error = (deltax / 2) | 0;
- y = y0;
- ystep = y0 < y1 ? 1 : -1;
- for ( x = x0; x < x1; x++) {
- if(steep){
- read(y, x);
- } else {
- read(x, y);
- }
- error = error - deltay;
- if (error < 0) {
- y = y + ystep;
- error = error + deltax;
+ trailingWhitespaceEnd = endInfo.end + (endInfo.end - endInfo.start);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
+ }
}
- }
-
- return {
- line : line,
- min : min,
- max : max
+ return null;
};
- };
-
- Bresenham.toOtsuBinaryLine = function(result) {
- var line = result.line,
- image = new ImageWrapper({x: line.length - 1, y: 1}, line),
- threshold = CVUtils.determineOtsuThreshold(image, 5);
- line = CVUtils.sharpenLine(line);
- CVUtils.thresholdImage(image, threshold);
+ EANReader.prototype._findEnd = function(offset, isWhite) {
+ var self = this,
+ endInfo = self._findPattern(self.STOP_PATTERN, offset, isWhite, false);
- return {
- line: line,
- threshold: threshold
+ return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
};
- };
-
- /**
- * Converts the result from getBarcodeLine into a binary representation
- * also considering the frequency and slope of the signal for more robust results
- * @param {Object} result {line, min, max}
- */
- Bresenham.toBinaryLine = function(result) {
- var min = result.min,
- max = result.max,
- line = result.line,
- slope,
- slope2,
- center = min + (max - min) / 2,
- extrema = [],
- currentDir,
- dir,
- threshold = (max - min) / 12,
- rThreshold = -threshold,
- i,
- j;
+ EANReader.prototype._calculateFirstDigit = function(codeFrequency) {
+ var i,
+ self = this;
- // 1. find extrema
- currentDir = line[0] > center ? Slope.DIR.UP : Slope.DIR.DOWN;
- extrema.push({
- pos : 0,
- val : line[0]
- });
- for ( i = 0; i < line.length - 2; i++) {
- slope = (line[i + 1] - line[i]);
- slope2 = (line[i + 2] - line[i + 1]);
- if ((slope + slope2) < rThreshold && line[i + 1] < (center*1.5)) {
- dir = Slope.DIR.DOWN;
- } else if ((slope + slope2) > threshold && line[i + 1] > (center*0.5)) {
- dir = Slope.DIR.UP;
- } else {
- dir = currentDir;
+ for ( i = 0; i < self.CODE_FREQUENCY.length; i++) {
+ if (codeFrequency === self.CODE_FREQUENCY[i]) {
+ return i;
+ }
}
+ return null;
+ };
- if (currentDir !== dir) {
- extrema.push({
- pos : i,
- val : line[i]
- });
- currentDir = dir;
+ EANReader.prototype._decodePayload = function(code, result, decodedCodes) {
+ var i,
+ self = this,
+ codeFrequency = 0x0,
+ firstDigit;
+
+ for ( i = 0; i < 6; i++) {
+ code = self._decodeCode(code.end);
+ if (!code) {
+ return null;
+ }
+ if (code.code >= self.CODE_G_START) {
+ code.code = code.code - self.CODE_G_START;
+ codeFrequency |= 1 << (5 - i);
+ } else {
+ codeFrequency |= 0 << (5 - i);
+ }
+ result.push(code.code);
+ decodedCodes.push(code);
}
- }
- extrema.push({
- pos : line.length,
- val : line[line.length - 1]
- });
- for ( j = extrema[0].pos; j < extrema[1].pos; j++) {
- line[j] = line[j] > center ? 0 : 1;
- }
+ firstDigit = self._calculateFirstDigit(codeFrequency);
+ if (firstDigit === null) {
+ return null;
+ }
+ result.unshift(firstDigit);
- // iterate over extrema and convert to binary based on avg between minmax
- for ( i = 1; i < extrema.length - 1; i++) {
- if (extrema[i + 1].val > extrema[i].val) {
- threshold = (extrema[i].val + ((extrema[i + 1].val - extrema[i].val) / 3) * 2) | 0;
- } else {
- threshold = (extrema[i + 1].val + ((extrema[i].val - extrema[i + 1].val) / 3)) | 0;
+ code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
+ if (code === null) {
+ return null;
}
+ decodedCodes.push(code);
- for ( j = extrema[i].pos; j < extrema[i + 1].pos; j++) {
- line[j] = line[j] > threshold ? 0 : 1;
+ for ( i = 0; i < 6; i++) {
+ code = self._decodeCode(code.end, self.CODE_G_START);
+ if (!code) {
+ return null;
+ }
+ decodedCodes.push(code);
+ result.push(code.code);
}
- }
- return {
- line : line,
- threshold : threshold
+ return code;
};
- };
-
- /**
- * Used for development only
- */
- Bresenham.debug = {
- printFrequency: function(line, canvas) {
- var i,
- ctx = canvas.getContext("2d");
- canvas.width = line.length;
- canvas.height = 256;
-
- ctx.beginPath();
- ctx.strokeStyle = "blue";
- for ( i = 0; i < line.length; i++) {
- ctx.moveTo(i, 255);
- ctx.lineTo(i, 255 - line[i]);
+
+ EANReader.prototype._decode = function() {
+ var startInfo,
+ self = this,
+ code,
+ result = [],
+ decodedCodes = [];
+
+ startInfo = self._findStart();
+ if (!startInfo) {
+ return null;
}
- ctx.stroke();
- ctx.closePath();
- },
-
- printPattern: function(line, canvas) {
- var ctx = canvas.getContext("2d"), i;
-
- canvas.width = line.length;
- ctx.fillColor = "black";
- for ( i = 0; i < line.length; i++) {
- if (line[i] === 1) {
- ctx.fillRect(i, 0, 1, 100);
- }
+ code = {
+ code : startInfo.code,
+ start : startInfo.start,
+ end : startInfo.end
+ };
+ decodedCodes.push(code);
+ code = self._decodePayload(code, result, decodedCodes);
+ if (!code) {
+ return null;
+ }
+ code = self._findEnd(code.end, false);
+ if (!code){
+ return null;
}
- }
- };
- return (Bresenham);
-});
+ decodedCodes.push(code);
+
+ // Checksum
+ if (!self._checksum(result)) {
+ return null;
+ }
+
+ return {
+ code : result.join(""),
+ start : startInfo.start,
+ end : code.end,
+ codeset : "",
+ startInfo : startInfo,
+ decodedCodes : decodedCodes
+ };
+ };
+
+ EANReader.prototype._checksum = function(result) {
+ var sum = 0, i;
+
+ for ( i = result.length - 2; i >= 0; i -= 2) {
+ sum += result[i];
+ }
+ sum *= 3;
+ for ( i = result.length - 1; i >= 0; i -= 2) {
+ sum += result[i];
+ }
+ return sum % 10 === 0;
+ };
+
+ return (EANReader);
+ }
+);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
@@ -8755,7 +10693,7 @@ define(
nextStart,
end;
- self._fillCounters();
+ this._counters = self._fillCounters();
start = self._findStart();
if (!start) {
return null;
@@ -8905,334 +10843,698 @@ define(
return true;
};
- CodabarReader.prototype._fillCounters = function() {
+ 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,
- counterPos = 0,
- isWhite = true,
- offset = self._nextUnset(self._row),
- i;
+ i,
+ pattern,
+ start = self._nextUnset(self._row),
+ end;
- 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;
+ 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
+ };
}
}
};
- CodabarReader.prototype._patternToChar = function(pattern) {
+ return (CodabarReader);
+ }
+);
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define(
+ 'upc_reader',[
+ "./ean_reader"
+ ],
+ function(EANReader) {
+ "use strict";
+
+ function UPCReader() {
+ EANReader.call(this);
+ }
+
+ var properties = {
+ FORMAT: {value: "upc_a", writeable: false}
+ };
+
+ UPCReader.prototype = Object.create(EANReader.prototype, properties);
+ UPCReader.prototype.constructor = UPCReader;
+
+ UPCReader.prototype._decode = function() {
+ var result = EANReader.prototype._decode.call(this);
+
+ if (result && result.code && result.code.length === 13 && result.code.charAt(0) === "0") {
+
+ result.code = result.code.substring(1);
+ return result;
+ }
+ return null;
+ };
+
+ return (UPCReader);
+ }
+);
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define(
+ 'ean_8_reader',[
+ "./ean_reader"
+ ],
+ function(EANReader) {
+ "use strict";
+
+ function EAN8Reader() {
+ EANReader.call(this);
+ }
+
+ var properties = {
+ FORMAT: {value: "ean_8", writeable: false}
+ };
+
+ EAN8Reader.prototype = Object.create(EANReader.prototype, properties);
+ EAN8Reader.prototype.constructor = EAN8Reader;
+
+ EAN8Reader.prototype._decodePayload = function(code, result, decodedCodes) {
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]);
+ for ( i = 0; i < 4; i++) {
+ code = self._decodeCode(code.end, self.CODE_G_START);
+ if (!code) {
+ return null;
}
+ result.push(code.code);
+ decodedCodes.push(code);
}
- return -1;
+
+ code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
+ if (code === null) {
+ return null;
+ }
+ decodedCodes.push(code);
+
+ for ( i = 0; i < 4; i++) {
+ code = self._decodeCode(code.end, self.CODE_G_START);
+ if (!code) {
+ return null;
+ }
+ decodedCodes.push(code);
+ result.push(code.code);
+ }
+
+ return code;
+ };
+
+ return (EAN8Reader);
+ }
+);
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define(
+ 'upc_e_reader',[
+ "./ean_reader"
+ ],
+ function(EANReader) {
+ "use strict";
+
+ function UPCEReader() {
+ EANReader.call(this);
+ }
+
+ var properties = {
+ CODE_FREQUENCY : {value: [
+ [ 56, 52, 50, 49, 44, 38, 35, 42, 41, 37 ],
+ [7, 11, 13, 14, 19, 25, 28, 21, 22, 26]]},
+ STOP_PATTERN: { value: [1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7]},
+ FORMAT: {value: "upc_e", writeable: false}
};
- CodabarReader.prototype._computeAlternatingThreshold = function(offset, end) {
+ UPCEReader.prototype = Object.create(EANReader.prototype, properties);
+ UPCEReader.prototype.constructor = UPCEReader;
+
+ UPCEReader.prototype._decodePayload = function(code, result, decodedCodes) {
var i,
- min = Number.MAX_VALUE,
- max = 0,
- counter;
+ self = this,
+ codeFrequency = 0x0;
- for (i = offset; i < end; i += 2){
- counter = this._counters[i];
- if (counter > max) {
- max = counter;
+ for ( i = 0; i < 6; i++) {
+ code = self._decodeCode(code.end);
+ if (!code) {
+ return null;
}
- if (counter < min) {
- min = counter;
+ if (code.code >= self.CODE_G_START) {
+ code.code = code.code - self.CODE_G_START;
+ codeFrequency |= 1 << (5 - i);
}
+ result.push(code.code);
+ decodedCodes.push(code);
+ }
+ if (!self._determineParity(codeFrequency, result)) {
+ return null;
}
- return ((min + max) / 2.0) | 0;
+ return code;
};
- CodabarReader.prototype._toPattern = function(offset) {
- var numCounters = 7,
- end = offset + numCounters,
- barThreshold,
- spaceThreshold,
- bitmask = 1 << (numCounters - 1),
- pattern = 0,
+ UPCEReader.prototype._determineParity = function(codeFrequency, result) {
+ var self =this,
i,
- threshold;
-
- if (end > this._counters.length) {
- return -1;
- }
-
- barThreshold = this._computeAlternatingThreshold(offset, end);
- spaceThreshold = this._computeAlternatingThreshold(offset + 1, end);
+ nrSystem;
- for (i = 0; i < numCounters; i++){
- threshold = (i & 1) === 0 ? barThreshold : spaceThreshold;
- if (this._counters[offset + i] > threshold) {
- pattern |= bitmask;
+ for (nrSystem = 0; nrSystem < self.CODE_FREQUENCY.length; nrSystem++){
+ for ( i = 0; i < self.CODE_FREQUENCY[nrSystem].length; i++) {
+ if (codeFrequency === self.CODE_FREQUENCY[nrSystem][i]) {
+ result.unshift(nrSystem);
+ result.push(i);
+ return true;
+ }
}
- bitmask >>= 1;
}
-
- return pattern;
+ return false;
};
- CodabarReader.prototype._isStartEnd = function(pattern) {
- var i;
+ UPCEReader.prototype._convertToUPCA = function(result) {
+ var upca = [result[0]],
+ lastDigit = result[result.length - 2];
- for (i = 0; i < this.START_END.length; i++) {
- if (this.START_END[i] === pattern) {
- return true;
- }
+ if (lastDigit <= 2) {
+ upca = upca.concat(result.slice(1, 3))
+ .concat([lastDigit, 0, 0, 0, 0])
+ .concat(result.slice(3, 6));
+ } else if (lastDigit === 3) {
+ upca = upca.concat(result.slice(1, 4))
+ .concat([0 ,0, 0, 0, 0])
+ .concat(result.slice(4,6));
+ } else if (lastDigit === 4) {
+ upca = upca.concat(result.slice(1, 5))
+ .concat([0, 0, 0, 0, 0, result[5]]);
+ } else {
+ upca = upca.concat(result.slice(1, 6))
+ .concat([0, 0, 0, 0, lastDigit]);
}
- return false;
+
+ upca.push(result[result.length - 1]);
+ return upca;
};
- CodabarReader.prototype._sumCounters = function(start, end) {
- var i,
- sum = 0;
+ UPCEReader.prototype._checksum = function(result) {
+ return EANReader.prototype._checksum.call(this, this._convertToUPCA(result));
+ };
- for (i = start; i < end; i++) {
- sum += this._counters[i];
- }
- return sum;
+ UPCEReader.prototype._findEnd = function(offset, isWhite) {
+ isWhite = true;
+ return EANReader.prototype._findEnd.call(this, offset, isWhite);
};
- CodabarReader.prototype._findStart = function() {
+ UPCEReader.prototype._verifyTrailingWhitespace = function(endInfo) {
var self = this,
- i,
- pattern,
- start = self._nextUnset(self._row),
- end;
+ trailingWhitespaceEnd;
- 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
- };
+ trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start)/2);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
}
}
};
- return (CodabarReader);
+ return (UPCEReader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
+define('html_utils',[], function() {
+ "use strict";
+
+ function createNode(htmlStr) {
+ var temp = document.createElement('div');
+
+ temp.innerHTML = htmlStr;
+ while (temp.firstChild) {
+ return temp.firstChild;
+ }
+ }
+
+ function mergeObjects(obj1, obj2) {
+ for (var p in obj2) {
+ try {
+ if (obj2[p].constructor == Object) {
+ obj1[p] = mergeObjects(obj1[p], obj2[p]);
+ } else {
+ obj1[p] = obj2[p];
+ }
+ } catch(e) {
+ obj1[p] = obj2[p];
+ }
+ }
+
+ return obj1;
+ }
+
+ return {
+ createNode : function(htmlStr) {
+ return createNode(htmlStr);
+ },
+ mergeObjects : function(obj1, obj2) {
+ return mergeObjects(obj1, obj2);
+ }
+ };
+});
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
define(
- 'upc_reader',[
- "./ean_reader"
+ 'i2of5_reader',[
+ "./barcode_reader",
+ "./html_utils"
],
- function(EANReader) {
+ function(BarcodeReader, HTMLUtils) {
"use strict";
- function UPCReader() {
- EANReader.call(this);
+ function I2of5Reader(opts) {
+ opts = HTMLUtils.mergeObjects(getDefaulConfig(), opts);
+ BarcodeReader.call(this, opts);
+ this.barSpaceRatio = [1, 1];
+ if (opts.normalizeBarSpaceWidth) {
+ this.SINGLE_CODE_ERROR = 0.38;
+ this.AVG_CODE_ERROR = 0.09;
+ }
}
- var properties = {
- FORMAT: {value: "upc_a", writeable: false}
+ function getDefaulConfig() {
+ var config = {};
+
+ Object.keys(I2of5Reader.CONFIG_KEYS).forEach(function(key) {
+ config[key] = I2of5Reader.CONFIG_KEYS[key]['default'];
+ });
+ return config;
+ }
+
+ var N = 1,
+ W = 3,
+ properties = {
+ MODULO : {value: 10},
+ START_PATTERN : {value: [N*2.5, N*2.5, N*2.5, N*2.5]},
+ STOP_PATTERN : {value: [N*2, N*2, W*2]},
+ 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.38, writable: true},
+ MAX_CORRECTION_FACTOR: {value: 5},
+ FORMAT: {value: "i2of5"}
+ };
+
+ I2of5Reader.prototype = Object.create(BarcodeReader.prototype, properties);
+ I2of5Reader.prototype.constructor = I2of5Reader;
+
+ I2of5Reader.prototype._matchPattern = function(counter, code) {
+ if (this.config.normalizeBarSpaceWidth) {
+ var i,
+ counterSum = [0, 0],
+ codeSum = [0, 0],
+ correction = [0, 0],
+ correctionRatio = this.MAX_CORRECTION_FACTOR,
+ correctionRatioInverse = 1 / correctionRatio;
+
+ for (i = 0; i < counter.length; i++) {
+ counterSum[i % 2] += counter[i];
+ codeSum[i % 2] += code[i];
+ }
+ correction[0] = codeSum[0] / counterSum[0];
+ correction[1] = codeSum[1] / counterSum[1];
+
+ correction[0] = Math.max(Math.min(correction[0], correctionRatio), correctionRatioInverse);
+ correction[1] = Math.max(Math.min(correction[1], correctionRatio), correctionRatioInverse);
+ this.barSpaceRatio = correction;
+ for (i = 0; i < counter.length; i++) {
+ counter[i] *= this.barSpaceRatio[i % 2];
+ }
+ }
+ return BarcodeReader.prototype._matchPattern.call(this, counter, code);
+ };
+
+ I2of5Reader.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,
+ normalized,
+ 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];
+ }
+ normalized = self._normalize(counter);
+ if (normalized) {
+ error = self._matchPattern(normalized, 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;
};
- UPCReader.prototype = Object.create(EANReader.prototype, properties);
- UPCReader.prototype.constructor = UPCReader;
+ I2of5Reader.prototype._findStart = function() {
+ var self = this,
+ leadingWhitespaceStart,
+ offset = self._nextSet(self._row),
+ startInfo,
+ narrowBarWidth = 1;
- UPCReader.prototype._decode = function() {
- var result = EANReader.prototype._decode.call(this);
+ while(!startInfo) {
+ startInfo = self._findPattern(self.START_PATTERN, offset, false, true);
+ if (!startInfo) {
+ return null;
+ }
+ narrowBarWidth = Math.floor((startInfo.end - startInfo.start) / 4);
+ leadingWhitespaceStart = startInfo.start - narrowBarWidth*10;
+ if (leadingWhitespaceStart >= 0) {
+ if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
+ return startInfo;
+ }
+ }
+ offset = startInfo.end;
+ startInfo = null;
+ }
+ };
- if (result && result.code && result.code.length === 13 && result.code.charAt(0) === "0") {
+ I2of5Reader.prototype._verifyTrailingWhitespace = function(endInfo) {
+ var self = this,
+ trailingWhitespaceEnd;
- result.code = result.code.substring(1);
- return result;
+ trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
+ }
}
return null;
};
- return (UPCReader);
- }
-);
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
+ I2of5Reader.prototype._findEnd = function() {
+ var self = this,
+ endInfo,
+ tmp;
-define(
- 'ean_8_reader',[
- "./ean_reader"
- ],
- function(EANReader) {
- "use strict";
+ self._row.reverse();
+ endInfo = self._findPattern(self.STOP_PATTERN);
+ self._row.reverse();
- function EAN8Reader() {
- EANReader.call(this);
- }
+ if (endInfo === null) {
+ return null;
+ }
- var properties = {
- FORMAT: {value: "ean_8", writeable: false}
- };
+ // reverse numbers
+ tmp = endInfo.start;
+ endInfo.start = self._row.length - endInfo.end;
+ endInfo.end = self._row.length - tmp;
- EAN8Reader.prototype = Object.create(EANReader.prototype, properties);
- EAN8Reader.prototype.constructor = EAN8Reader;
+ return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
+ };
- EAN8Reader.prototype._decodePayload = function(code, result, decodedCodes) {
+ I2of5Reader.prototype._decodePair = function(counterPair) {
var i,
+ code,
+ codes = [],
self = this;
- for ( i = 0; i < 4; i++) {
- code = self._decodeCode(code.end, self.CODE_G_START);
+ for (i = 0; i < counterPair.length; i++) {
+ code = self._decodeCode(counterPair[i]);
if (!code) {
return null;
}
- result.push(code.code);
- decodedCodes.push(code);
+ codes.push(code);
}
+ return codes;
+ };
- code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
- if (code === null) {
- return null;
- }
- decodedCodes.push(code);
+ I2of5Reader.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 ( i = 0; i < 4; i++) {
- code = self._decodeCode(code.end, self.CODE_G_START);
- if (!code) {
- return null;
+ for ( j = 0; j < counter.length; j++) {
+ sum += counter[j];
+ }
+ normalized = self._normalize(counter);
+ if (normalized) {
+ for (code = 0; code < self.CODE_PATTERN.length; code++) {
+ error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
+ if (error < bestMatch.error) {
+ bestMatch.code = code;
+ bestMatch.error = error;
+ }
+ }
+ if (bestMatch.error < epsilon) {
+ return bestMatch;
}
- decodedCodes.push(code);
- result.push(code.code);
}
-
- return code;
- };
-
- return (EAN8Reader);
- }
-);
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-
-define(
- 'upc_e_reader',[
- "./ean_reader"
- ],
- function(EANReader) {
- "use strict";
-
- function UPCEReader() {
- EANReader.call(this);
- }
-
- var properties = {
- CODE_FREQUENCY : {value: [
- [ 56, 52, 50, 49, 44, 38, 35, 42, 41, 37 ],
- [7, 11, 13, 14, 19, 25, 28, 21, 22, 26]]},
- STOP_PATTERN: { value: [1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7]},
- FORMAT: {value: "upc_e", writeable: false}
+ return null;
};
- UPCEReader.prototype = Object.create(EANReader.prototype, properties);
- UPCEReader.prototype.constructor = UPCEReader;
-
- UPCEReader.prototype._decodePayload = function(code, result, decodedCodes) {
+ I2of5Reader.prototype._decodePayload = function(counters, result, decodedCodes) {
var i,
self = this,
- codeFrequency = 0x0;
-
- for ( i = 0; i < 6; i++) {
- code = self._decodeCode(code.end);
- if (!code) {
+ pos = 0,
+ counterLength = counters.length,
+ counterPair = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]],
+ codes;
+
+ while (pos < counterLength) {
+ for (i = 0; i < 5; i++) {
+ counterPair[0][i] = counters[pos]*this.barSpaceRatio[0];
+ counterPair[1][i] = counters[pos + 1]*this.barSpaceRatio[1];
+ pos += 2;
+ }
+ codes = self._decodePair(counterPair);
+ if (!codes) {
return null;
}
- if (code.code >= self.CODE_G_START) {
- code.code = code.code - self.CODE_G_START;
- codeFrequency |= 1 << (5 - i);
+ for (i = 0; i < codes.length; i++) {
+ result.push(codes[i].code + "");
+ decodedCodes.push(codes[i]);
}
- result.push(code.code);
- decodedCodes.push(code);
- }
- if (!self._determineParity(codeFrequency, result)) {
- return null;
}
-
- return code;
+ return codes;
};
- UPCEReader.prototype._determineParity = function(codeFrequency, result) {
- var self =this,
- i,
- nrSystem;
-
- for (nrSystem = 0; nrSystem < self.CODE_FREQUENCY.length; nrSystem++){
- for ( i = 0; i < self.CODE_FREQUENCY[nrSystem].length; i++) {
- if (codeFrequency === self.CODE_FREQUENCY[nrSystem][i]) {
- result.unshift(nrSystem);
- result.push(i);
- return true;
- }
- }
- }
- return false;
+ I2of5Reader.prototype._verifyCounterLength = function(counters) {
+ return (counters.length % 10 === 0);
};
- UPCEReader.prototype._convertToUPCA = function(result) {
- var upca = [result[0]],
- lastDigit = result[result.length - 2];
+ I2of5Reader.prototype._decode = function() {
+ var startInfo,
+ endInfo,
+ self = this,
+ code,
+ result = [],
+ decodedCodes = [],
+ counters;
- if (lastDigit <= 2) {
- upca = upca.concat(result.slice(1, 3))
- .concat([lastDigit, 0, 0, 0, 0])
- .concat(result.slice(3, 6));
- } else if (lastDigit === 3) {
- upca = upca.concat(result.slice(1, 4))
- .concat([0 ,0, 0, 0, 0])
- .concat(result.slice(4,6));
- } else if (lastDigit === 4) {
- upca = upca.concat(result.slice(1, 5))
- .concat([0, 0, 0, 0, 0, result[5]]);
- } else {
- upca = upca.concat(result.slice(1, 6))
- .concat([0, 0, 0, 0, lastDigit]);
+ startInfo = self._findStart();
+ if (!startInfo) {
+ return null;
}
+ decodedCodes.push(startInfo);
- upca.push(result[result.length - 1]);
- return upca;
- };
+ endInfo = self._findEnd();
+ if (!endInfo) {
+ return null;
+ }
- UPCEReader.prototype._checksum = function(result) {
- return EANReader.prototype._checksum.call(this, this._convertToUPCA(result));
- };
+ 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 % 2 !== 0 ||
+ result.length < 6) {
+ return null;
+ }
- UPCEReader.prototype._findEnd = function(offset, isWhite) {
- isWhite = true;
- return EANReader.prototype._findEnd.call(this, offset, isWhite);
+ decodedCodes.push(endInfo);
+ return {
+ code : result.join(""),
+ start : startInfo.start,
+ end : endInfo.end,
+ startInfo : startInfo,
+ decodedCodes : decodedCodes
+ };
};
- UPCEReader.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;
- }
+ I2of5Reader.CONFIG_KEYS = {
+ normalizeBarSpaceWidth: {
+ 'type': 'boolean',
+ 'default': false,
+ 'description': 'If true, the reader tries to normalize the' +
+ 'width-difference between bars and spaces'
}
};
- return (UPCEReader);
+ return (I2of5Reader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
@@ -9248,7 +11550,8 @@ define('barcode_decoder',[
'codabar_reader',
'upc_reader',
'ean_8_reader',
- 'upc_e_reader'
+ 'upc_e_reader',
+ 'i2of5_reader'
], function(
Bresenham,
ImageDebug,
@@ -9259,7 +11562,8 @@ define('barcode_decoder',[
CodabarReader,
UPCReader,
EAN8Reader,
- UPCEReader) {
+ UPCEReader,
+ I2of5Reader) {
"use strict";
var readers = {
@@ -9270,7 +11574,8 @@ define('barcode_decoder',[
code_39_vin_reader: Code39VINReader,
codabar_reader: CodabarReader,
upc_reader: UPCReader,
- upc_e_reader: UPCEReader
+ upc_e_reader: UPCEReader,
+ i2of5_reader: I2of5Reader
};
var BarcodeDecoder = {
create : function(config, inputImageWrapper) {
@@ -9323,11 +11628,21 @@ define('barcode_decoder',[
}
function initReaders() {
- var i;
- for ( i = 0; i < config.readers.length; i++) {
- console.log(config.readers[i]);
- _barcodeReaders.push(new readers[config.readers[i]]());
- }
+ config.readers.forEach(function(readerConfig) {
+ var reader,
+ config = {};
+
+ if (typeof readerConfig === 'object') {
+ reader = readerConfig.format;
+ config = readerConfig.config;
+ } else if (typeof readerConfig === 'string') {
+ reader = readerConfig;
+ }
+ _barcodeReaders.push(new readers[reader](config));
+ });
+ console.log("Registered Readers: " + _barcodeReaders
+ .map(function(reader) {return JSON.stringify({format: reader.FORMAT, config: reader.config});})
+ .join(', '));
}
function initConfig() {
@@ -9607,46 +11922,6 @@ define('frame_grabber',["cv_utils"], function(CVUtils) {
return (FrameGrabber);
});
-/* jshint undef: true, unused: true, browser:true, devel: true */
-/* global define */
-
-define('html_utils',[], function() {
- "use strict";
-
- function createNode(htmlStr) {
- var temp = document.createElement('div');
-
- temp.innerHTML = htmlStr;
- while (temp.firstChild) {
- return temp.firstChild;
- }
- }
-
- function mergeObjects(obj1, obj2) {
- for (var p in obj2) {
- try {
- if (obj2[p].constructor == Object) {
- obj1[p] = mergeObjects(obj1[p], obj2[p]);
- } else {
- obj1[p] = obj2[p];
- }
- } catch(e) {
- obj1[p] = obj2[p];
- }
- }
-
- return obj1;
- }
-
- return {
- createNode : function(htmlStr) {
- return createNode(htmlStr);
- },
- mergeObjects : function(obj1, obj2) {
- return mergeObjects(obj1, obj2);
- }
- };
-});
/**
* The basic configuration
*/
@@ -10006,8 +12281,6 @@ define('result_collector',["image_debug"], function(ImageDebug) {
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
/* global define */
define('quagga',[
- "code_128_reader",
- "ean_reader",
"input_stream",
"image_wrapper",
"barcode_locator",
@@ -10020,9 +12293,7 @@ define('quagga',[
"image_debug",
"gl-matrix",
"result_collector"],
-function(Code128Reader,
- EANReader,
- InputStream,
+function(InputStream,
ImageWrapper,
BarcodeLocator,
BarcodeDecoder,
@@ -10462,9 +12733,15 @@ function(Code128Reader,
onDetected : function(callback) {
Events.subscribe("detected", callback);
},
+ offDetected: function(callback) {
+ Events.unsubscribe("detected", callback);
+ },
onProcessed: function(callback) {
Events.subscribe("processed", callback);
},
+ offProcessed: function(callback) {
+ Events.unsubscribe("processed", callback);
+ },
setReaders: function(readers) {
setReaders(readers);
},
@@ -10495,10 +12772,6 @@ function(Code128Reader,
start();
});
},
- Reader: {
- EANReader : EANReader,
- Code128Reader : Code128Reader
- },
ImageWrapper: ImageWrapper,
ImageDebug: ImageDebug,
ResultCollector: ResultCollector
diff --git a/dist/quagga.min.js b/dist/quagga.min.js
index 783e8ad..50565b5 100644
--- a/dist/quagga.min.js
+++ b/dist/quagga.min.js
@@ -1,9 +1,20 @@
+<<<<<<< HEAD
/*! quagga 2015-07-10 */
+=======
+/*! quagga 2015-08-13 */
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
!function(a,b){var c=b.toString();"undefined"!=typeof module?module.exports=b(c):a.Quagga=b(c)}(this,function(a){/**
* @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/almond for details
*/
+<<<<<<< HEAD
var b,c,d;return function(a){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(b,c){return function(){return n.apply(a,v.call(arguments,0).concat([b,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(b){if(e(r,b)){var c=r[b];delete r[b],t[b]=!0,m.apply(a,c)}if(!e(q,b)&&!e(t,b))throw new Error("No "+b);return q[b]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(b,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||b,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;ng)return Number.MAX_VALUE;d+=e}return d/f},a.prototype._nextSet=function(a,b){var c;for(b=b||0,c=b;c1)for(c=0;cd?(j.start=c-g,j.end=c,j.counter=e,j):null;i++,e[i]=1,h=!h}}else for(e.push(0),c=g;ca?0:a,d=a;b>d;d++)if(this._row[d]!==c)return!1;return!0},Object.defineProperty(a.prototype,"FORMAT",{value:"unknown",writeable:!1}),a.DIRECTION={FORWARD:1,REVERSE:-1},a.Exception={StartNotFoundException:"Start-Info was not found!",CodeNotFoundException:"Code could not be found!",PatternNotFoundException:"Pattern could not be found!"},a}),d("code_128_reader",["./barcode_reader"],function(a){"use strict";function b(){a.call(this)}var c={CODE_SHIFT:{value:98},CODE_C:{value:99},CODE_B:{value:100},CODE_A:{value:101},START_CODE_A:{value:103},START_CODE_B:{value:104},START_CODE_C:{value:105},STOP_CODE:{value:106},MODULO:{value:11},CODE_PATTERN:{value:[[2,1,2,2,2,2],[2,2,2,1,2,2],[2,2,2,2,2,1],[1,2,1,2,2,3],[1,2,1,3,2,2],[1,3,1,2,2,2],[1,2,2,2,1,3],[1,2,2,3,1,2],[1,3,2,2,1,2],[2,2,1,2,1,3],[2,2,1,3,1,2],[2,3,1,2,1,2],[1,1,2,2,3,2],[1,2,2,1,3,2],[1,2,2,2,3,1],[1,1,3,2,2,2],[1,2,3,1,2,2],[1,2,3,2,2,1],[2,2,3,2,1,1],[2,2,1,1,3,2],[2,2,1,2,3,1],[2,1,3,2,1,2],[2,2,3,1,1,2],[3,1,2,1,3,1],[3,1,1,2,2,2],[3,2,1,1,2,2],[3,2,1,2,2,1],[3,1,2,2,1,2],[3,2,2,1,1,2],[3,2,2,2,1,1],[2,1,2,1,2,3],[2,1,2,3,2,1],[2,3,2,1,2,1],[1,1,1,3,2,3],[1,3,1,1,2,3],[1,3,1,3,2,1],[1,1,2,3,1,3],[1,3,2,1,1,3],[1,3,2,3,1,1],[2,1,1,3,1,3],[2,3,1,1,1,3],[2,3,1,3,1,1],[1,1,2,1,3,3],[1,1,2,3,3,1],[1,3,2,1,3,1],[1,1,3,1,2,3],[1,1,3,3,2,1],[1,3,3,1,2,1],[3,1,3,1,2,1],[2,1,1,3,3,1],[2,3,1,1,3,1],[2,1,3,1,1,3],[2,1,3,3,1,1],[2,1,3,1,3,1],[3,1,1,1,2,3],[3,1,1,3,2,1],[3,3,1,1,2,1],[3,1,2,1,1,3],[3,1,2,3,1,1],[3,3,2,1,1,1],[3,1,4,1,1,1],[2,2,1,4,1,1],[4,3,1,1,1,1],[1,1,1,2,2,4],[1,1,1,4,2,2],[1,2,1,1,2,4],[1,2,1,4,2,1],[1,4,1,1,2,2],[1,4,1,2,2,1],[1,1,2,2,1,4],[1,1,2,4,1,2],[1,2,2,1,1,4],[1,2,2,4,1,1],[1,4,2,1,1,2],[1,4,2,2,1,1],[2,4,1,2,1,1],[2,2,1,1,1,4],[4,1,3,1,1,1],[2,4,1,1,1,2],[1,3,4,1,1,1],[1,1,1,2,4,2],[1,2,1,1,4,2],[1,2,1,2,4,1],[1,1,4,2,1,2],[1,2,4,1,1,2],[1,2,4,2,1,1],[4,1,1,2,1,2],[4,2,1,1,1,2],[4,2,1,2,1,1],[2,1,2,1,4,1],[2,1,4,1,2,1],[4,1,2,1,2,1],[1,1,1,1,4,3],[1,1,1,3,4,1],[1,3,1,1,4,1],[1,1,4,1,1,3],[1,1,4,3,1,1],[4,1,1,1,1,3],[4,1,1,3,1,1],[1,1,3,1,4,1],[1,1,4,1,3,1],[3,1,1,1,4,1],[4,1,1,1,3,1],[2,1,1,4,1,2],[2,1,1,2,1,4],[2,1,1,2,3,2],[2,3,3,1,1,1,2]]},SINGLE_CODE_ERROR:{value:1},AVG_CODE_ERROR:{value:.5},FORMAT:{value:"code_128",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodeCode=function(a){var b,c,d,e,f=[0,0,0,0,0,0],g=this,h=a,i=!g._row[h],j=0,k={error:Number.MAX_VALUE,code:-1,start:a,end:a};for(b=h;bd;d++)g[d]=g[d+2];g[4]=0,g[5]=0,k--}else k++;g[k]=1,j=!j}return null},b.prototype._decode=function(){var a,b,c,d=this,e=d._findStart(),f=null,g=!1,h=[],i=0,j=0,k=[],l=[],m=!1;if(null===e)return null;switch(f={code:e.code,start:e.start,end:e.end},l.push(f),j=f.code,f.code){case d.START_CODE_A:a=d.CODE_A;break;case d.START_CODE_B:a=d.CODE_B;break;case d.START_CODE_C:a=d.CODE_C;break;default:return null}for(;!g;){if(b=m,m=!1,f=d._decodeCode(f.end),null!==f)switch(f.code!==d.STOP_CODE&&(k.push(f.code),i++,j+=i*f.code),l.push(f),a){case d.CODE_A:if(f.code<64)h.push(String.fromCharCode(32+f.code));else if(f.code<96)h.push(String.fromCharCode(f.code-64));else switch(f.code){case d.CODE_SHIFT:m=!0,a=d.CODE_B;break;case d.CODE_B:a=d.CODE_B;break;case d.CODE_C:a=d.CODE_C;break;case d.STOP_CODE:g=!0}break;case d.CODE_B:if(f.code<96)h.push(String.fromCharCode(32+f.code));else switch(f.code!=d.STOP_CODE&&(c=!1),f.code){case d.CODE_SHIFT:m=!0,a=d.CODE_A;break;case d.CODE_A:a=d.CODE_A;break;case d.CODE_C:a=d.CODE_C;break;case d.STOP_CODE:g=!0}break;case d.CODE_C:switch(f.code<100&&h.push(f.code<10?"0"+f.code:f.code),f.code){case d.CODE_A:a=d.CODE_A;break;case d.CODE_B:a=d.CODE_B;break;case d.STOP_CODE:g=!0}}else g=!0;b&&(a=a==d.CODE_A?d.CODE_B:d.CODE_A)}return null===f?null:(f.end=d._nextUnset(d._row,f.end),d._verifyTrailingWhitespace(f)?(j-=i*k[k.length-1],j%103!=k[k.length-1]?null:h.length?(h.splice(h.length-1,1),{code:h.join(""),start:e.start,end:f.end,codeset:a,startInfo:e,decodedCodes:l,endInfo:f}):null):null)},a.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,bd;d++)e=h._matchPattern(f,h.CODE_PATTERN[d]),eh.AVG_CODE_ERROR?null:l}}else k++;g[k]=1,j=!j}return null},b.prototype._findPattern=function(a,b,c,d,e){var f,g,h,i,j,k=[],l=this,m=0,n={error:Number.MAX_VALUE,code:-1,start:0,end:0};for(b||(b=l._nextSet(l._row)),void 0===c&&(c=!1),void 0===d&&(d=!0),void 0===e&&(e=l.AVG_CODE_ERROR),f=0;fg))return n.error=g,n.start=f-i,n.end=f,n;if(!d)return null;for(h=0;h=0&&c._matchRange(a,b.start,0))return b;d=b.end,b=null}},b.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start),bd;d++){if(a=f._decodeCode(a.end),!a)return null;a.code>=f.CODE_G_START?(a.code=a.code-f.CODE_G_START,g|=1<<5-d):g|=0<<5-d,b.push(a.code),c.push(a)}if(e=f._calculateFirstDigit(g),null===e)return null;if(b.unshift(e),a=f._findPattern(f.MIDDLE_PATTERN,a.end,!0,!1),null===a)return null;for(c.push(a),d=0;6>d;d++){if(a=f._decodeCode(a.end,f.CODE_G_START),!a)return null;c.push(a),b.push(a.code)}return a},b.prototype._decode=function(){var a,b,c=this,d=[],e=[];return(a=c._findStart())?(b={code:a.code,start:a.start,end:a.end},e.push(b),(b=c._decodePayload(b,d,e))&&(b=c._findEnd(b.end,!1))?(e.push(b),c._checksum(d)?{code:d.join(""),start:a.start,end:b.end,codeset:"",startInfo:a,decodedCodes:e}:null):null):null},b.prototype._checksum=function(a){var b,c=0;for(b=a.length-2;b>=0;b-=2)c+=a[b];for(c*=3,b=a.length-1;b>=0;b-=2)c+=a[b];return c%10===0},b}),d("image_loader",[],function(){"use strict";function a(a,b){a.onload=function(){b.loaded(this)}}var b={};return b.load=function(b,c,d,e,f){var g,h,i,j=new Array(e),k=new Array(j.length);if(f===!1)j[0]=b;else for(g=0;g1?f.size:Math.floor(b/e*f.size):b,d=f.size?b/e>1?Math.floor(e/b*f.size):f.size:e,j.x=c,j.y=d}var c,d,e={},f=null,g=["canrecord","ended"],h={},i={x:0,y:0},j={x:0,y:0};return e.getRealWidth=function(){return a.videoWidth},e.getRealHeight=function(){return a.videoHeight},e.getWidth=function(){return c},e.getHeight=function(){return d},e.setWidth=function(a){c=a},e.setHeight=function(a){d=a},e.setInputStream=function(b){f=b,a.src="undefined"!=typeof b.src?b.src:""},e.ended=function(){return a.ended},e.getConfig=function(){return f},e.setAttribute=function(b,c){a.setAttribute(b,c)},e.pause=function(){a.pause()},e.play=function(){a.play()},e.setCurrentTime=function(b){"LiveStream"!==f.type&&(a.currentTime=b)},e.addEventListener=function(b,c,d){-1!==g.indexOf(b)?(h[b]||(h[b]=[]),h[b].push(c)):a.addEventListener(b,c,d)},e.clearEventHandlers=function(){g.forEach(function(b){var c=h[b];c&&c.length>0&&c.forEach(function(c){a.removeEventListener(b,c)})})},e.trigger=function(a,c){var d,f=h[a];if("canrecord"===a&&b(),f&&f.length>0)for(d=0;d1?g.size:Math.floor(h/i*g.size):h,e=g.size?h/i>1?Math.floor(i/h*g.size):g.size:i,u.x=d,u.y=e,l=!0,j=0,setTimeout(function(){c("canrecord",[])},0)},o,n,g.sequence)}function c(a,b){var c,d=s[a];if(d&&d.length>0)for(c=0;cj?j++:setTimeout(function(){q=!0,c("ended",[])},0)),a):null},f},b}),glMatrixArrayType=Float32Array,"undefined"!=typeof window&&(window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia,window.URL=window.URL||window.webkitURL||window.mozURL||window.msURL),d("typedefs",function(a){return function(){var b;return b||a.typedefs}}(this)),d("subImage",["typedefs"],function(){"use strict";function a(a,b,c){c||(c={data:null,size:b}),this.data=c.data,this.originalSize=c.size,this.I=c,this.from=a,this.size=b}return a.prototype.show=function(a,b){var c,d,e,f,g,h,i;for(b||(b=1),c=a.getContext("2d"),a.width=this.size.x,a.height=this.size.y,d=c.getImageData(0,0,a.width,a.height),e=d.data,f=0,g=0;g0&&(e=1/Math.sqrt(e),a[0]=b[0]*e,a[1]=b[1]*e),a},e.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]},e.cross=function(a,b,c){var d=b[0]*c[1]-b[1]*c[0];return a[0]=a[1]=0,a[2]=d,a},e.lerp=function(a,b,c,d){var e=b[0],f=b[1];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a},e.transformMat2=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[2]*e,a[1]=c[1]*d+c[3]*e,a},e.transformMat2d=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[2]*e+c[4],a[1]=c[1]*d+c[3]*e+c[5],a},e.transformMat3=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[3]*e+c[6],a[1]=c[1]*d+c[4]*e+c[7],a},e.transformMat4=function(a,b,c){var d=b[0],e=b[1];return a[0]=c[0]*d+c[4]*e+c[12],a[1]=c[1]*d+c[5]*e+c[13],a},e.forEach=function(){var a=e.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=2),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],f(a,a,g),b[h]=a[0],b[h+1]=a[1];return b}}(),e.str=function(a){return"vec2("+a[0]+", "+a[1]+")"},"undefined"!=typeof a&&(a.vec2=e);var f={};f.create=function(){var a=new c(3);return a[0]=0,a[1]=0,a[2]=0,a},f.clone=function(a){var b=new c(3);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b},f.fromValues=function(a,b,d){var e=new c(3);return e[0]=a,e[1]=b,e[2]=d,e},f.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a},f.set=function(a,b,c,d){return a[0]=b,a[1]=c,a[2]=d,a},f.add=function(a,b,c){return a[0]=b[0]+c[0],a[1]=b[1]+c[1],a[2]=b[2]+c[2],a},f.subtract=function(a,b,c){return a[0]=b[0]-c[0],a[1]=b[1]-c[1],a[2]=b[2]-c[2],a},f.sub=f.subtract,f.multiply=function(a,b,c){return a[0]=b[0]*c[0],a[1]=b[1]*c[1],a[2]=b[2]*c[2],a},f.mul=f.multiply,f.divide=function(a,b,c){return a[0]=b[0]/c[0],a[1]=b[1]/c[1],a[2]=b[2]/c[2],a},f.div=f.divide,f.min=function(a,b,c){return a[0]=Math.min(b[0],c[0]),a[1]=Math.min(b[1],c[1]),a[2]=Math.min(b[2],c[2]),a},f.max=function(a,b,c){return a[0]=Math.max(b[0],c[0]),a[1]=Math.max(b[1],c[1]),a[2]=Math.max(b[2],c[2]),a},f.scale=function(a,b,c){return a[0]=b[0]*c,a[1]=b[1]*c,a[2]=b[2]*c,a},f.distance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2];return Math.sqrt(c*c+d*d+e*e)},f.dist=f.distance,f.squaredDistance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2];return c*c+d*d+e*e},f.sqrDist=f.squaredDistance,f.length=function(a){var b=a[0],c=a[1],d=a[2];return Math.sqrt(b*b+c*c+d*d)},f.len=f.length,f.squaredLength=function(a){var b=a[0],c=a[1],d=a[2];return b*b+c*c+d*d},f.sqrLen=f.squaredLength,f.negate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a},f.normalize=function(a,b){var c=b[0],d=b[1],e=b[2],f=c*c+d*d+e*e;return f>0&&(f=1/Math.sqrt(f),a[0]=b[0]*f,a[1]=b[1]*f,a[2]=b[2]*f),a},f.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},f.cross=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2];return a[0]=e*i-f*h,a[1]=f*g-d*i,a[2]=d*h-e*g,a},f.lerp=function(a,b,c,d){var e=b[0],f=b[1],g=b[2];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a[2]=g+d*(c[2]-g),a},f.transformMat4=function(a,b,c){var d=b[0],e=b[1],f=b[2];return a[0]=c[0]*d+c[4]*e+c[8]*f+c[12],a[1]=c[1]*d+c[5]*e+c[9]*f+c[13],a[2]=c[2]*d+c[6]*e+c[10]*f+c[14],a},f.transformQuat=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2],j=c[3],k=j*d+h*f-i*e,l=j*e+i*d-g*f,m=j*f+g*e-h*d,n=-g*d-h*e-i*f;return a[0]=k*j+n*-g+l*-i-m*-h,a[1]=l*j+n*-h+m*-g-k*-i,a[2]=m*j+n*-i+k*-h-l*-g,a},f.forEach=function(){var a=f.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=3),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],a[2]=b[h+2],f(a,a,g),b[h]=a[0],b[h+1]=a[1],b[h+2]=a[2];return b}}(),f.str=function(a){return"vec3("+a[0]+", "+a[1]+", "+a[2]+")"},"undefined"!=typeof a&&(a.vec3=f);var g={};g.create=function(){var a=new c(4);return a[0]=0,a[1]=0,a[2]=0,a[3]=0,a},g.clone=function(a){var b=new c(4);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b},g.fromValues=function(a,b,d,e){var f=new c(4);return f[0]=a,f[1]=b,f[2]=d,f[3]=e,f},g.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a},g.set=function(a,b,c,d,e){return a[0]=b,a[1]=c,a[2]=d,a[3]=e,a},g.add=function(a,b,c){return a[0]=b[0]+c[0],a[1]=b[1]+c[1],a[2]=b[2]+c[2],a[3]=b[3]+c[3],a},g.subtract=function(a,b,c){return a[0]=b[0]-c[0],a[1]=b[1]-c[1],a[2]=b[2]-c[2],a[3]=b[3]-c[3],a},g.sub=g.subtract,g.multiply=function(a,b,c){return a[0]=b[0]*c[0],a[1]=b[1]*c[1],a[2]=b[2]*c[2],a[3]=b[3]*c[3],a},g.mul=g.multiply,g.divide=function(a,b,c){return a[0]=b[0]/c[0],a[1]=b[1]/c[1],a[2]=b[2]/c[2],a[3]=b[3]/c[3],a},g.div=g.divide,g.min=function(a,b,c){return a[0]=Math.min(b[0],c[0]),a[1]=Math.min(b[1],c[1]),a[2]=Math.min(b[2],c[2]),a[3]=Math.min(b[3],c[3]),a},g.max=function(a,b,c){return a[0]=Math.max(b[0],c[0]),a[1]=Math.max(b[1],c[1]),a[2]=Math.max(b[2],c[2]),a[3]=Math.max(b[3],c[3]),a},g.scale=function(a,b,c){return a[0]=b[0]*c,a[1]=b[1]*c,a[2]=b[2]*c,a[3]=b[3]*c,a},g.distance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2],f=b[3]-a[3];return Math.sqrt(c*c+d*d+e*e+f*f)},g.dist=g.distance,g.squaredDistance=function(a,b){var c=b[0]-a[0],d=b[1]-a[1],e=b[2]-a[2],f=b[3]-a[3];return c*c+d*d+e*e+f*f},g.sqrDist=g.squaredDistance,g.length=function(a){var b=a[0],c=a[1],d=a[2],e=a[3];return Math.sqrt(b*b+c*c+d*d+e*e)},g.len=g.length,g.squaredLength=function(a){var b=a[0],c=a[1],d=a[2],e=a[3];return b*b+c*c+d*d+e*e},g.sqrLen=g.squaredLength,g.negate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a[3]=-b[3],a},g.normalize=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*c+d*d+e*e+f*f;return g>0&&(g=1/Math.sqrt(g),a[0]=b[0]*g,a[1]=b[1]*g,a[2]=b[2]*g,a[3]=b[3]*g),a},g.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]},g.lerp=function(a,b,c,d){var e=b[0],f=b[1],g=b[2],h=b[3];return a[0]=e+d*(c[0]-e),a[1]=f+d*(c[1]-f),a[2]=g+d*(c[2]-g),a[3]=h+d*(c[3]-h),a},g.transformMat4=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3];return a[0]=c[0]*d+c[4]*e+c[8]*f+c[12]*g,a[1]=c[1]*d+c[5]*e+c[9]*f+c[13]*g,a[2]=c[2]*d+c[6]*e+c[10]*f+c[14]*g,a[3]=c[3]*d+c[7]*e+c[11]*f+c[15]*g,a},g.transformQuat=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=c[0],h=c[1],i=c[2],j=c[3],k=j*d+h*f-i*e,l=j*e+i*d-g*f,m=j*f+g*e-h*d,n=-g*d-h*e-i*f;return a[0]=k*j+n*-g+l*-i-m*-h,a[1]=l*j+n*-h+m*-g-k*-i,a[2]=m*j+n*-i+k*-h-l*-g,a},g.forEach=function(){var a=g.create();return function(b,c,d,e,f,g){var h,i;for(c||(c=4),d||(d=0),i=e?Math.min(e*c+d,b.length):b.length,h=d;i>h;h+=c)a[0]=b[h],a[1]=b[h+1],a[2]=b[h+2],a[3]=b[h+3],f(a,a,g),b[h]=a[0],b[h+1]=a[1],b[h+2]=a[2],b[h+3]=a[3];return b}}(),g.str=function(a){return"vec4("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},"undefined"!=typeof a&&(a.vec4=g);{var h={};new Float32Array([1,0,0,1])}h.create=function(){var a=new c(4);return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a},h.clone=function(a){var b=new c(4);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b},h.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a},h.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a},h.transpose=function(a,b){if(a===b){var c=b[1];a[1]=b[2],a[2]=c}else a[0]=b[0],a[1]=b[2],a[2]=b[1],a[3]=b[3];return a},h.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*f-e*d;return g?(g=1/g,a[0]=f*g,a[1]=-d*g,a[2]=-e*g,a[3]=c*g,a):null},h.adjoint=function(a,b){var c=b[0];return a[0]=b[3],a[1]=-b[1],a[2]=-b[2],a[3]=c,a},h.determinant=function(a){return a[0]*a[3]-a[2]*a[1]},h.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=c[0],i=c[1],j=c[2],k=c[3];return a[0]=d*h+e*j,a[1]=d*i+e*k,a[2]=f*h+g*j,a[3]=f*i+g*k,a},h.mul=h.multiply,h.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=Math.sin(c),i=Math.cos(c);return a[0]=d*i+e*h,a[1]=d*-h+e*i,a[2]=f*i+g*h,a[3]=f*-h+g*i,a},h.scale=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=c[0],i=c[1];return a[0]=d*h,a[1]=e*i,a[2]=f*h,a[3]=g*i,a},h.str=function(a){return"mat2("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},"undefined"!=typeof a&&(a.mat2=h);{var i={};new Float32Array([1,0,0,1,0,0])}i.create=function(){var a=new c(6);return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a[4]=0,a[5]=0,a},i.clone=function(a){var b=new c(6);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b},i.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4],a[5]=b[5],a},i.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=1,a[4]=0,a[5]=0,a},i.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=c*f-d*e;return i?(i=1/i,a[0]=f*i,a[1]=-d*i,a[2]=-e*i,a[3]=c*i,a[4]=(e*h-f*g)*i,a[5]=(d*g-c*h)*i,a):null},i.determinant=function(a){return a[0]*a[3]-a[1]*a[2]},i.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=c[0],k=c[1],l=c[2],m=c[3],n=c[4],o=c[5];return a[0]=d*j+e*l,a[1]=d*k+e*m,a[2]=f*j+g*l,a[3]=f*k+g*m,a[4]=j*h+l*i+n,a[5]=k*h+m*i+o,a},i.mul=i.multiply,i.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=Math.sin(c),k=Math.cos(c);return a[0]=d*k+e*j,a[1]=-d*j+e*k,a[2]=f*k+g*j,a[3]=-f*j+k*g,a[4]=k*h+j*i,a[5]=k*i-j*h,a},i.scale=function(a,b,c){var d=c[0],e=c[1];return a[0]=b[0]*d,a[1]=b[1]*e,a[2]=b[2]*d,a[3]=b[3]*e,a[4]=b[4]*d,a[5]=b[5]*e,a},i.translate=function(a,b,c){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4]+c[0],a[5]=b[5]+c[1],a},i.str=function(a){return"mat2d("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+")"},"undefined"!=typeof a&&(a.mat2d=i);{var j={};new Float32Array([1,0,0,0,1,0,0,0,1])}j.create=function(){var a=new c(9);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},j.clone=function(a){var b=new c(9);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},j.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4],a[5]=b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a},j.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},j.transpose=function(a,b){if(a===b){var c=b[1],d=b[2],e=b[5];a[1]=b[3],a[2]=b[6],a[3]=c,a[5]=b[7],a[6]=d,a[7]=e}else a[0]=b[0],a[1]=b[3],a[2]=b[6],a[3]=b[1],a[4]=b[4],a[5]=b[7],a[6]=b[2],a[7]=b[5],a[8]=b[8];return a},j.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=k*g-h*j,m=-k*f+h*i,n=j*f-g*i,o=c*l+d*m+e*n;return o?(o=1/o,a[0]=l*o,a[1]=(-k*d+e*j)*o,a[2]=(h*d-e*g)*o,a[3]=m*o,a[4]=(k*c-e*i)*o,a[5]=(-h*c+e*f)*o,a[6]=n*o,a[7]=(-j*c+d*i)*o,a[8]=(g*c-d*f)*o,a):null},j.adjoint=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8];return a[0]=g*k-h*j,a[1]=e*j-d*k,a[2]=d*h-e*g,a[3]=h*i-f*k,a[4]=c*k-e*i,a[5]=e*f-c*h,a[6]=f*j-g*i,a[7]=d*i-c*j,a[8]=c*g-d*f,a},j.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8];return b*(j*f-g*i)+c*(-j*e+g*h)+d*(i*e-f*h)},j.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=c[0],n=c[1],o=c[2],p=c[3],q=c[4],r=c[5],s=c[6],t=c[7],u=c[8];return a[0]=m*d+n*g+o*j,a[1]=m*e+n*h+o*k,a[2]=m*f+n*i+o*l,a[3]=p*d+q*g+r*j,a[4]=p*e+q*h+r*k,a[5]=p*f+q*i+r*l,a[6]=s*d+t*g+u*j,a[7]=s*e+t*h+u*k,a[8]=s*f+t*i+u*l,a},j.mul=j.multiply,j.translate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=c[0],n=c[1];return a[0]=d,a[1]=e,a[2]=f,a[3]=g,a[4]=h,a[5]=i,a[6]=m*d+n*g+j,a[7]=m*e+n*h+k,a[8]=m*f+n*i+l,a},j.rotate=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=Math.sin(c),n=Math.cos(c);return a[0]=n*d+m*g,a[1]=n*e+m*h,a[2]=n*f+m*i,a[3]=n*g-m*d,a[4]=n*h-m*e,a[5]=n*i-m*f,a[6]=j,a[7]=k,a[8]=l,a},j.scale=function(a,b,c){var d=c[0],e=c[2];return a[0]=d*b[0],a[1]=d*b[1],a[2]=d*b[2],a[3]=e*b[3],a[4]=e*b[4],a[5]=e*b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a},j.fromMat2d=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=0,a[3]=b[2],a[4]=b[3],a[5]=0,a[6]=b[4],a[7]=b[5],a[8]=1,a},j.fromQuat=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c+c,h=d+d,i=e+e,j=c*g,k=c*h,l=c*i,m=d*h,n=d*i,o=e*i,p=f*g,q=f*h,r=f*i;return a[0]=1-(m+o),a[1]=k+r,a[2]=l-q,a[3]=k-r,a[4]=1-(j+o),a[5]=n+p,a[6]=l+q,a[7]=n-p,a[8]=1-(j+m),a},j.str=function(a){return"mat3("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+")"},"undefined"!=typeof a&&(a.mat3=j);{var k={};new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])}k.create=function(){var a=new c(16);return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},k.clone=function(a){var b=new c(16);return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15],b},k.copy=function(a,b){return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4],a[5]=b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a[9]=b[9],a[10]=b[10],a[11]=b[11],a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15],a},k.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},k.transpose=function(a,b){if(a===b){var c=b[1],d=b[2],e=b[3],f=b[6],g=b[7],h=b[11];a[1]=b[4],a[2]=b[8],a[3]=b[12],a[4]=c,a[6]=b[9],a[7]=b[13],a[8]=d,a[9]=f,a[11]=b[14],a[12]=e,a[13]=g,a[14]=h
}else a[0]=b[0],a[1]=b[4],a[2]=b[8],a[3]=b[12],a[4]=b[1],a[5]=b[5],a[6]=b[9],a[7]=b[13],a[8]=b[2],a[9]=b[6],a[10]=b[10],a[11]=b[14],a[12]=b[3],a[13]=b[7],a[14]=b[11],a[15]=b[15];return a},k.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9],m=b[10],n=b[11],o=b[12],p=b[13],q=b[14],r=b[15],s=c*h-d*g,t=c*i-e*g,u=c*j-f*g,v=d*i-e*h,w=d*j-f*h,x=e*j-f*i,y=k*p-l*o,z=k*q-m*o,A=k*r-n*o,B=l*q-m*p,C=l*r-n*p,D=m*r-n*q,E=s*D-t*C+u*B+v*A-w*z+x*y;return E?(E=1/E,a[0]=(h*D-i*C+j*B)*E,a[1]=(e*C-d*D-f*B)*E,a[2]=(p*x-q*w+r*v)*E,a[3]=(m*w-l*x-n*v)*E,a[4]=(i*A-g*D-j*z)*E,a[5]=(c*D-e*A+f*z)*E,a[6]=(q*u-o*x-r*t)*E,a[7]=(k*x-m*u+n*t)*E,a[8]=(g*C-h*A+j*y)*E,a[9]=(d*A-c*C-f*y)*E,a[10]=(o*w-p*u+r*s)*E,a[11]=(l*u-k*w-n*s)*E,a[12]=(h*z-g*B-i*y)*E,a[13]=(c*B-d*z+e*y)*E,a[14]=(p*t-o*v-q*s)*E,a[15]=(k*v-l*t+m*s)*E,a):null},k.adjoint=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9],m=b[10],n=b[11],o=b[12],p=b[13],q=b[14],r=b[15];return a[0]=h*(m*r-n*q)-l*(i*r-j*q)+p*(i*n-j*m),a[1]=-(d*(m*r-n*q)-l*(e*r-f*q)+p*(e*n-f*m)),a[2]=d*(i*r-j*q)-h*(e*r-f*q)+p*(e*j-f*i),a[3]=-(d*(i*n-j*m)-h*(e*n-f*m)+l*(e*j-f*i)),a[4]=-(g*(m*r-n*q)-k*(i*r-j*q)+o*(i*n-j*m)),a[5]=c*(m*r-n*q)-k*(e*r-f*q)+o*(e*n-f*m),a[6]=-(c*(i*r-j*q)-g*(e*r-f*q)+o*(e*j-f*i)),a[7]=c*(i*n-j*m)-g*(e*n-f*m)+k*(e*j-f*i),a[8]=g*(l*r-n*p)-k*(h*r-j*p)+o*(h*n-j*l),a[9]=-(c*(l*r-n*p)-k*(d*r-f*p)+o*(d*n-f*l)),a[10]=c*(h*r-j*p)-g*(d*r-f*p)+o*(d*j-f*h),a[11]=-(c*(h*n-j*l)-g*(d*n-f*l)+k*(d*j-f*h)),a[12]=-(g*(l*q-m*p)-k*(h*q-i*p)+o*(h*m-i*l)),a[13]=c*(l*q-m*p)-k*(d*q-e*p)+o*(d*m-e*l),a[14]=-(c*(h*q-i*p)-g*(d*q-e*p)+o*(d*i-e*h)),a[15]=c*(h*m-i*l)-g*(d*m-e*l)+k*(d*i-e*h),a},k.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],m=a[11],n=a[12],o=a[13],p=a[14],q=a[15],r=b*g-c*f,s=b*h-d*f,t=b*i-e*f,u=c*h-d*g,v=c*i-e*g,w=d*i-e*h,x=j*o-k*n,y=j*p-l*n,z=j*q-m*n,A=k*p-l*o,B=k*q-m*o,C=l*q-m*p;return r*C-s*B+t*A+u*z-v*y+w*x},k.multiply=function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=b[9],n=b[10],o=b[11],p=b[12],q=b[13],r=b[14],s=b[15],t=c[0],u=c[1],v=c[2],w=c[3];return a[0]=t*d+u*h+v*l+w*p,a[1]=t*e+u*i+v*m+w*q,a[2]=t*f+u*j+v*n+w*r,a[3]=t*g+u*k+v*o+w*s,t=c[4],u=c[5],v=c[6],w=c[7],a[4]=t*d+u*h+v*l+w*p,a[5]=t*e+u*i+v*m+w*q,a[6]=t*f+u*j+v*n+w*r,a[7]=t*g+u*k+v*o+w*s,t=c[8],u=c[9],v=c[10],w=c[11],a[8]=t*d+u*h+v*l+w*p,a[9]=t*e+u*i+v*m+w*q,a[10]=t*f+u*j+v*n+w*r,a[11]=t*g+u*k+v*o+w*s,t=c[12],u=c[13],v=c[14],w=c[15],a[12]=t*d+u*h+v*l+w*p,a[13]=t*e+u*i+v*m+w*q,a[14]=t*f+u*j+v*n+w*r,a[15]=t*g+u*k+v*o+w*s,a},k.mul=k.multiply,k.translate=function(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=c[0],q=c[1],r=c[2];return b===a?(a[12]=b[0]*p+b[4]*q+b[8]*r+b[12],a[13]=b[1]*p+b[5]*q+b[9]*r+b[13],a[14]=b[2]*p+b[6]*q+b[10]*r+b[14],a[15]=b[3]*p+b[7]*q+b[11]*r+b[15]):(d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5],j=b[6],k=b[7],l=b[8],m=b[9],n=b[10],o=b[11],a[0]=d,a[1]=e,a[2]=f,a[3]=g,a[4]=h,a[5]=i,a[6]=j,a[7]=k,a[8]=l,a[9]=m,a[10]=n,a[11]=o,a[12]=d*p+h*q+l*r+b[12],a[13]=e*p+i*q+m*r+b[13],a[14]=f*p+j*q+n*r+b[14],a[15]=g*p+k*q+o*r+b[15]),a},k.scale=function(a,b,c){var d=c[0],e=c[1],f=c[2];return a[0]=b[0]*d,a[1]=b[1]*d,a[2]=b[2]*d,a[3]=b[3]*d,a[4]=b[4]*e,a[5]=b[5]*e,a[6]=b[6]*e,a[7]=b[7]*e,a[8]=b[8]*f,a[9]=b[9]*f,a[10]=b[10]*f,a[11]=b[11]*f,a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15],a},k.rotate=function(a,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D=e[0],E=e[1],F=e[2],G=Math.sqrt(D*D+E*E+F*F);return Math.abs(G)=1?(a!==b&&(a[0]=i,a[1]=j,a[2]=k,a[3]=l),a):(e=Math.acos(q),f=Math.sqrt(1-q*q),Math.abs(f)<.001?(a[0]=.5*i+.5*m,a[1]=.5*j+.5*n,a[2]=.5*k+.5*o,a[3]=.5*l+.5*p,a):(g=Math.sin((1-d)*e)/f,h=Math.sin(d*e)/f,a[0]=i*g+m*h,a[1]=j*g+n*h,a[2]=k*g+o*h,a[3]=l*g+p*h,a))},l.invert=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=c*c+d*d+e*e+f*f,h=g?1/g:0;return a[0]=-c*h,a[1]=-d*h,a[2]=-e*h,a[3]=f*h,a},l.conjugate=function(a,b){return a[0]=-b[0],a[1]=-b[1],a[2]=-b[2],a[3]=b[3],a},l.length=g.length,l.len=l.length,l.squaredLength=g.squaredLength,l.sqrLen=l.squaredLength,l.normalize=g.normalize,l.fromMat3=function(){var a=[1,2,0];return function(b,c){var d,e=c[0]+c[4]+c[8];if(e>0)d=Math.sqrt(e+1),b[3]=.5*d,d=.5/d,b[0]=(c[7]-c[5])*d,b[1]=(c[2]-c[6])*d,b[2]=(c[3]-c[1])*d;else{var f=0;c[4]>c[0]&&(f=1),c[8]>c[3*f+f]&&(f=2);var g=a[f],h=a[g];d=Math.sqrt(c[3*f+f]-c[3*g+g]-c[3*h+h]+1),b[f]=.5*d,d=.5/d,b[3]=(c[3*h+g]-c[3*g+h])*d,b[g]=(c[3*g+f]+c[3*f+g])*d,b[h]=(c[3*h+f]+c[3*f+h])*d}return b}}(),l.str=function(a){return"quat("+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+")"},"undefined"!=typeof a&&(a.quat=l)}(a.exports)}(),d("cluster",["gl-matrix"],function(a){"use strict";var b=a.vec2,c={create:function(a,c){function d(){e(a),f()}function e(a){i[a.id]=a,g.push(a)}function f(){var a,c=0;for(a=0;ac?!0:!1},getPoints:function(){return g},getCenter:function(){return h}}},createPoint:function(a,b,c){return{rad:a[c],point:a,id:b}}};return c}),d("array_helper",[],function(){"use strict";return{init:function(a,b){for(var c=a.length;c--;)a[c]=b},shuffle:function(a){var b,c,d=a.length-1;for(d;d>=0;d--)b=Math.floor(Math.random()*d),c=a[d],a[d]=a[b],a[b]=c;return a},toPointList:function(a){var b,c,d=[],e=[];for(b=0;b=b&&e.push(a[d]);return e},maxIndex:function(a){var b,c=0;for(b=0;ba[c]&&(c=b);return c},max:function(a){var b,c=0;for(b=0;bc&&(c=a[b]);return c},sum:function(a){for(var b=a.length,c=0;b--;)c+=a[b];return c}}}),d("cv_utils",["cluster","array_helper","gl-matrix"],function(a,b,c){"use strict";var d={},e=c.vec2,f=c.vec3;return d.imageRef=function(a,b){var c={x:a,y:b,toVec2:function(){return e.clone([this.x,this.y])},toVec3:function(){return f.clone([this.x,this.y,1])},round:function(){return this.x=Math.floor(this.x>0?this.x+.5:this.x-.5),this.y=Math.floor(this.y>0?this.y+.5:this.y-.5),this}};return c},d.computeIntegralImage2=function(a,b){var c,d,e=a.data,f=a.size.x,g=a.size.y,h=b.data,i=0,j=0,k=0,l=0,m=0;for(k=f,i=0,d=1;g>d;d++)i+=e[j],h[k]+=i,j+=f,k+=f;for(j=0,k=1,i=0,c=1;f>c;c++)i+=e[j],h[k]+=i,j++,k++;for(d=1;g>d;d++)for(j=d*f+1,k=(d-1)*f+1,l=d*f,m=(d-1)*f,c=1;f>c;c++)h[j]+=e[j]+h[k]+h[l]-h[m],j++,k++,l++,m++},d.computeIntegralImage=function(a,b){for(var c=a.data,d=a.size.x,e=a.size.y,f=b.data,g=0,h=0;d>h;h++)g+=c[h],f[h]=g;for(var i=1;e>i;i++){g=0;for(var j=0;d>j;j++)g+=c[i*d+j],f[i*d+j]=g+f[(i-1)*d+j]}},d.thresholdImage=function(a,b,c){c||(c=a);for(var d=a.data,e=d.length,f=c.data;e--;)f[e]=d[e]>e]++;return g},d.sharpenLine=function(a){var b,c,d=a.length,e=a[0],f=a[1];for(b=1;d-1>b;b++)c=a[b+1],a[b-1]=2*f-e-c&255,e=f,f=c;return a},d.determineOtsuThreshold=function(a,c){function e(a,b){var c,d=0;for(c=a;b>=c;c++)d+=h[c];return d}function f(a,b){var c,d=0;for(c=a;b>=c;c++)d+=c*h[c];return d}function g(){var g,i,j,k,l,m,n,o=[0],p=(1<k;k++)g=e(0,k),i=e(k+1,p),j=g*i,0===j&&(j=1),l=f(0,k)*i,m=f(k+1,p)*g,n=l-m,o[k]=n*n/j;return b.maxIndex(o)}c||(c=8);var h,i,j=8-c;return i=g(),i<=e;e++)for(f=0;n>f;f++)m[e*n+f]=0,m[(o-1-e)*n+f]=0;for(e=r;o-r>e;e++)for(f=0;r>=f;f++)m[e*n+f]=0,m[e*n+(n-1-f)]=0;for(e=r+1;o-r-1>e;e++)for(f=r+1;n-r>f;f++)g=p[(e-r-1)*n+(f-r-1)],h=p[(e-r-1)*n+(f+r)],i=p[(e+r)*n+(f-r-1)],j=p[(e+r)*n+(f+r)],q=j-i-h+g,k=q/s,m[e*n+f]=l[e*n+f]>k+5?0:1},d.cluster=function(b,c,d){function e(a){var b=!1;for(g=0;gb.x-j&&a.xb.y-k&&a.yd;d++){for(h=Math.floor(Math.random()*a.length),f=[],i=h,f.push(a[i]);null!==(i=c(i,!0));)f.push(a[i]);if(h>0)for(i=h;null!==(i=c(i,!1));)f.push(a[i]);f.length>g.length&&(g=f)}return g}},d.DILATE=1,d.ERODE=2,d.dilate=function(a,b){var c,d,e,f,g,h,i,j=a.data,k=b.data,l=a.size.y,m=a.size.x;for(c=1;l-1>c;c++)for(d=1;m-1>d;d++)f=c-1,g=c+1,h=d-1,i=d+1,e=j[f*m+h]+j[f*m+i]+j[c*m+d]+j[g*m+h]+j[g*m+i],k[c*m+d]=e>0?1:0},d.erode=function(a,b){var c,d,e,f,g,h,i,j=a.data,k=b.data,l=a.size.y,m=a.size.x;for(c=1;l-1>c;c++)for(d=1;m-1>d;d++)f=c-1,g=c+1,h=d-1,i=d+1,e=j[f*m+h]+j[f*m+i]+j[c*m+d]+j[g*m+h]+j[g*m+i],k[c*m+d]=5===e?1:0},d.subtract=function(a,b,c){c||(c=a);for(var d=a.data.length,e=a.data,f=b.data,g=c.data;d--;)g[d]=e[d]-f[d]},d.bitwiseOr=function(a,b,c){c||(c=a);for(var d=a.data.length,e=a.data,f=b.data,g=c.data;d--;)g[d]=e[d]||f[d]},d.countNonZero=function(a){for(var b=a.data.length,c=a.data,d=0;b--;)d+=c[b];return d},d.topGeneric=function(a,b,c){var d,e,f,g,h=0,i=0,j=[];for(d=0;b>d;d++)j[d]={score:0,item:null};for(d=0;di)for(f=j[h],f.score=e,f.item=a[d],i=Number.MAX_VALUE,g=0;b>g;g++)j[g].scoref;){for(d=0;h>d;d++)c[i]=Math.floor((.299*a[4*e+0]+.587*a[4*e+1]+.114*a[4*e+2]+(.299*a[4*(e+1)+0]+.587*a[4*(e+1)+1]+.114*a[4*(e+1)+2])+(.299*a[4*f+0]+.587*a[4*f+1]+.114*a[4*f+2])+(.299*a[4*(f+1)+0]+.587*a[4*(f+1)+1]+.114*a[4*(f+1)+2]))/4),i++,e+=2,f+=2;e+=j,f+=j}},d.computeGray=function(a,b,c){var d,e=a.length/4|0,f=c&&c.singleChannel===!0;if(f)for(d=0;e>d;d++)b[d]=a[4*d+0];else for(d=0;e>d;d++)b[d]=Math.floor(.299*a[4*d+0]+.587*a[4*d+1]+.114*a[4*d+2])},d.loadImageArray=function(a,b,c){c||(c=document.createElement("canvas"));var e=new Image;e.callback=b,e.onload=function(){c.width=this.width,c.height=this.height;var a=c.getContext("2d");a.drawImage(this,0,0);var b=new Uint8Array(this.width*this.height);a.drawImage(this,0,0);var e=a.getImageData(0,0,this.width,this.height).data;d.computeGray(e,b),this.callback(b,{x:this.width,y:this.height},this)},e.src=a},d.halfSample=function(a,b){for(var c=a.data,d=a.size.x,e=b.data,f=0,g=d,h=c.length,i=d/2,j=0;h>g;){for(var k=0;i>k;k++)e[j]=Math.floor((c[f]+c[f+1]+c[g]+c[g+1])/4),j++,f+=2,g+=2;f+=d,g+=d}},d.hsv2rgb=function(a,b){var c=a[0],d=a[1],e=a[2],f=e*d,g=f*(1-Math.abs(c/60%2-1)),h=e-f,i=0,j=0,k=0;return b=b||[0,0,0],60>c?(i=f,j=g):120>c?(i=g,j=f):180>c?(j=f,k=g):240>c?(j=g,k=f):300>c?(i=g,k=f):360>c&&(i=f,k=g),b[0]=255*(i+h)|0,b[1]=255*(j+h)|0,b[2]=255*(k+h)|0,b},d._computeDivisors=function(a){var b,c=[],d=[];for(b=1;bb[d]?d++:c++;return e},d.calculatePatchSize=function(a,b){function c(a){for(var b=0,c=a[Math.floor(a.length/2)];b0&&(c=Math.abs(a[b]-m)>Math.abs(a[b-1]-m)?a[b-1]:a[b]),m/ci[k-1]/i[k]?{x:c,y:c}:null}var d,e=this._computeDivisors(b.x),f=this._computeDivisors(b.y),g=Math.max(b.x,b.y),h=this._computeIntersection(e,f),i=[8,10,15,20,32,60,80],j={"x-small":5,small:4,medium:3,large:2,"x-large":1},k=j[a]||j.medium,l=i[k],m=Math.floor(g/l);return d=c(h),d||(d=c(this._computeDivisors(g)),d||(d=c(this._computeDivisors(m*l)))),d},d._parseCSSDimensionValues=function(a){var b={value:parseFloat(a),unit:a.indexOf("%")===a.length-1?"%":"%"};return b},d._dimensionsConverters={top:function(a,b){return"%"===a.unit?Math.floor(b.height*(a.value/100)):void 0},right:function(a,b){return"%"===a.unit?Math.floor(b.width-b.width*(a.value/100)):void 0},bottom:function(a,b){return"%"===a.unit?Math.floor(b.height-b.height*(a.value/100)):void 0},left:function(a,b){return"%"===a.unit?Math.floor(b.width*(a.value/100)):void 0}},d.computeImageArea=function(a,b,c){var e={width:a,height:b},f=Object.keys(c).reduce(function(a,b){var f=c[b],g=d._parseCSSDimensionValues(f),h=d._dimensionsConverters[b](g,e);return a[b]=h,a},{});return{sx:f.left,sy:f.top,sw:f.right-f.left,sh:f.bottom-f.top}},d}),d("image_wrapper",["subImage","cv_utils","array_helper","gl-matrix"],function(a,b,c,d){"use strict";function e(a,b,d,e){b?this.data=b:d?(this.data=new d(a.x*a.y),d===Array&&e&&c.init(this.data,0)):(this.data=new Uint8Array(a.x*a.y),Uint8Array===Array&&e&&c.init(this.data,0)),this.size=a}var f=d.vec2,g=d.mat2;return e.prototype.inImageWithBorder=function(a,b){return a.x>=b&&a.y>=b&&a.x=0&&u>=0&&n-1>v&&o-1>w){for(i=s,j=0;m>j;++j,f.add(i,y))for(k=0;l>k;++k,f.add(i,p))b.set(k,j,x(a,i[0],i[1]));return 0}var z=n-1,A=o-1,B=0;for(i=s,j=0;m>j;++j,f.add(i,y))for(k=0;l>k;++k,f.add(i,p))0<=i[0]&&0<=i[1]&&i[0]c;c++)for(d=0;e>d;d++)a.data[d*f+c]=this.data[(b.y+d)*this.size.x+b.x+c]},e.prototype.copyTo=function(a){for(var b=this.data.length,c=this.data,d=a.data;b--;)d[b]=c[b]},e.prototype.get=function(a,b){return this.data[b*this.size.x+a]},e.prototype.getSafe=function(a,b){var c;if(!this.indexMapping){for(this.indexMapping={x:[],y:[]},c=0;ca;a++)d[a]=d[(c-1)*b+a]=0;for(a=1;c-1>a;a++)d[a*b]=d[a*b+(b-1)]=0},e.prototype.invert=function(){for(var a=this.data,b=a.length;b--;)a[b]=a[b]?0:1},e.prototype.convolve=function(a){var b,c,d,e,f=a.length/2|0,g=0;for(c=0;c=e;e++)for(d=-f;f>=d;d++)g+=a[e+f][d+f]*this.getSafe(b+d,c+e);this.data[c*this.size.x+b]=g}},e.prototype.moments=function(a){var b,c,d,e,g,h,i,j,k,l,m,n,o=this.data,p=this.size.y,q=this.size.x,r=[],s=[],t=Math.PI,u=t/4;if(0>=a)return s;for(g=0;a>g;g++)r[g]={m00:0,m01:0,m10:0,m11:0,m02:0,m20:0,theta:0,rad:0};for(c=0;p>c;c++)for(e=c*c,b=0;q>b;b++)d=o[c*q+b],d>0&&(h=r[d-1],h.m00+=1,h.m01+=c,h.m10+=b,h.m11+=b*c,h.m02+=e,h.m20+=b*b);for(g=0;a>g;g++)h=r[g],isNaN(h.m00)||0===h.m00||(l=h.m10/h.m00,m=h.m01/h.m00,i=h.m11/h.m00-l*m,j=h.m02/h.m00-m*m,k=h.m20/h.m00-l*l,n=(j-k)/(2*i),n=.5*Math.atan(n)+(i>=0?u:-u)+t,h.theta=(180*n/t+90)%180-90,h.theta<0&&(h.theta+=180),h.rad=n>t?n-t:n,h.vec=f.clone([Math.cos(n),Math.sin(n)]),s.push(h));return s},e.prototype.show=function(a,b){var c,d,e,f,g,h,i;for(b||(b=1),c=a.getContext("2d"),a.width=this.size.x,a.height=this.size.y,d=c.getImageData(0,0,a.width,a.height),e=d.data,f=0,i=0;ic||c>360)&&(c=360);for(var e=[0,1,1],f=[0,0,0],g=[255,255,255],h=[0,0,0],i=[],j=a.getContext("2d"),k=j.getImageData(d.x,d.y,this.size.x,this.size.y),l=k.data,m=this.data.length;m--;)e[0]=this.data[m]*c,i=e[0]<=0?g:e[0]>=360?h:b.hsv2rgb(e,f),l[4*m+0]=i[0],l[4*m+1]=i[1],l[4*m+2]=i[2],l[4*m+3]=255;j.putImageData(k,d.x,d.y)},e}),d("tracer",[],function(){"use strict";var a={searchDirections:[[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1],[-1,0],[-1,1]],create:function(a,b){function c(a,b,c,d){var e,k,l;for(e=0;7>e;e++){if(k=a.cy+i[a.dir][0],l=a.cx+i[a.dir][1],f=k*j+l,g[f]===b&&(0===h[f]||h[f]===c))return h[f]=c,a.cy=k,a.cx=l,!0;0===h[f]&&(h[f]=d),a.dir=(a.dir+1)%8}return!1}function d(a,b,c){return{dir:c,x:a,y:b,next:null,prev:null}}function e(a,b,e,f,g){var h,i,j,k=null,l={cx:b,cy:a,dir:0};if(c(l,f,e,g)){k=d(b,a,l.dir),h=k,j=l.dir,i=d(l.cx,l.cy,0),i.prev=h,h.next=i,i.next=null,h=i;do l.dir=(l.dir+6)%8,c(l,f,e,g),j!=l.dir?(h.dir=l.dir,i=d(l.cx,l.cy,0),i.prev=h,h.next=i,i.next=null,h=i):(h.dir=j,h.x=l.cx,h.y=l.cy),j=l.dir;while(l.cx!=b||l.cy!=a);k.prev=h.prev,h.prev.next=k}return k}var f,g=a.data,h=b.data,i=this.searchDirections,j=a.size.x;return{trace:function(a,b,d,e){return c(a,b,d,e)},contourTracing:function(a,b,c,d,f){return e(a,b,c,d,f)}}}};return a}),d("rasterizer",["tracer"],function(a){"use strict";var b={createContour2D:function(){return{dir:null,index:null,firstVertex:null,insideContours:null,nextpeer:null,prevpeer:null}},CONTOUR_DIR:{CW_DIR:0,CCW_DIR:1,UNKNOWN_DIR:2},DIR:{OUTSIDE_EDGE:-32767,INSIDE_EDGE:-32766},create:function(c,d){var e=c.data,f=d.data,g=c.size.x,h=c.size.y,i=a.create(c,d);return{rasterize:function(a){var c,d,j,k,l,m,n,o,p,q,r,s,t=[],u=0;for(s=0;400>s;s++)t[s]=0;for(t[0]=e[0],p=null,m=1;h-1>m;m++)for(k=0,d=t[0],l=1;g-1>l;l++)if(r=m*g+l,0===f[r])if(c=e[r],c!==d){if(0===k)j=u+1,t[j]=c,d=c,n=i.contourTracing(m,l,j,c,b.DIR.OUTSIDE_EDGE),null!==n&&(u++,k=j,o=b.createContour2D(),o.dir=b.CONTOUR_DIR.CW_DIR,o.index=k,o.firstVertex=n,o.nextpeer=p,o.insideContours=null,null!==p&&(p.prevpeer=o),p=o);else if(n=i.contourTracing(m,l,b.DIR.INSIDE_EDGE,c,k),null!==n){for(o=b.createContour2D(),o.firstVertex=n,o.insideContours=null,o.dir=0===a?b.CONTOUR_DIR.CCW_DIR:b.CONTOUR_DIR.CW_DIR,o.index=a,q=p;null!==q&&q.index!==k;)q=q.nextpeer;null!==q&&(o.nextpeer=q.insideContours,null!==q.insideContours&&(q.insideContours.prevpeer=o),q.insideContours=o)}}else f[r]=k;else f[r]===b.DIR.OUTSIDE_EDGE||f[r]===b.DIR.INSIDE_EDGE?(k=0,d=f[r]===b.DIR.INSIDE_EDGE?e[r]:t[0]):(k=f[r],d=t[k]);for(q=p;null!==q;)q.index=a,q=q.nextpeer;return{cc:p,count:u}},debug:{drawContour:function(a,c){var d,e,f,g=a.getContext("2d"),h=c;for(g.strokeStyle="red",g.fillStyle="red",g.lineWidth=1,d=null!==h?h.insideContours:null;null!==h;){switch(null!==d?(e=d,d=d.nextpeer):(e=h,h=h.nextpeer,d=null!==h?h.insideContours:null),e.dir){case b.CONTOUR_DIR.CW_DIR:g.strokeStyle="red";break;case b.CONTOUR_DIR.CCW_DIR:g.strokeStyle="blue";break;case b.CONTOUR_DIR.UNKNOWN_DIR:g.strokeStyle="green"}f=e.firstVertex,g.beginPath(),g.moveTo(f.x,f.y);do f=f.next,g.lineTo(f.x,f.y);while(f!==e.firstVertex);g.stroke()}}}}}};return b}),d("skeletonizer",[],function(){"use strict";function a(stdlib, foreign, buffer) {"use asm";var images=new stdlib.Uint8Array(buffer),size=foreign.size|0,imul=stdlib.Math.imul;function erode(inImagePtr, outImagePtr) {inImagePtr=inImagePtr|0;outImagePtr=outImagePtr|0;var v=0,u=0,sum=0,yStart1=0,yStart2=0,xStart1=0,xStart2=0,offset=0;for ( v=1; (v|0)<((size - 1)|0); v=(v+1)|0) {offset=(offset+size)|0;for ( u=1; (u|0)<((size - 1)|0); u=(u+1)|0) {yStart1=(offset - size)|0;yStart2=(offset+size)|0;xStart1=(u - 1)|0;xStart2=(u+1)|0;sum=((images[(inImagePtr+yStart1+xStart1)|0]|0)+(images[(inImagePtr+yStart1+xStart2)|0]|0)+(images[(inImagePtr+offset+u)|0]|0)+(images[(inImagePtr+yStart2+xStart1)|0]|0)+(images[(inImagePtr+yStart2+xStart2)|0]|0))|0;if ((sum|0) == (5|0)) {images[(outImagePtr+offset+u)|0]=1;} else {images[(outImagePtr+offset+u)|0]=0;}}}return;}function subtract(aImagePtr, bImagePtr, outImagePtr) {aImagePtr=aImagePtr|0;bImagePtr=bImagePtr|0;outImagePtr=outImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(outImagePtr+length)|0]=((images[(aImagePtr+length)|0]|0) - (images[(bImagePtr+length)|0]|0))|0;}}function bitwiseOr(aImagePtr, bImagePtr, outImagePtr) {aImagePtr=aImagePtr|0;bImagePtr=bImagePtr|0;outImagePtr=outImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(outImagePtr+length)|0]=((images[(aImagePtr+length)|0]|0)|(images[(bImagePtr+length)|0]|0))|0;}}function countNonZero(imagePtr) {imagePtr=imagePtr|0;var sum=0,length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;sum=((sum|0)+(images[(imagePtr+length)|0]|0))|0;}return (sum|0);}function init(imagePtr, value) {imagePtr=imagePtr|0;value=value|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(imagePtr+length)|0]=value;}}function dilate(inImagePtr, outImagePtr) {inImagePtr=inImagePtr|0;outImagePtr=outImagePtr|0;var v=0,u=0,sum=0,yStart1=0,yStart2=0,xStart1=0,xStart2=0,offset=0;for ( v=1; (v|0)<((size - 1)|0); v=(v+1)|0) {offset=(offset+size)|0;for ( u=1; (u|0)<((size - 1)|0); u=(u+1)|0) {yStart1=(offset - size)|0;yStart2=(offset+size)|0;xStart1=(u - 1)|0;xStart2=(u+1)|0;sum=((images[(inImagePtr+yStart1+xStart1)|0]|0)+(images[(inImagePtr+yStart1+xStart2)|0]|0)+(images[(inImagePtr+offset+u)|0]|0)+(images[(inImagePtr+yStart2+xStart1)|0]|0)+(images[(inImagePtr+yStart2+xStart2)|0]|0))|0;if ((sum|0)>(0|0)) {images[(outImagePtr+offset+u)|0]=1;} else {images[(outImagePtr+offset+u)|0]=0;}}}return;}function memcpy(srcImagePtr, dstImagePtr) {srcImagePtr=srcImagePtr|0;dstImagePtr=dstImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(dstImagePtr+length)|0]=(images[(srcImagePtr+length)|0]|0);}}function zeroBorder(imagePtr) {imagePtr=imagePtr|0;var x=0,y=0;for ( x=0; (x|0)<((size - 1)|0); x=(x+1)|0) {images[(imagePtr+x)|0]=0;images[(imagePtr+y)|0]=0;y=((y+size) - 1)|0;images[(imagePtr+y)|0]=0;y=(y+1)|0;}for ( x=0; (x|0)<(size|0); x=(x+1)|0) {images[(imagePtr+y)|0]=0;y=(y+1)|0;}}function skeletonize() {var subImagePtr=0,erodedImagePtr=0,tempImagePtr=0,skelImagePtr=0,sum=0,done=0;erodedImagePtr=imul(size, size)|0;tempImagePtr=(erodedImagePtr+erodedImagePtr)|0;skelImagePtr=(tempImagePtr+erodedImagePtr)|0;init(skelImagePtr, 0);zeroBorder(subImagePtr);do {erode(subImagePtr, erodedImagePtr);dilate(erodedImagePtr, tempImagePtr);subtract(subImagePtr, tempImagePtr, tempImagePtr);bitwiseOr(skelImagePtr, tempImagePtr, skelImagePtr);memcpy(erodedImagePtr, subImagePtr);sum=countNonZero(subImagePtr)|0;done=((sum|0) == 0|0);} while(!done);}return {skeletonize : skeletonize};}
-return Math.imul=Math.imul||function(a,b){var c=a>>>16&65535,d=65535&a,e=b>>>16&65535,f=65535&b;return d*f+(c*f+d*e<<16>>>0)|0},a}),d("image_debug",[],function(){"use strict";return{drawRect:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=1,c.beginPath(),c.strokeRect(a.x,a.y,b.x,b.y)},drawPath:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=d.lineWidth,c.beginPath(),c.moveTo(a[0][b.x],a[0][b.y]);for(var e=1;eb&&(b+=180),b=(180-b)*Math.PI/180,f=I.clone([Math.cos(b),Math.sin(b),-Math.sin(b),Math.cos(b)]),c=0;cd;d++)H.transformMat2(e.box[d],e.box[d],f);t.boxFromPatches.showTransformed&&g.drawPath(e.box,{x:0,y:1},F.ctx.binary,{color:"#99ff00",lineWidth:2})}for(c=0;cd;d++)e.box[d][0]l&&(l=e.box[d][0]),e.box[d][1]m&&(m=e.box[d][1]);for(h=[[j,k],[l,k],[l,m],[j,m]],t.boxFromPatches.showTransformedBox&&g.drawPath(h,{x:0,y:1},F.ctx.binary,{color:"#ff0000",lineWidth:2}),i=t.halfSample?2:1,f=I.invert(f,f),d=0;4>d;d++)H.transformMat2(h[d],h[d],f);for(t.boxFromPatches.showBB&&g.drawPath(h,{x:0,y:1},F.ctx.binary,{color:"#ff0000",lineWidth:2}),d=0;4>d;d++)H.scale(h[d],h[d],i);return h}function l(){b.otsuThreshold(u,B),B.zeroBorder(),t.showCanvas&&B.show(F.dom.binary,255)}function m(){var a,b,d,e,h,i,j,k,l=[];for(a=0;ab;b++)d.push(0);for(c=z.data.length;c--;)z.data[c]>0&&d[z.data[c]-1]++;return d=d.map(function(a,b){return{val:a,label:b+1}}),d.sort(function(a,b){return b.val-a.val}),e=d.filter(function(a){return a.val>=5})}function o(a,c){var d,e,f,h,i,j=[],l=[],m=[0,1,1],n=[0,0,0];for(d=0;d=2){for(e=0;el&&j.push(a[e]);if(j.length>=2){for(i=j.length,g=p(j),f=0,e=0;e1&&g.length>=j.length/4*3&&g.length>a.length/4&&(f/=g.length,h={index:b[1]*G.x+b[0],pos:{x:c,y:d},box:[H.clone([c,d]),H.clone([c+w.size.x,d]),H.clone([c+w.size.x,d+w.size.y]),H.clone([c,d+w.size.y])],moments:g,rad:f,vec:H.clone([Math.cos(f),Math.sin(f)])},k.push(h))}}return k}function s(a){function c(){var a;for(a=0;ak&&e(h))):z.data[h]=Number.MAX_VALUE}var h,i,j=0,k=.95,l=0,m=[0,1,1],n=[0,0,0];for(f.init(y.data,0),f.init(z.data,0),f.init(A.data,null),h=0;h0&&z.data[h]<=j&&(i=A.data[h],m[0]=z.data[h]/(j+1)*360,b.hsv2rgb(m,n),g.drawRect(i.pos,w.size,F.ctx.binary,{color:"rgb("+n.join(",")+")",lineWidth:2}));return j}var t,u,v,w,x,y,z,A,B,C,D,E,F={ctx:{binary:null},dom:{binary:null}},G={x:0,y:0},H=h.vec2,I=h.mat2,J=this;return{init:function(a,b){t=b,D=a,i(),j()},locate:function(){var a,c,d;if(t.halfSample&&b.halfSample(D,u),l(),a=m(),a.lengthe?null:(c=n(e),0===c.length?null:d=o(c,e))},checkImageConstraints:function(a,c){var d,e,f,g=a.getWidth(),h=a.getHeight(),i=c.halfSample?.5:1;if(a.getConfig().area&&(f=b.computeImageArea(g,h,a.getConfig().area),a.setTopRight({x:f.sx,y:f.sy}),a.setCanvasSize({x:g,y:h}),g=f.sw,h=f.sh),e={x:Math.floor(g*i),y:Math.floor(h*i)},d=b.calculatePatchSize(c.patchSize,e),console.log("Patch-Size: "+JSON.stringify(d)),a.setWidth(Math.floor(Math.floor(e.x/d.x)*(1/i)*d.x)),a.setHeight(Math.floor(Math.floor(e.y/d.y)*(1/i)*d.y)),a.getWidth()%d.x===0&&a.getHeight()%d.y===0)return!0;throw new Error("Image dimensions do not comply with the current settings: Width ("+g+" )and height ("+h+") must a multiple of "+d.x)}}}),d("bresenham",["cv_utils","image_wrapper"],function(a,b){"use strict";var c={},d={DIR:{UP:1,DOWN:-1}};return c.getBarcodeLine=function(a,b,c){function d(a,b){l=s[b*t+a],u+=l,v=v>l?l:v,w=l>w?l:w,r.push(l)}var e,f,g,h,i,j,k,l,m=0|b.x,n=0|b.y,o=0|c.x,p=0|c.y,q=Math.abs(p-n)>Math.abs(o-m),r=[],s=a.data,t=a.size.x,u=0,v=255,w=0;for(q&&(j=m,m=n,n=j,j=o,o=p,p=j),m>o&&(j=m,m=o,o=j,j=n,n=p,p=j),e=o-m,f=Math.abs(p-n),g=e/2|0,i=n,h=p>n?1:-1,k=m;o>k;k++)q?d(i,k):d(k,i),g-=f,0>g&&(i+=h,g+=e);return{line:r,min:v,max:w}},c.toOtsuBinaryLine=function(c){var d=c.line,e=new b({x:d.length-1,y:1},d),f=a.determineOtsuThreshold(e,5);return d=a.sharpenLine(d),a.thresholdImage(e,f),{line:d,threshold:f}},c.toBinaryLine=function(a){var b,c,e,f,g,h,i=a.min,j=a.max,k=a.line,l=i+(j-i)/2,m=[],n=(j-i)/12,o=-n;for(e=k[0]>l?d.DIR.UP:d.DIR.DOWN,m.push({pos:0,val:k[0]}),g=0;gb+c&&k[g+1]<1.5*l?d.DIR.DOWN:b+c>n&&k[g+1]>.5*l?d.DIR.UP:e,e!==f&&(m.push({pos:g,val:k[g]}),e=f);for(m.push({pos:k.length,val:k[k.length-1]}),h=m[0].pos;hl?0:1;for(g=1;gm[g].val?m[g].val+(m[g+1].val-m[g].val)/3*2|0:m[g+1].val+(m[g].val-m[g+1].val)/3|0,h=m[g].pos;hn?0:1;return{line:k,threshold:n}},c.debug={printFrequency:function(a,b){var c,d=b.getContext("2d");for(b.width=a.length,b.height=256,d.beginPath(),d.strokeStyle="blue",c=0;cd;d++)if(e._row[d]^h)c[i]++;else{if(i++,i===f)break;c[i]=1,h=!h}return c},c.prototype._decode=function(){var a,c,d,e,f=this,g=[0,0,0,0,0,0,0,0,0],h=[],i=f._findStart();if(!i)return null;e=f._nextSet(f._row,i.end);do{if(g=f._toCounters(e,g),d=f._toPattern(g),0>d)return null;if(a=f._patternToChar(d),0>a)return null;h.push(a),c=e,e+=b.sum(g),e=f._nextSet(f._row,e)}while("*"!==a);return h.pop(),h.length&&f._verifyTrailingWhitespace(c,e,g)?{code:h.join(""),start:i.start,end:e,startInfo:i,decodedCodes:h}:null},c.prototype._verifyTrailingWhitespace=function(a,c,d){var e,f=b.sum(d);return e=c-a-f,3*e>=f?!0:!1},c.prototype._patternToChar=function(a){var b,c=this;for(b=0;bb&&(d=a[c]);return d},c.prototype._toPattern=function(a){for(var b,c,d=a.length,e=0,f=d,g=0,h=this;f>3;){for(e=h._findNextWidth(a,e),f=0,b=0,c=0;d>c;c++)a[c]>e&&(b|=1<c&&f>0;c++)if(a[c]>e&&(f--,2*a[c]>=g))return-1;return b}}return-1},c.prototype._findStart=function(){var a,b,c,d=this,e=d._nextSet(d._row),f=e,g=[0,0,0,0,0,0,0,0,0],h=0,i=!1;for(a=e;ab;b++)g[b]=g[b+2];g[7]=0,g[8]=0,h--}else h++;g[h]=1,i=!i}return null},c}),d("code_39_vin_reader",["./code_39_reader"],function(a){"use strict";function b(){a.call(this)}var c={IOQ:/[IOQ]/g,AZ09:/[A-Z0-9]{17}/};return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b.prototype._decode=function(){var b=a.prototype._decode.apply(this);if(!b)return null;var d=b.code;if(d)return d=d.replace(c.IOQ,""),d.match(c.AZ09)?this._checkChecksum(d)?(b.code=d,b):null:(console.log("Failed AZ09 pattern code:",d),null)},b.prototype._checkChecksum=function(a){return!!a},b}),d("codabar_reader",["./barcode_reader"],function(a){"use strict";function b(){a.call(this),this._counters=[]}var c={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:[3,6,9,96,18,66,33,36,48,72,12,24,69,81,84,21,26,41,11,14]},START_END:{value:[26,41,11,14]},MIN_ENCODED_CHARS:{value:4},MAX_ACCEPTABLE:{value:2},PADDING:{value:1.5},FORMAT:{value:"codabar",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decode=function(){var a,b,c,d,e,f=this,g=[];if(f._fillCounters(),a=f._findStart(),!a)return null;d=a.startCounter;do{if(c=f._toPattern(d),0>c)return null;if(b=f._patternToChar(c),0>b)return null;if(g.push(b),d+=8,g.length>1&&f._isStartEnd(c))break}while(df._counters.length?f._counters.length:d,e=a.start+f._sumCounters(a.startCounter,d-8),{code:g.join(""),start:a.start,end:e,startInfo:a,decodedCodes:g}):null},b.prototype._verifyWhitespace=function(a,b){return(0>=a-1||this._counters[a-1]>=this._calculatePatternLength(a)/2)&&(b+8>=this._counters.length||this._counters[b+7]>=this._calculatePatternLength(b)/2)?!0:!1},b.prototype._calculatePatternLength=function(a){var b,c=0;for(b=a;a+7>b;b++)c+=this._counters[b];return c},b.prototype._thresholdResultPattern=function(a,b){var c,d,e,f,g,h=this,i={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}}},j=b;for(e=0;e=0;f--)c=2===(1&f)?i.bar:i.space,d=1===(1&g)?c.wide:c.narrow,d.size+=h._counters[j+f],d.counts++,g>>=1;j+=8}return["space","bar"].forEach(function(a){var b=i[a];b.wide.min=Math.floor((b.narrow.size/b.narrow.counts+b.wide.size/b.wide.counts)/2),b.narrow.max=Math.ceil(b.wide.min),b.wide.max=Math.ceil((b.wide.size*h.MAX_ACCEPTABLE+h.PADDING)/b.wide.counts)}),i},b.prototype._charToPattern=function(a){var b,c=this,d=a.charCodeAt(0);for(b=0;b=0;d--){if(e=0===(1&d)?j.bar:j.space,f=1===(1&h)?e.wide:e.narrow,g=i._counters[k+d],gf.max)return!1;h>>=1}k+=8}return!0},b.prototype._fillCounters=function(){var a,b=this,c=0,d=!0,e=b._nextUnset(b._row);for(b._counters.length=0,b._counters[c]=0,a=e;ac;c+=2)d=this._counters[c],d>f&&(f=d),e>d&&(e=d);return(e+f)/2|0},b.prototype._toPattern=function(a){var b,c,d,e,f=7,g=a+f,h=1<this._counters.length)return-1;for(b=this._computeAlternatingThreshold(a,g),c=this._computeAlternatingThreshold(a+1,g),d=0;f>d;d++)e=0===(1&d)?b:c,this._counters[a+d]>e&&(i|=h),h>>=1;return i},b.prototype._isStartEnd=function(a){var b;for(b=0;bc;c++)d+=this._counters[c];return d},b.prototype._findStart=function(){var a,b,c,d=this,e=d._nextUnset(d._row);for(a=1;ad;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;b.push(a.code),c.push(a)}if(a=e._findPattern(e.MIDDLE_PATTERN,a.end,!0,!1),null===a)return null;for(c.push(a),d=0;4>d;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;c.push(a),b.push(a.code)}return a},b}),d("upc_e_reader",["./ean_reader"],function(a){"use strict";function b(){a.call(this)}var c={CODE_FREQUENCY:{value:[[56,52,50,49,44,38,35,42,41,37],[7,11,13,14,19,25,28,21,22,26]]},STOP_PATTERN:{value:[1/6*7,1/6*7,1/6*7,1/6*7,1/6*7,1/6*7]},FORMAT:{value:"upc_e",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodePayload=function(a,b,c){var d,e=this,f=0;for(d=0;6>d;d++){if(a=e._decodeCode(a.end),!a)return null;a.code>=e.CODE_G_START&&(a.code=a.code-e.CODE_G_START,f|=1<<5-d),b.push(a.code),c.push(a)}return e._determineParity(f,b)?a:null},b.prototype._determineParity=function(a,b){var c,d,e=this;for(d=0;d=c?b.concat(a.slice(1,3)).concat([c,0,0,0,0]).concat(a.slice(3,6)):3===c?b.concat(a.slice(1,4)).concat([0,0,0,0,0]).concat(a.slice(4,6)):4===c?b.concat(a.slice(1,5)).concat([0,0,0,0,0,a[5]]):b.concat(a.slice(1,6)).concat([0,0,0,0,c]),b.push(a[a.length-1]),b},b.prototype._checksum=function(b){return a.prototype._checksum.call(this,this._convertToUPCA(b))},b.prototype._findEnd=function(b,c){return c=!0,a.prototype._findEnd.call(this,b,c)},b.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,b1&&(!d.inImageWithBorder(a[0],0)||!d.inImageWithBorder(a[1],0));)c-=Math.ceil(c/2),e(-c);return a}function i(a){return[{x:(a[1][0]-a[0][0])/2+a[0][0],y:(a[1][1]-a[0][1])/2+a[0][1]},{x:(a[3][0]-a[2][0])/2+a[2][0],y:(a[3][1]-a[2][1])/2+a[2][1]}]}function j(e){var f,g=null,h=a.getBarcodeLine(d,e[0],e[1]);for(c.showFrequency&&(b.drawPath(e,{x:"x",y:"y"},o.ctx.overlay,{color:"red",lineWidth:3}),a.debug.printFrequency(h.line,o.dom.frequency)),a.toBinaryLine(h),c.showPattern&&a.debug.printPattern(h.line,o.dom.pattern),f=0;fd&&null===i;d++)e=g/h*d*(d%2===0?-1:1),f={y:e*k,x:e*l},b[0].y+=f.x,b[0].x-=f.y,b[1].y+=f.x,b[1].x-=f.y,i=j(b);return i}function m(a){return Math.sqrt(Math.pow(Math.abs(a[1].y-a[0].y),2)+Math.pow(Math.abs(a[1].x-a[0].x),2))}function n(a){var d,e,f,g,k=o.ctx.overlay;return c.drawBoundingBox&&k&&b.drawPath(a,{x:0,y:1},k,{color:"blue",lineWidth:2}),d=i(a),g=m(d),e=Math.atan2(d[1].y-d[0].y,d[1].x-d[0].x),d=h(d,e,Math.floor(.1*g)),null===d?null:(f=j(d),null===f&&(f=l(a,d,e)),null===f?null:(f&&c.drawScanline&&k&&b.drawPath(d,{x:"x",y:"y"},k,{color:"red",lineWidth:3}),{codeResult:f.codeResult,line:d,angle:e,pattern:f.barcodeLine.line,threshold:f.barcodeLine.threshold}))}var o={ctx:{frequency:null,pattern:null,overlay:null},dom:{frequency:null,pattern:null,overlay:null}},p=[];return e(),f(),g(),{decodeFromBoundingBox:function(a){return n(a)},decodeFromBoundingBoxes:function(a){var b,c;for(b=0;b0?a.videoWidth>0&&a.videoHeight>0?(console.log(a.videoWidth+"px x "+a.videoHeight+"px"),b()):window.setTimeout(c,500):b("Unable to play video stream. Is webcam working?"),d--}var d=10;c()}function d(a,d,e){b(a,function(a){d.src=a,h&&d.removeEventListener("loadeddata",h,!1),h=c.bind(null,d,e),d.addEventListener("loadeddata",h,!1),d.play()},function(a){e(a)})}function e(b,c){var d={audio:!1,video:!0},e=a.mergeObjects({width:640,height:480,minAspectRatio:0,maxAspectRatio:100,facing:"environment"},b);return"undefined"==typeof MediaStreamTrack||"undefined"==typeof MediaStreamTrack.getSources?(d.video={mediaSource:"camera",width:{min:e.width,max:e.width},height:{min:e.height,max:e.height},require:["width","height"]},c(d)):void MediaStreamTrack.getSources(function(a){for(var b,f=0;f!=a.length;++f){var g=a[f];"video"==g.kind&&g.facing==e.facing&&(b=g.id)}return d.video={mandatory:{minWidth:e.width,minHeight:e.height,minAspectRatio:e.minAspectRatio,maxAspectRatio:e.maxAspectRatio},optional:[{sourceId:b}]},c(d)})}function f(a,b,c){e(b,function(b){d(b,a,c)})}var g,h;return{request:function(a,b,c){f(a,b,c)},release:function(){var a=g&&g.getVideoTracks();a.length&&a[0].stop(),g=null}}}),d("result_collector",["image_debug"],function(a){"use strict";function b(a,b){return b?b.some(function(b){return Object.keys(b).every(function(c){return b[c]===a[c]})}):!1}function c(a,b){return"function"==typeof b?b(a):!0}return{create:function(d){function e(a){return i&&a&&!b(a,d.blacklist)&&c(a,d.filter)}var f=document.createElement("canvas"),g=f.getContext("2d"),h=[],i=d.capacity||20,j=d.capture===!0;return{addResult:function(b,c,d){var k={};e(d)&&(i--,k.codeResult=d,j&&(f.width=c.x,f.height=c.y,a.drawImage(b,c,g),k.frame=f.toDataURL()),h.push(k))},getResults:function(){return h}}}}}),d("quagga",["code_128_reader","ean_reader","input_stream","image_wrapper","barcode_locator","barcode_decoder","frame_grabber","html_utils","config","events","camera_access","image_debug","gl-matrix","result_collector"],function(b,c,d,e,f,g,h,i,j,k,l,m,n,o){"use strict";function p(a){v(a),M=g.create(j.decoder,K)}function q(){if("undefined"!=typeof document)for(var a=[{node:document.querySelector("div[data-controls]"),prop:j.controls},{node:O.dom.overlay,prop:j.visual.show}],b=0;b0?C(function(){console.log("Workers created"),t(a)}):(p(),t(a))}function t(a){H.play(),a()}function u(){if("undefined"!=typeof document){var a=document.querySelector("#interactive.viewport");if(O.dom.image=document.querySelector("canvas.imgBuffer"),O.dom.image||(O.dom.image=document.createElement("canvas"),O.dom.image.className="imgBuffer",a&&"ImageStream"==j.inputStream.type&&a.appendChild(O.dom.image)),O.ctx.image=O.dom.image.getContext("2d"),O.dom.image.width=H.getCanvasSize().x,O.dom.image.height=H.getCanvasSize().y,O.dom.overlay=document.querySelector("canvas.drawingBuffer"),!O.dom.overlay){O.dom.overlay=document.createElement("canvas"),O.dom.overlay.className="drawingBuffer",a&&a.appendChild(O.dom.overlay);var b=document.createElement("br");b.setAttribute("clear","all"),a&&a.appendChild(b)}O.ctx.overlay=O.dom.overlay.getContext("2d"),O.dom.overlay.width=H.getCanvasSize().x,O.dom.overlay.height=H.getCanvasSize().y}}function v(a){K=a?a:new e({x:H.getWidth(),y:H.getHeight()}),console.log(K.size),L=[R.clone([0,0]),R.clone([0,K.size.y]),R.clone([K.size.x,K.size.y]),R.clone([K.size.x,0])],f.init(K,j.locator)}function w(){return j.locate?f.locate():[[R.clone(L[0]),R.clone(L[1]),R.clone(L[2]),R.clone(L[3])]]}function x(a){function b(a){for(var b=a.length;b--;)a[b][0]+=f,a[b][1]+=g}function c(a){a[0].x+=f,a[0].y+=g,a[1].x+=f,a[1].y+=g}var d,e=H.getTopRight(),f=e.x,g=e.y;if(a&&(0!==f||0!==g)&&(a.line&&2===a.line.length&&c(a.line),a.boxes&&a.boxes.length>0))for(d=0;d0){if(a=P.filter(function(a){return!a.busy})[0],!a)return;I.attachData(a.imageData)}else I.attachData(K.data);I.grab()&&(a?(a.busy=!0,a.worker.postMessage({cmd:"process",imageData:a.imageData},[a.imageData.buffer])):z())}else z()}function B(){J=!1,function a(){J||(A(),Q&&"LiveStream"==j.inputStream.type&&window.requestAnimFrame(a))}()}function C(a){function b(b){P.push(b),P.length>=j.numOfWorkers&&a()}var c;for(P=[],c=0;c0&&P.forEach(function(b){b.worker.postMessage({cmd:"setReaders",readers:a})})}var H,I,J,K,L,M,N,O={ctx:{image:null,overlay:null},dom:{image:null,overlay:null}},P=[],Q=!0,R=n.vec2;return{init:function(a,b,c){return j=i.mergeObjects(j,a),c?(Q=!1,p(c),b()):void r(b)},start:function(){B()},stop:function(){J=!0,P.forEach(function(a){a.worker.terminate(),console.log("Worker terminated!")}),P.length=0,"LiveStream"===j.inputStream.type&&(l.release(),H.clearEventHandlers())},pause:function(){J=!0},onDetected:function(a){k.subscribe("detected",a)},onProcessed:function(a){k.subscribe("processed",a)},setReaders:function(a){G(a)},registerResultCollector:function(a){a&&"function"==typeof a.addResult&&(N=a)},canvas:O,decodeSingle:function(a,b){a=i.mergeObjects({inputStream:{type:"ImageStream",sequence:!1,size:800,src:a.src},numOfWorkers:1,locator:{halfSample:!1}},a),this.init(a,function(){k.once("processed",function(a){J=!0,b.call(null,a)},!0),B()})},Reader:{EANReader:c,Code128Reader:b},ImageWrapper:e,ImageDebug:m,ResultCollector:o}}),c("quagga")});
\ No newline at end of file
+return Math.imul=Math.imul||function(a,b){var c=a>>>16&65535,d=65535&a,e=b>>>16&65535,f=65535&b;return d*f+(c*f+d*e<<16>>>0)|0},a}),d("image_debug",[],function(){"use strict";return{drawRect:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=1,c.beginPath(),c.strokeRect(a.x,a.y,b.x,b.y)},drawPath:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=d.lineWidth,c.beginPath(),c.moveTo(a[0][b.x],a[0][b.y]);for(var e=1;eb&&(b+=180),b=(180-b)*Math.PI/180,f=I.clone([Math.cos(b),Math.sin(b),-Math.sin(b),Math.cos(b)]),c=0;cd;d++)H.transformMat2(e.box[d],e.box[d],f);t.boxFromPatches.showTransformed&&g.drawPath(e.box,{x:0,y:1},F.ctx.binary,{color:"#99ff00",lineWidth:2})}for(c=0;cd;d++)e.box[d][0]l&&(l=e.box[d][0]),e.box[d][1]m&&(m=e.box[d][1]);for(h=[[j,k],[l,k],[l,m],[j,m]],t.boxFromPatches.showTransformedBox&&g.drawPath(h,{x:0,y:1},F.ctx.binary,{color:"#ff0000",lineWidth:2}),i=t.halfSample?2:1,f=I.invert(f,f),d=0;4>d;d++)H.transformMat2(h[d],h[d],f);for(t.boxFromPatches.showBB&&g.drawPath(h,{x:0,y:1},F.ctx.binary,{color:"#ff0000",lineWidth:2}),d=0;4>d;d++)H.scale(h[d],h[d],i);return h}function l(){b.otsuThreshold(u,B),B.zeroBorder(),t.showCanvas&&B.show(F.dom.binary,255)}function m(){var a,b,d,e,h,i,j,k,l=[];for(a=0;ab;b++)d.push(0);for(c=z.data.length;c--;)z.data[c]>0&&d[z.data[c]-1]++;return d=d.map(function(a,b){return{val:a,label:b+1}}),d.sort(function(a,b){return b.val-a.val}),e=d.filter(function(a){return a.val>=5})}function o(a,c){var d,e,f,h,i,j=[],l=[],m=[0,1,1],n=[0,0,0];for(d=0;d=2){for(e=0;el&&j.push(a[e]);if(j.length>=2){for(i=j.length,g=p(j),f=0,e=0;e1&&g.length>=j.length/4*3&&g.length>a.length/4&&(f/=g.length,h={index:b[1]*G.x+b[0],pos:{x:c,y:d},box:[H.clone([c,d]),H.clone([c+w.size.x,d]),H.clone([c+w.size.x,d+w.size.y]),H.clone([c,d+w.size.y])],moments:g,rad:f,vec:H.clone([Math.cos(f),Math.sin(f)])},k.push(h))}}return k}function s(a){function c(){var a;for(a=0;ak&&e(h))):z.data[h]=Number.MAX_VALUE}var h,i,j=0,k=.95,l=0,m=[0,1,1],n=[0,0,0];for(f.init(y.data,0),f.init(z.data,0),f.init(A.data,null),h=0;h0&&z.data[h]<=j&&(i=A.data[h],m[0]=z.data[h]/(j+1)*360,b.hsv2rgb(m,n),g.drawRect(i.pos,w.size,F.ctx.binary,{color:"rgb("+n.join(",")+")",lineWidth:2}));return j}var t,u,v,w,x,y,z,A,B,C,D,E,F={ctx:{binary:null},dom:{binary:null}},G={x:0,y:0},H=h.vec2,I=h.mat2,J=this;return{init:function(a,b){t=b,D=a,i(),j()},locate:function(){var a,c,d;if(t.halfSample&&b.halfSample(D,u),l(),a=m(),a.lengthe?null:(c=n(e),0===c.length?null:d=o(c,e))},checkImageConstraints:function(a,c){var d,e,f,g=a.getWidth(),h=a.getHeight(),i=c.halfSample?.5:1;if(a.getConfig().area&&(f=b.computeImageArea(g,h,a.getConfig().area),a.setTopRight({x:f.sx,y:f.sy}),a.setCanvasSize({x:g,y:h}),g=f.sw,h=f.sh),e={x:Math.floor(g*i),y:Math.floor(h*i)},d=b.calculatePatchSize(c.patchSize,e),console.log("Patch-Size: "+JSON.stringify(d)),a.setWidth(Math.floor(Math.floor(e.x/d.x)*(1/i)*d.x)),a.setHeight(Math.floor(Math.floor(e.y/d.y)*(1/i)*d.y)),a.getWidth()%d.x===0&&a.getHeight()%d.y===0)return!0;throw new Error("Image dimensions do not comply with the current settings: Width ("+g+" )and height ("+h+") must a multiple of "+d.x)}}}),d("bresenham",["cv_utils","image_wrapper"],function(a,b){"use strict";var c={},d={DIR:{UP:1,DOWN:-1}};return c.getBarcodeLine=function(a,b,c){function d(a,b){l=s[b*t+a],u+=l,v=v>l?l:v,w=l>w?l:w,r.push(l)}var e,f,g,h,i,j,k,l,m=0|b.x,n=0|b.y,o=0|c.x,p=0|c.y,q=Math.abs(p-n)>Math.abs(o-m),r=[],s=a.data,t=a.size.x,u=0,v=255,w=0;for(q&&(j=m,m=n,n=j,j=o,o=p,p=j),m>o&&(j=m,m=o,o=j,j=n,n=p,p=j),e=o-m,f=Math.abs(p-n),g=e/2|0,i=n,h=p>n?1:-1,k=m;o>k;k++)q?d(i,k):d(k,i),g-=f,0>g&&(i+=h,g+=e);return{line:r,min:v,max:w}},c.toOtsuBinaryLine=function(c){var d=c.line,e=new b({x:d.length-1,y:1},d),f=a.determineOtsuThreshold(e,5);return d=a.sharpenLine(d),a.thresholdImage(e,f),{line:d,threshold:f}},c.toBinaryLine=function(a){var b,c,e,f,g,h,i=a.min,j=a.max,k=a.line,l=i+(j-i)/2,m=[],n=(j-i)/12,o=-n;for(e=k[0]>l?d.DIR.UP:d.DIR.DOWN,m.push({pos:0,val:k[0]}),g=0;gb+c&&k[g+1]<1.5*l?d.DIR.DOWN:b+c>n&&k[g+1]>.5*l?d.DIR.UP:e,e!==f&&(m.push({pos:g,val:k[g]}),e=f);for(m.push({pos:k.length,val:k[k.length-1]}),h=m[0].pos;hl?0:1;for(g=1;gm[g].val?m[g].val+(m[g+1].val-m[g].val)/3*2|0:m[g+1].val+(m[g].val-m[g+1].val)/3|0,h=m[g].pos;hn?0:1;return{line:k,threshold:n}},c.debug={printFrequency:function(a,b){var c,d=b.getContext("2d");for(b.width=a.length,b.height=256,d.beginPath(),d.strokeStyle="blue",c=0;cd;d++)if(e._row[d]^h)c[i]++;else{if(i++,i===f)break;c[i]=1,h=!h}return c},c.prototype._decode=function(){var a,c,d,e,f=this,g=[0,0,0,0,0,0,0,0,0],h=[],i=f._findStart();if(!i)return null;e=f._nextSet(f._row,i.end);do{if(g=f._toCounters(e,g),d=f._toPattern(g),0>d)return null;if(a=f._patternToChar(d),0>a)return null;h.push(a),c=e,e+=b.sum(g),e=f._nextSet(f._row,e)}while("*"!==a);return h.pop(),h.length&&f._verifyTrailingWhitespace(c,e,g)?{code:h.join(""),start:i.start,end:e,startInfo:i,decodedCodes:h}:null},c.prototype._verifyTrailingWhitespace=function(a,c,d){var e,f=b.sum(d);return e=c-a-f,3*e>=f?!0:!1},c.prototype._patternToChar=function(a){var b,c=this;for(b=0;bb&&(d=a[c]);return d},c.prototype._toPattern=function(a){for(var b,c,d=a.length,e=0,f=d,g=0,h=this;f>3;){for(e=h._findNextWidth(a,e),f=0,b=0,c=0;d>c;c++)a[c]>e&&(b|=1<c&&f>0;c++)if(a[c]>e&&(f--,2*a[c]>=g))return-1;return b}}return-1},c.prototype._findStart=function(){var a,b,c,d=this,e=d._nextSet(d._row),f=e,g=[0,0,0,0,0,0,0,0,0],h=0,i=!1;for(a=e;ab;b++)g[b]=g[b+2];g[7]=0,g[8]=0,h--}else h++;g[h]=1,i=!i}return null},c}),d("code_39_vin_reader",["./code_39_reader"],function(a){"use strict";function b(){a.call(this)}var c={IOQ:/[IOQ]/g,AZ09:/[A-Z0-9]{17}/};return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b.prototype._decode=function(){var b=a.prototype._decode.apply(this);if(!b)return null;var d=b.code;if(d)return d=d.replace(c.IOQ,""),d.match(c.AZ09)?this._checkChecksum(d)?(b.code=d,b):null:(console.log("Failed AZ09 pattern code:",d),null)},b.prototype._checkChecksum=function(a){return!!a},b}),d("codabar_reader",["./barcode_reader"],function(a){"use strict";function b(){a.call(this),this._counters=[]}var c={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:[3,6,9,96,18,66,33,36,48,72,12,24,69,81,84,21,26,41,11,14]},START_END:{value:[26,41,11,14]},MIN_ENCODED_CHARS:{value:4},MAX_ACCEPTABLE:{value:2},PADDING:{value:1.5},FORMAT:{value:"codabar",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decode=function(){var a,b,c,d,e,f=this,g=[];if(f._fillCounters(),a=f._findStart(),!a)return null;d=a.startCounter;do{if(c=f._toPattern(d),0>c)return null;if(b=f._patternToChar(c),0>b)return null;if(g.push(b),d+=8,g.length>1&&f._isStartEnd(c))break}while(df._counters.length?f._counters.length:d,e=a.start+f._sumCounters(a.startCounter,d-8),{code:g.join(""),start:a.start,end:e,startInfo:a,decodedCodes:g}):null},b.prototype._verifyWhitespace=function(a,b){return(0>=a-1||this._counters[a-1]>=this._calculatePatternLength(a)/2)&&(b+8>=this._counters.length||this._counters[b+7]>=this._calculatePatternLength(b)/2)?!0:!1},b.prototype._calculatePatternLength=function(a){var b,c=0;for(b=a;a+7>b;b++)c+=this._counters[b];return c},b.prototype._thresholdResultPattern=function(a,b){var c,d,e,f,g,h=this,i={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}}},j=b;for(e=0;e=0;f--)c=2===(1&f)?i.bar:i.space,d=1===(1&g)?c.wide:c.narrow,d.size+=h._counters[j+f],d.counts++,g>>=1;j+=8}return["space","bar"].forEach(function(a){var b=i[a];b.wide.min=Math.floor((b.narrow.size/b.narrow.counts+b.wide.size/b.wide.counts)/2),b.narrow.max=Math.ceil(b.wide.min),b.wide.max=Math.ceil((b.wide.size*h.MAX_ACCEPTABLE+h.PADDING)/b.wide.counts)}),i},b.prototype._charToPattern=function(a){var b,c=this,d=a.charCodeAt(0);for(b=0;b=0;d--){if(e=0===(1&d)?j.bar:j.space,f=1===(1&h)?e.wide:e.narrow,g=i._counters[k+d],gf.max)return!1;h>>=1}k+=8}return!0},b.prototype._fillCounters=function(){var a,b=this,c=0,d=!0,e=b._nextUnset(b._row);for(b._counters.length=0,b._counters[c]=0,a=e;ac;c+=2)d=this._counters[c],d>f&&(f=d),e>d&&(e=d);return(e+f)/2|0},b.prototype._toPattern=function(a){var b,c,d,e,f=7,g=a+f,h=1<this._counters.length)return-1;for(b=this._computeAlternatingThreshold(a,g),c=this._computeAlternatingThreshold(a+1,g),d=0;f>d;d++)e=0===(1&d)?b:c,this._counters[a+d]>e&&(i|=h),h>>=1;return i},b.prototype._isStartEnd=function(a){var b;for(b=0;bc;c++)d+=this._counters[c];return d},b.prototype._findStart=function(){var a,b,c,d=this,e=d._nextUnset(d._row);for(a=1;ad;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;b.push(a.code),c.push(a)}if(a=e._findPattern(e.MIDDLE_PATTERN,a.end,!0,!1),null===a)return null;for(c.push(a),d=0;4>d;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;c.push(a),b.push(a.code)}return a},b}),d("upc_e_reader",["./ean_reader"],function(a){"use strict";function b(){a.call(this)}var c={CODE_FREQUENCY:{value:[[56,52,50,49,44,38,35,42,41,37],[7,11,13,14,19,25,28,21,22,26]]},STOP_PATTERN:{value:[1/6*7,1/6*7,1/6*7,1/6*7,1/6*7,1/6*7]},FORMAT:{value:"upc_e",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodePayload=function(a,b,c){var d,e=this,f=0;for(d=0;6>d;d++){if(a=e._decodeCode(a.end),!a)return null;a.code>=e.CODE_G_START&&(a.code=a.code-e.CODE_G_START,f|=1<<5-d),b.push(a.code),c.push(a)}return e._determineParity(f,b)?a:null},b.prototype._determineParity=function(a,b){var c,d,e=this;for(d=0;d=c?b.concat(a.slice(1,3)).concat([c,0,0,0,0]).concat(a.slice(3,6)):3===c?b.concat(a.slice(1,4)).concat([0,0,0,0,0]).concat(a.slice(4,6)):4===c?b.concat(a.slice(1,5)).concat([0,0,0,0,0,a[5]]):b.concat(a.slice(1,6)).concat([0,0,0,0,c]),b.push(a[a.length-1]),b},b.prototype._checksum=function(b){return a.prototype._checksum.call(this,this._convertToUPCA(b))},b.prototype._findEnd=function(b,c){return c=!0,a.prototype._findEnd.call(this,b,c)},b.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,b1&&(!d.inImageWithBorder(a[0],0)||!d.inImageWithBorder(a[1],0));)c-=Math.ceil(c/2),e(-c);return a}function i(a){return[{x:(a[1][0]-a[0][0])/2+a[0][0],y:(a[1][1]-a[0][1])/2+a[0][1]},{x:(a[3][0]-a[2][0])/2+a[2][0],y:(a[3][1]-a[2][1])/2+a[2][1]}]}function j(e){var f,g=null,h=a.getBarcodeLine(d,e[0],e[1]);for(c.showFrequency&&(b.drawPath(e,{x:"x",y:"y"},o.ctx.overlay,{color:"red",lineWidth:3}),a.debug.printFrequency(h.line,o.dom.frequency)),a.toBinaryLine(h),c.showPattern&&a.debug.printPattern(h.line,o.dom.pattern),f=0;fd&&null===i;d++)e=g/h*d*(d%2===0?-1:1),f={y:e*k,x:e*l},b[0].y+=f.x,b[0].x-=f.y,b[1].y+=f.x,b[1].x-=f.y,i=j(b);return i}function m(a){return Math.sqrt(Math.pow(Math.abs(a[1].y-a[0].y),2)+Math.pow(Math.abs(a[1].x-a[0].x),2))}function n(a){var d,e,f,g,k=o.ctx.overlay;return c.drawBoundingBox&&k&&b.drawPath(a,{x:0,y:1},k,{color:"blue",lineWidth:2}),d=i(a),g=m(d),e=Math.atan2(d[1].y-d[0].y,d[1].x-d[0].x),d=h(d,e,Math.floor(.1*g)),null===d?null:(f=j(d),null===f&&(f=l(a,d,e)),null===f?null:(f&&c.drawScanline&&k&&b.drawPath(d,{x:"x",y:"y"},k,{color:"red",lineWidth:3}),{codeResult:f.codeResult,line:d,angle:e,pattern:f.barcodeLine.line,threshold:f.barcodeLine.threshold}))}var o={ctx:{frequency:null,pattern:null,overlay:null},dom:{frequency:null,pattern:null,overlay:null}},p=[];return e(),f(),g(),{decodeFromBoundingBox:function(a){return n(a)},decodeFromBoundingBoxes:function(a){var b,c;for(b=0;b0?a.videoWidth>0&&a.videoHeight>0?(console.log(a.videoWidth+"px x "+a.videoHeight+"px"),b()):window.setTimeout(c,500):b("Unable to play video stream. Is webcam working?"),d--}var d=10;c()}function d(a,d,e){b(a,function(a){d.src=a,h&&d.removeEventListener("loadeddata",h,!1),h=c.bind(null,d,e),d.addEventListener("loadeddata",h,!1),d.play()},function(a){e(a)})}function e(b,c){var d={audio:!1,video:!0},e=a.mergeObjects({width:640,height:480,minAspectRatio:0,maxAspectRatio:100,facing:"environment"},b);return"undefined"==typeof MediaStreamTrack||"undefined"==typeof MediaStreamTrack.getSources?(d.video={mediaSource:"camera",width:{min:e.width,max:e.width},height:{min:e.height,max:e.height},require:["width","height"]},c(d)):void MediaStreamTrack.getSources(function(a){for(var b,f=0;f!=a.length;++f){var g=a[f];"video"==g.kind&&g.facing==e.facing&&(b=g.id)}return d.video={mandatory:{minWidth:e.width,minHeight:e.height,minAspectRatio:e.minAspectRatio,maxAspectRatio:e.maxAspectRatio},optional:[{sourceId:b}]},c(d)})}function f(a,b,c){e(b,function(b){d(b,a,c)})}var g,h;return{request:function(a,b,c){f(a,b,c)},release:function(){var a=g&&g.getVideoTracks();a.length&&a[0].stop(),g=null}}}),d("result_collector",["image_debug"],function(a){"use strict";function b(a,b){return b?b.some(function(b){return Object.keys(b).every(function(c){return b[c]===a[c]})}):!1}function c(a,b){return"function"==typeof b?b(a):!0}return{create:function(d){function e(a){return i&&a&&!b(a,d.blacklist)&&c(a,d.filter)}var f=document.createElement("canvas"),g=f.getContext("2d"),h=[],i=d.capacity||20,j=d.capture===!0;return{addResult:function(b,c,d){var k={};e(d)&&(i--,k.codeResult=d,j&&(f.width=c.x,f.height=c.y,a.drawImage(b,c,g),k.frame=f.toDataURL()),h.push(k))},getResults:function(){return h}}}}}),d("quagga",["code_128_reader","ean_reader","input_stream","image_wrapper","barcode_locator","barcode_decoder","frame_grabber","html_utils","config","events","camera_access","image_debug","gl-matrix","result_collector"],function(b,c,d,e,f,g,h,i,j,k,l,m,n,o){"use strict";function p(a){v(a),M=g.create(j.decoder,K)}function q(){if("undefined"!=typeof document)for(var a=[{node:document.querySelector("div[data-controls]"),prop:j.controls},{node:O.dom.overlay,prop:j.visual.show}],b=0;b0?C(function(){console.log("Workers created"),t(a)}):(p(),t(a))}function t(a){H.play(),a()}function u(){if("undefined"!=typeof document){var a=document.querySelector("#interactive.viewport");if(O.dom.image=document.querySelector("canvas.imgBuffer"),O.dom.image||(O.dom.image=document.createElement("canvas"),O.dom.image.className="imgBuffer",a&&"ImageStream"==j.inputStream.type&&a.appendChild(O.dom.image)),O.ctx.image=O.dom.image.getContext("2d"),O.dom.image.width=H.getCanvasSize().x,O.dom.image.height=H.getCanvasSize().y,O.dom.overlay=document.querySelector("canvas.drawingBuffer"),!O.dom.overlay){O.dom.overlay=document.createElement("canvas"),O.dom.overlay.className="drawingBuffer",a&&a.appendChild(O.dom.overlay);var b=document.createElement("br");b.setAttribute("clear","all"),a&&a.appendChild(b)}O.ctx.overlay=O.dom.overlay.getContext("2d"),O.dom.overlay.width=H.getCanvasSize().x,O.dom.overlay.height=H.getCanvasSize().y}}function v(a){K=a?a:new e({x:H.getWidth(),y:H.getHeight()}),console.log(K.size),L=[R.clone([0,0]),R.clone([0,K.size.y]),R.clone([K.size.x,K.size.y]),R.clone([K.size.x,0])],f.init(K,j.locator)}function w(){return j.locate?f.locate():[[R.clone(L[0]),R.clone(L[1]),R.clone(L[2]),R.clone(L[3])]]}function x(a){function b(a){for(var b=a.length;b--;)a[b][0]+=f,a[b][1]+=g}function c(a){a[0].x+=f,a[0].y+=g,a[1].x+=f,a[1].y+=g}var d,e=H.getTopRight(),f=e.x,g=e.y;if(a&&(0!==f||0!==g)&&(a.line&&2===a.line.length&&c(a.line),a.boxes&&a.boxes.length>0))for(d=0;d0){if(a=P.filter(function(a){return!a.busy})[0],!a)return;I.attachData(a.imageData)}else I.attachData(K.data);I.grab()&&(a?(a.busy=!0,a.worker.postMessage({cmd:"process",imageData:a.imageData},[a.imageData.buffer])):z())}else z()}function B(){J=!1,function a(){J||(A(),Q&&"LiveStream"==j.inputStream.type&&window.requestAnimFrame(a))}()}function C(a){function b(b){P.push(b),P.length>=j.numOfWorkers&&a()}var c;for(P=[],c=0;c0&&P.forEach(function(b){b.worker.postMessage({cmd:"setReaders",readers:a})})}var H,I,J,K,L,M,N,O={ctx:{image:null,overlay:null},dom:{image:null,overlay:null}},P=[],Q=!0,R=n.vec2;return{init:function(a,b,c){return j=i.mergeObjects(j,a),c?(Q=!1,p(c),b()):void r(b)},start:function(){B()},stop:function(){J=!0,P.forEach(function(a){a.worker.terminate(),console.log("Worker terminated!")}),P.length=0,"LiveStream"===j.inputStream.type&&(l.release(),H.clearEventHandlers())},pause:function(){J=!0},onDetected:function(a){k.subscribe("detected",a)},onProcessed:function(a){k.subscribe("processed",a)},setReaders:function(a){G(a)},registerResultCollector:function(a){a&&"function"==typeof a.addResult&&(N=a)},canvas:O,decodeSingle:function(a,b){a=i.mergeObjects({inputStream:{type:"ImageStream",sequence:!1,size:800,src:a.src},numOfWorkers:1,locator:{halfSample:!1}},a),this.init(a,function(){k.once("processed",function(a){J=!0,b.call(null,a)},!0),B()})},Reader:{EANReader:c,Code128Reader:b},ImageWrapper:e,ImageDebug:m,ResultCollector:o}}),c("quagga")});
+=======
+var b,c,d;!function(a){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(b,c){return function(){return n.apply(a,v.call(arguments,0).concat([b,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(b){if(e(r,b)){var c=r[b];delete r[b],t[b]=!0,m.apply(a,c)}if(!e(q,b)&&!e(t,b))throw new Error("No "+b);return q[b]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(b,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||b,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n1?f.size:Math.floor(b/e*f.size):b,d=f.size?b/e>1?Math.floor(e/b*f.size):f.size:e,j.x=c,j.y=d}var c,d,e={},f=null,g=["canrecord","ended"],h={},i={x:0,y:0},j={x:0,y:0};return e.getRealWidth=function(){return a.videoWidth},e.getRealHeight=function(){return a.videoHeight},e.getWidth=function(){return c},e.getHeight=function(){return d},e.setWidth=function(a){c=a},e.setHeight=function(a){d=a},e.setInputStream=function(b){f=b,a.src="undefined"!=typeof b.src?b.src:""},e.ended=function(){return a.ended},e.getConfig=function(){return f},e.setAttribute=function(b,c){a.setAttribute(b,c)},e.pause=function(){a.pause()},e.play=function(){a.play()},e.setCurrentTime=function(b){"LiveStream"!==f.type&&(a.currentTime=b)},e.addEventListener=function(b,c,d){-1!==g.indexOf(b)?(h[b]||(h[b]=[]),h[b].push(c)):a.addEventListener(b,c,d)},e.clearEventHandlers=function(){g.forEach(function(b){var c=h[b];c&&c.length>0&&c.forEach(function(c){a.removeEventListener(b,c)})})},e.trigger=function(a,c){var d,f=h[a];if("canrecord"===a&&b(),f&&f.length>0)for(d=0;d1?g.size:Math.floor(h/i*g.size):h,e=g.size?h/i>1?Math.floor(i/h*g.size):g.size:i,u.x=d,u.y=e,l=!0,j=0,setTimeout(function(){c("canrecord",[])},0)},o,n,g.sequence)}function c(a,b){var c,d=s[a];if(d&&d.length>0)for(c=0;cj?j++:setTimeout(function(){q=!0,c("ended",[])},0)),a):null},f},b}),glMatrixArrayType=Float32Array,"undefined"!=typeof window&&(window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a,b){window.setTimeout(a,1e3/60)}}(),navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia,window.URL=window.URL||window.webkitURL||window.mozURL||window.msURL),d("typedefs",function(a){return function(){var b;return b||a.typedefs}}(this)),d("subImage",["typedefs"],function(){"use strict";function a(a,b,c){c||(c={data:null,size:b}),this.data=c.data,this.originalSize=c.size,this.I=c,this.from=a,this.size=b}return a.prototype.show=function(a,b){var c,d,e,f,g,h,i;for(b||(b=1),c=a.getContext("2d"),a.width=this.size.x,a.height=this.size.y,d=c.getImageData(0,0,a.width,a.height),e=d.data,f=0,g=0;gb?!0:!1},getPoints:function(){return f},getCenter:function(){return g}}},createPoint:function(a,b,c){return{rad:a[c],point:a,id:b}}};return a});var e={};e.create=function(a){var b;return a?(b=new glMatrixArrayType(3),b[0]=a[0],b[1]=a[1],b[2]=a[2]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0]):new glMatrixArrayType(3),b},e.set=function(a,b){return b[0]=a[0],b[1]=a[1],b[2]=a[2],b},e.add=function(a,b,c){return c&&a!=c?(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2],c):(a[0]+=b[0],a[1]+=b[1],a[2]+=b[2],a)},e.subtract=function(a,b,c){return c&&a!=c?(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2],c):(a[0]-=b[0],a[1]-=b[1],a[2]-=b[2],a)},e.negate=function(a,b){return b||(b=a),b[0]=-a[0],b[1]=-a[1],b[2]=-a[2],b},e.scale=function(a,b,c){return c&&a!=c?(c[0]=a[0]*b,c[1]=a[1]*b,c[2]=a[2]*b,c):(a[0]*=b,a[1]*=b,a[2]*=b,a)},e.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],f=Math.sqrt(c*c+d*d+e*e);return f?1==f?(b[0]=c,b[1]=d,b[2]=e,b):(f=1/f,b[0]=c*f,b[1]=d*f,b[2]=e*f,b):(b[0]=0,b[1]=0,b[2]=0,b)},e.cross=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=b[0],h=b[1],i=b[2];return c[0]=e*i-f*h,c[1]=f*g-d*i,c[2]=d*h-e*g,c},e.length=function(a){var b=a[0],c=a[1],d=a[2];return Math.sqrt(b*b+c*c+d*d)},e.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},e.direction=function(a,b,c){c||(c=a);var d=a[0]-b[0],e=a[1]-b[1],f=a[2]-b[2],g=Math.sqrt(d*d+e*e+f*f);return g?(g=1/g,c[0]=d*g,c[1]=e*g,c[2]=f*g,c):(c[0]=0,c[1]=0,c[2]=0,c)},e.lerp=function(a,b,c,d){return d||(d=a),d[0]=a[0]+c*(b[0]-a[0]),d[1]=a[1]+c*(b[1]-a[1]),d[2]=a[2]+c*(b[2]-a[2]),d},e.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+"]"};var f={};f.create=function(a){var b;return a?(b=new glMatrixArrayType(9),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0,0,0,0,0,0,0]):new glMatrixArrayType(9),b},f.set=function(a,b){return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b},f.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=1,a[5]=0,a[6]=0,a[7]=0,a[8]=1,a},f.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[5];return a[1]=a[3],a[2]=a[6],a[3]=c,a[5]=a[7],a[6]=d,a[7]=e,a}return b[0]=a[0],b[1]=a[3],b[2]=a[6],b[3]=a[1],b[4]=a[4],b[5]=a[7],b[6]=a[2],b[7]=a[5],b[8]=a[8],b},f.toMat4=function(a,b){return b||(b=g.create()),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=0,b[4]=a[3],b[5]=a[4],b[6]=a[5],b[7]=0,b[8]=a[6],b[9]=a[7],b[10]=a[8],b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,b},f.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+"]"};var g={};g.create=function(a){var b;return a?(b=new glMatrixArrayType(16),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]):new glMatrixArrayType(16),b},g.set=function(a,b){return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15],b},g.identity=function(a){return a[0]=1,a[1]=0,a[2]=0,a[3]=0,a[4]=0,a[5]=1,a[6]=0,a[7]=0,a[8]=0,a[9]=0,a[10]=1,a[11]=0,a[12]=0,a[13]=0,a[14]=0,a[15]=1,a},g.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[3],f=a[6],g=a[7],h=a[11];return a[1]=a[4],a[2]=a[8],a[3]=a[12],a[4]=c,a[6]=a[9],a[7]=a[13],a[8]=d,a[9]=f,a[11]=a[14],a[12]=e,a[13]=g,a[14]=h,a}return b[0]=a[0],b[1]=a[4],b[2]=a[8],b[3]=a[12],b[4]=a[1],b[5]=a[5],b[6]=a[9],b[7]=a[13],b[8]=a[2],b[9]=a[6],b[10]=a[10],b[11]=a[14],b[12]=a[3],b[13]=a[7],b[14]=a[11],b[15]=a[15],b},g.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],m=a[11],n=a[12],o=a[13],p=a[14],q=a[15];return n*k*h*e-j*o*h*e-n*g*l*e+f*o*l*e+j*g*p*e-f*k*p*e-n*k*d*i+j*o*d*i+n*c*l*i-b*o*l*i-j*c*p*i+b*k*p*i+n*g*d*m-f*o*d*m-n*c*h*m+b*o*h*m+f*c*p*m-b*g*p*m-j*g*d*q+f*k*d*q+j*c*h*q-b*k*h*q-f*c*l*q+b*g*l*q},g.inverse=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],i=a[6],j=a[7],k=a[8],l=a[9],m=a[10],n=a[11],o=a[12],p=a[13],q=a[14],r=a[15],s=c*h-d*g,t=c*i-e*g,u=c*j-f*g,v=d*i-e*h,w=d*j-f*h,x=e*j-f*i,y=k*p-l*o,z=k*q-m*o,A=k*r-n*o,B=l*q-m*p,C=l*r-n*p,D=m*r-n*q,E=1/(s*D-t*C+u*B+v*A-w*z+x*y);return b[0]=(h*D-i*C+j*B)*E,b[1]=(-d*D+e*C-f*B)*E,b[2]=(p*x-q*w+r*v)*E,b[3]=(-l*x+m*w-n*v)*E,b[4]=(-g*D+i*A-j*z)*E,b[5]=(c*D-e*A+f*z)*E,b[6]=(-o*x+q*u-r*t)*E,b[7]=(k*x-m*u+n*t)*E,b[8]=(g*C-h*A+j*y)*E,b[9]=(-c*C+d*A-f*y)*E,b[10]=(o*w-p*u+r*s)*E,b[11]=(-k*w+l*u-n*s)*E,b[12]=(-g*B+h*z-i*y)*E,b[13]=(c*B-d*z+e*y)*E,b[14]=(-o*v+p*t-q*s)*E,b[15]=(k*v-l*t+m*s)*E,b},g.toRotationMat=function(a,b){return b||(b=g.create()),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=0,b[13]=0,b[14]=0,b[15]=1,b},g.toMat3=function(a,b){return b||(b=f.create()),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[4],b[4]=a[5],b[5]=a[6],b[6]=a[8],b[7]=a[9],b[8]=a[10],b},g.toInverseMat3=function(a,b){var c=a[0],d=a[1],e=a[2],g=a[4],h=a[5],i=a[6],j=a[8],k=a[9],l=a[10],m=l*h-i*k,n=-l*g+i*j,o=k*g-h*j,p=c*m+d*n+e*o;if(!p)return null;var q=1/p;return b||(b=f.create()),b[0]=m*q,b[1]=(-l*d+e*k)*q,b[2]=(i*d-e*h)*q,b[3]=n*q,b[4]=(l*c-e*j)*q,b[5]=(-i*c+e*g)*q,b[6]=o*q,b[7]=(-k*c+d*j)*q,b[8]=(h*c-d*g)*q,b},g.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=a[9],n=a[10],o=a[11],p=a[12],q=a[13],r=a[14],s=a[15],t=b[0],u=b[1],v=b[2],w=b[3],x=b[4],y=b[5],z=b[6],A=b[7],B=b[8],C=b[9],D=b[10],E=b[11],F=b[12],G=b[13],H=b[14],I=b[15];return c[0]=t*d+u*h+v*l+w*p,c[1]=t*e+u*i+v*m+w*q,c[2]=t*f+u*j+v*n+w*r,c[3]=t*g+u*k+v*o+w*s,c[4]=x*d+y*h+z*l+A*p,c[5]=x*e+y*i+z*m+A*q,c[6]=x*f+y*j+z*n+A*r,c[7]=x*g+y*k+z*o+A*s,c[8]=B*d+C*h+D*l+E*p,c[9]=B*e+C*i+D*m+E*q,c[10]=B*f+C*j+D*n+E*r,c[11]=B*g+C*k+D*o+E*s,c[12]=F*d+G*h+H*l+I*p,c[13]=F*e+G*i+H*m+I*q,c[14]=F*f+G*j+H*n+I*r,c[15]=F*g+G*k+H*o+I*s,c},g.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2];return c[0]=a[0]*d+a[4]*e+a[8]*f+a[12],c[1]=a[1]*d+a[5]*e+a[9]*f+a[13],c[2]=a[2]*d+a[6]*e+a[10]*f+a[14],c},g.multiplyVec4=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2],g=b[3];return c[0]=a[0]*d+a[4]*e+a[8]*f+a[12]*g,c[1]=a[1]*d+a[5]*e+a[9]*f+a[13]*g,c[2]=a[2]*d+a[6]*e+a[10]*f+a[14]*g,c[3]=a[3]*d+a[7]*e+a[11]*f+a[15]*g,c},g.translate=function(a,b,c){var d=b[0],e=b[1],f=b[2];if(!c||a==c)return a[12]=a[0]*d+a[4]*e+a[8]*f+a[12],a[13]=a[1]*d+a[5]*e+a[9]*f+a[13],a[14]=a[2]*d+a[6]*e+a[10]*f+a[14],a[15]=a[3]*d+a[7]*e+a[11]*f+a[15],a;var g=a[0],h=a[1],i=a[2],j=a[3],k=a[4],l=a[5],m=a[6],n=a[7],o=a[8],p=a[9],q=a[10],r=a[11];return c[0]=g,c[1]=h,c[2]=i,c[3]=j,c[4]=k,c[5]=l,c[6]=m,c[7]=n,c[8]=o,c[9]=p,c[10]=q,c[11]=r,c[12]=g*d+k*e+o*f+a[12],c[13]=h*d+l*e+p*f+a[13],c[14]=i*d+m*e+q*f+a[14],c[15]=j*d+n*e+r*f+a[15],c},g.scale=function(a,b,c){var d=b[0],e=b[1],f=b[2];return c&&a!=c?(c[0]=a[0]*d,c[1]=a[1]*d,c[2]=a[2]*d,c[3]=a[3]*d,c[4]=a[4]*e,c[5]=a[5]*e,c[6]=a[6]*e,c[7]=a[7]*e,c[8]=a[8]*f,c[9]=a[9]*f,c[10]=a[10]*f,c[11]=a[11]*f,c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15],c):(a[0]*=d,a[1]*=d,a[2]*=d,a[3]*=d,a[4]*=e,a[5]*=e,a[6]*=e,a[7]*=e,a[8]*=f,a[9]*=f,a[10]*=f,a[11]*=f,a)},g.rotate=function(a,b,c,d){var e=c[0],f=c[1],g=c[2],h=Math.sqrt(e*e+f*f+g*g);if(!h)return null;1!=h&&(h=1/h,e*=h,f*=h,g*=h);var i=Math.sin(b),j=Math.cos(b),k=1-j,l=a[0],m=a[1],n=a[2],o=a[3],p=a[4],q=a[5],r=a[6],s=a[7],t=a[8],u=a[9],v=a[10],w=a[11],x=e*e*k+j,y=f*e*k+g*i,z=g*e*k-f*i,A=e*f*k-g*i,B=f*f*k+j,C=g*f*k+e*i,D=e*g*k+f*i,E=f*g*k-e*i,F=g*g*k+j;return d?a!=d&&(d[12]=a[12],d[13]=a[13],d[14]=a[14],d[15]=a[15]):d=a,d[0]=l*x+p*y+t*z,d[1]=m*x+q*y+u*z,d[2]=n*x+r*y+v*z,d[3]=o*x+s*y+w*z,d[4]=l*A+p*B+t*C,d[5]=m*A+q*B+u*C,d[6]=n*A+r*B+v*C,d[7]=o*A+s*B+w*C,d[8]=l*D+p*E+t*F,d[9]=m*D+q*E+u*F,d[10]=n*D+r*E+v*F,d[11]=o*D+s*E+w*F,d},g.rotateX=function(a,b,c){var d=Math.sin(b),e=Math.cos(b),f=a[4],g=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],m=a[11];return c?a!=c&&(c[0]=a[0],c[1]=a[1],c[2]=a[2],c[3]=a[3],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15]):c=a,c[4]=f*e+j*d,c[5]=g*e+k*d,c[6]=h*e+l*d,c[7]=i*e+m*d,c[8]=f*-d+j*e,c[9]=g*-d+k*e,c[10]=h*-d+l*e,c[11]=i*-d+m*e,c},g.rotateY=function(a,b,c){var d=Math.sin(b),e=Math.cos(b),f=a[0],g=a[1],h=a[2],i=a[3],j=a[8],k=a[9],l=a[10],m=a[11];return c?a!=c&&(c[4]=a[4],c[5]=a[5],c[6]=a[6],c[7]=a[7],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15]):c=a,c[0]=f*e+j*-d,c[1]=g*e+k*-d,c[2]=h*e+l*-d,c[3]=i*e+m*-d,c[8]=f*d+j*e,c[9]=g*d+k*e,c[10]=h*d+l*e,c[11]=i*d+m*e,c},g.rotateZ=function(a,b,c){var d=Math.sin(b),e=Math.cos(b),f=a[0],g=a[1],h=a[2],i=a[3],j=a[4],k=a[5],l=a[6],m=a[7];return c?a!=c&&(c[8]=a[8],c[9]=a[9],c[10]=a[10],c[11]=a[11],c[12]=a[12],c[13]=a[13],c[14]=a[14],c[15]=a[15]):c=a,c[0]=f*e+j*d,c[1]=g*e+k*d,c[2]=h*e+l*d,c[3]=i*e+m*d,c[4]=f*-d+j*e,c[5]=g*-d+k*e,c[6]=h*-d+l*e,c[7]=i*-d+m*e,c},g.frustum=function(a,b,c,d,e,f,h){h||(h=g.create());var i=b-a,j=d-c,k=f-e;return h[0]=2*e/i,h[1]=0,h[2]=0,h[3]=0,h[4]=0,h[5]=2*e/j,h[6]=0,h[7]=0,h[8]=(b+a)/i,h[9]=(d+c)/j,h[10]=-(f+e)/k,h[11]=-1,h[12]=0,h[13]=0,h[14]=-(f*e*2)/k,h[15]=0,h},g.perspective=function(a,b,c,d,e){var f=c*Math.tan(a*Math.PI/360),h=f*b;return g.frustum(-h,h,-f,f,c,d,e)},g.ortho=function(a,b,c,d,e,f,h){h||(h=g.create());var i=b-a,j=d-c,k=f-e;return h[0]=2/i,h[1]=0,h[2]=0,h[3]=0,h[4]=0,h[5]=2/j,h[6]=0,h[7]=0,h[8]=0,h[9]=0,h[10]=-2/k,h[11]=0,h[12]=-(a+b)/i,h[13]=-(d+c)/j,h[14]=-(f+e)/k,h[15]=1,h},g.lookAt=function(a,b,c,d){d||(d=g.create());var e=a[0],f=a[1],h=a[2],i=c[0],j=c[1],k=c[2],l=b[0],m=b[1],n=b[2];if(e==l&&f==m&&h==n)return g.identity(d);var o,p,q,r,s,t,u,v,w,x;return o=e-b[0],p=f-b[1],q=h-b[2],x=1/Math.sqrt(o*o+p*p+q*q),o*=x,p*=x,q*=x,r=j*q-k*p,s=k*o-i*q,t=i*p-j*o,x=Math.sqrt(r*r+s*s+t*t),x?(x=1/x,r*=x,s*=x,t*=x):(r=0,s=0,t=0),u=p*t-q*s,v=q*r-o*t,w=o*s-p*r,x=Math.sqrt(u*u+v*v+w*w),x?(x=1/x,u*=x,v*=x,w*=x):(u=0,v=0,w=0),d[0]=r,d[1]=u,d[2]=o,d[3]=0,d[4]=s,d[5]=v,d[6]=p,d[7]=0,d[8]=t,d[9]=w,d[10]=q,d[11]=0,d[12]=-(r*e+s*f+t*h),d[13]=-(u*e+v*f+w*h),d[14]=-(o*e+p*f+q*h),d[15]=1,d},g.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+",\n "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+",\n "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+",\n "+a[12]+", "+a[13]+", "+a[14]+", "+a[15]+"]"},quat4={},quat4.create=function(a){var b;return a?(b=new glMatrixArrayType(4),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0,0]):new glMatrixArrayType(4),b},quat4.set=function(a,b){return b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b},quat4.calculateW=function(a,b){var c=a[0],d=a[1],e=a[2];return b&&a!=b?(b[0]=c,b[1]=d,b[2]=e,b[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e)),b):(a[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e)),a)},quat4.inverse=function(a,b){return b&&a!=b?(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2],b[3]=a[3],b):(a[0]*=-1,a[1]*=-1,a[2]*=-1,a)},quat4.length=function(a){var b=a[0],c=a[1],d=a[2],e=a[3];return Math.sqrt(b*b+c*c+d*d+e*e)},quat4.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],f=a[3],g=Math.sqrt(c*c+d*d+e*e+f*f);return 0==g?(b[0]=0,b[1]=0,b[2]=0,b[3]=0,b):(g=1/g,b[0]=c*g,b[1]=d*g,b[2]=e*g,b[3]=f*g,b)},quat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=b[0],i=b[1],j=b[2],k=b[3];return c[0]=d*k+g*h+e*j-f*i,c[1]=e*k+g*i+f*h-d*j,c[2]=f*k+g*j+d*i-e*h,c[3]=g*k-d*h-e*i-f*j,c},quat4.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2],g=a[0],h=a[1],i=a[2],j=a[3],k=j*d+h*f-i*e,l=j*e+i*d-g*f,m=j*f+g*e-h*d,n=-g*d-h*e-i*f;return c[0]=k*j+n*-g+l*-i-m*-h,c[1]=l*j+n*-h+m*-g-k*-i,c[2]=m*j+n*-i+k*-h-l*-g,c},quat4.toMat3=function(a,b){b||(b=f.create());var c=a[0],d=a[1],e=a[2],g=a[3],h=c+c,i=d+d,j=e+e,k=c*h,l=c*i,m=c*j,n=d*i,o=d*j,p=e*j,q=g*h,r=g*i,s=g*j;return b[0]=1-(n+p),b[1]=l-s,b[2]=m+r,b[3]=l+s,b[4]=1-(k+p),b[5]=o-q,b[6]=m-r,b[7]=o+q,b[8]=1-(k+n),b},quat4.toMat4=function(a,b){b||(b=g.create());var c=a[0],d=a[1],e=a[2],f=a[3],h=c+c,i=d+d,j=e+e,k=c*h,l=c*i,m=c*j,n=d*i,o=d*j,p=e*j,q=f*h,r=f*i,s=f*j;return b[0]=1-(n+p),b[1]=l-s,b[2]=m+r,b[3]=0,b[4]=l+s,b[5]=1-(k+p),b[6]=o-q,b[7]=0,b[8]=m-r,b[9]=o+q,b[10]=1-(k+n),b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,b},quat4.slerp=function(a,b,c,d){d||(d=a);var e=a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3];if(Math.abs(e)>=1)return d!=a&&(d[0]=a[0],d[1]=a[1],d[2]=a[2],d[3]=a[3]),d;var f=Math.acos(e),g=Math.sqrt(1-e*e);if(Math.abs(g)<.001)return d[0]=.5*a[0]+.5*b[0],d[1]=.5*a[1]+.5*b[1],d[2]=.5*a[2]+.5*b[2],d[3]=.5*a[3]+.5*b[3],d;var h=Math.sin((1-c)*f)/g,i=Math.sin(c*f)/g;return d[0]=a[0]*h+b[0]*i,d[1]=a[1]*h+b[1]*i,d[2]=a[2]*h+b[2]*i,d[3]=a[3]*h+b[3]*i,d},quat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+"]"},d("glMatrix",["typedefs"],function(a){return function(){var b;return b||a.glMatrix}}(this)),g.xVec4=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2],g=b[3];return c[0]=a[0]*d+a[1]*e+a[2]*f+a[3]*g,c[1]=a[4]*d+a[5]*e+a[6]*f+a[7]*g,c[2]=a[8]*d+a[9]*e+a[10]*f+a[11]*g,c[3]=a[12]*d+a[13]*e+a[14]*f+a[15]*g,c},f.scale=function(a,b,c){return c&&a!=c?(c=f.create(),c[0]=a[0]*b,c[1]=a[1]*b,c[2]=a[2]*b,c[3]=a[3]*b,c[4]=a[4]*b,c[5]=a[5]*b,c[6]=a[6]*b,c[7]=a[7]*b,c[8]=a[8]*b,c):(a[0]*=b,a[1]*=b,a[2]*=b,a[3]*=b,a[4]*=b,a[5]*=b,a[6]*=b,a[7]*=b,a[8]*=b,a)},f.inverse=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],i=a[6],j=a[7],k=a[8],l=1/(c*g*k+d*h*i+e*f*j-e*g*i-d*f*k-c*h*j);return b[0]=(g*k-h*j)*l,b[1]=(e*j-d*k)*l,b[2]=(d*h-e*g)*l,b[3]=(h*i-f*k)*l,b[4]=(c*k-e*i)*l,b[5]=(e*f-c*h)*l,b[6]=(f*j-g*i)*l,b[7]=(d*i-c*j)*l,b[8]=(c*g-d*f)*l,b},f.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],m=b[0],n=b[1],o=b[2],p=b[3],q=b[4],r=b[5],s=b[6],t=b[7],u=b[8];return c[0]=d*m+e*p+f*s,c[1]=d*n+e*q+f*t,c[2]=d*o+e*r+f*u,c[3]=g*m+h*p+i*s,c[4]=g*n+h*q+i*t,c[5]=g*o+h*r+i*u,c[6]=j*m+k*p+l*s,c[7]=j*n+k*q+l*t,c[8]=j*o+k*r+l*u,c},f.xVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2];return c[0]=a[0]*d+a[1]*e+a[2]*f,c[1]=a[3]*d+a[4]*e+a[5]*f,c[2]=a[6]*d+a[7]*e+a[8]*f,c};var h={};h.create=function(a){var b;return a?(b=new glMatrixArrayType(4),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0,0]):new glMatrixArrayType(4),b},h.project=function(a,b){return b||(b=a),b[0]=a[0]/a[3],b[1]=a[1]/a[3],b[2]=a[2]/a[3],b},h.scale=function(a,b,c){return c&&a!=c?(c[0]=a[0]*b,c[1]=a[1]*b,c[2]=a[2]*b,c[3]=a[3]*b,c):(a[0]*=b,a[1]*=b,a[2]*=b,a[4]*=b,a)},h.xMat4=function(a,b,c){c||(c=a);var d=a[0],e=a[1],f=a[2],g=a[3];return c[0]=b[0]*d+b[4]*e+b[8]*f+b[12]*g,c[1]=b[1]*d+b[5]*e+b[9]*f+b[13]*g,c[2]=b[2]*d+b[6]*e+b[10]*f+b[14]*g,c[3]=b[3]*d+b[7]*e+b[11]*f+b[15]*g,c};var i={};i.create=function(a){var b;return a?(b=new glMatrixArrayType(4),b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0,0,0]):new glMatrixArrayType(4),b},i.xVec2=function(a,b,c){c||(c=b);var d=b[0],e=b[1];return c[0]=a[0]*d+a[1]*e,c[1]=a[2]*d+a[3]*e,c},i.scale=function(a,b,c){return c&&a!=c?(c[0]=a[0]*b,c[1]=a[1]*b,c[2]=a[2]*b,c[3]=a[3]*b,c):(a[0]*=b,a[1]*=b,a[2]*=b,a[3]*=b,a)},i.determinant=function(a){return a[0]*a[3]-a[1]*a[2]},i.inverse=function(a){var b=1/i.determinant(a),c=a[3]*b,d=-a[1]*b,e=-a[2]*b,f=a[0];return a[0]=c,a[1]=d,a[2]=e,a[3]=f,a};var j={};j.create=function(a){var b;return a?(b=new glMatrixArrayType(2),b[0]=a[0],b[1]=a[1]):b=glMatrixArrayType===Array?new glMatrixArrayType([0,0]):new glMatrixArrayType(2),b},j.subtract=function(a,b,c){return c&&a!=c?(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c):(a[0]-=b[0],a[1]-=b[1],a)},j.add=function(a,b,c){return c&&a!=c?(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c):(a[0]+=b[0],a[1]+=b[1],a)},j.scale=function(a,b,c){return c&&a!=c?(c[0]=a[0]*b,c[1]=a[1]*b,c):(a[0]*=b,a[1]*=b,a)},j.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=Math.sqrt(c*c+d*d);return e?1==e?(b[0]=c,b[1]=d,b):(e=1/e,b[0]=c*e,b[1]=d*e,b):(b[0]=0,b[1]=0,b)},j.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]},j.multiply=function(a,b,c){return c||(c=a),c[0]=a[0]*b[0],c[1]=a[1]*b[1],c},j.unproject=function(a){return e.create([a[0],a[1],1])},j.length=function(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1])},j.perspectiveProject=function(a){var b=j.create(a);return j.scale(b,1/a[2])},e.project=function(a){return j.scale(j.create(a),1/a[2])};var k={};k.scale=function(a,b,c){return c&&a!=c?(c[0]=a[0]*b,c[1]=a[1]*b,c[2]=a[2]*b,c[3]=a[3]*b,c[4]=a[4]*b,c[5]=a[5]*b,c):(a[0]*=b,a[1]*=b,a[2]*=b,a[3]*=b,a[4]*=b,a[5]*=b,a)},k.subtract=function(a,b,c){return c&&a!=c?(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2],c[3]=a[3]-b[3],c[4]=a[4]-b[4],c[5]=a[5]-b[5],c):(a[0]-=b[0],a[1]-=b[1],a[2]-=b[2],a[3]-=b[3],a[4]-=b[4],a[5]-=b[5],a)},k.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]+a[4]*b[4]+a[5]*b[5]};var l={};return l.xVec6=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],i=b[5];return c[0]=a[0]*d+a[1]*e+a[2]*f+a[3]*g+a[4]*h+a[5]*i,c[1]=a[6]*d+a[7]*e+a[8]*f+a[9]*g+a[10]*h+a[11]*i,c[2]=a[12]*d+a[13]*e+a[14]*f+a[15]*g+a[16]*h+a[17]*i,c[3]=a[18]*d+a[19]*e+a[20]*f+a[21]*g+a[22]*h+a[23]*i,c[4]=a[24]*d+a[25]*e+a[26]*f+a[27]*g+a[28]*h+a[29]*i,c[5]=a[30]*d+a[31]*e+a[32]*f+a[33]*g+a[34]*h+a[35]*i,c},f.xVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],f=b[2];return c[0]=a[0]*d+a[1]*e+a[2]*f,c[1]=a[3]*d+a[4]*e+a[5]*f,c[2]=a[6]*d+a[7]*e+a[8]*f,c},d("glMatrixAddon",["glMatrix"],function(a){return function(){var b;return b||a.glMatrixAddon}}(this)),d("array_helper",[],function(){"use strict";return{init:function(a,b){for(var c=a.length;c--;)a[c]=b},shuffle:function(a){var b,c,d=a.length-1;for(d;d>=0;d--)b=Math.floor(Math.random()*d),c=a[d],a[d]=a[b],a[b]=c;return a},toPointList:function(a){var b,c,d=[],e=[];for(b=0;b=b&&e.push(a[d]);return e},maxIndex:function(a){var b,c=0;for(b=0;ba[c]&&(c=b);return c},max:function(a){var b,c=0;for(b=0;bc&&(c=a[b]);return c},sum:function(a){for(var b=a.length,c=0;b--;)c+=a[b];return c}}}),d("cv_utils",["cluster","glMatrixAddon","array_helper"],function(a,b,c){"use strict";var d={};return d.imageRef=function(a,b){var c={x:a,y:b,toVec2:function(){return j.create([this.x,this.y])},toVec3:function(){return e.create([this.x,this.y,1])},round:function(){return this.x=this.x>0?Math.floor(this.x+.5):Math.floor(this.x-.5),this.y=this.y>0?Math.floor(this.y+.5):Math.floor(this.y-.5),this}};return c},d.computeIntegralImage2=function(a,b){var c,d,e=a.data,f=a.size.x,g=a.size.y,h=b.data,i=0,j=0,k=0,l=0,m=0;for(k=f,i=0,d=1;g>d;d++)i+=e[j],h[k]+=i,j+=f,k+=f;for(j=0,k=1,i=0,c=1;f>c;c++)i+=e[j],h[k]+=i,j++,k++;for(d=1;g>d;d++)for(j=d*f+1,k=(d-1)*f+1,l=d*f,m=(d-1)*f,c=1;f>c;c++)h[j]+=e[j]+h[k]+h[l]-h[m],j++,k++,l++,m++},d.computeIntegralImage=function(a,b){for(var c=a.data,d=a.size.x,e=a.size.y,f=b.data,g=0,h=0;d>h;h++)g+=c[h],f[h]=g;for(var i=1;e>i;i++){g=0;for(var j=0;d>j;j++)g+=c[i*d+j],f[i*d+j]=g+f[(i-1)*d+j]}},d.thresholdImage=function(a,b,c){c||(c=a);for(var d=a.data,e=d.length,f=c.data;e--;)f[e]=d[e]>e]++;return g},d.sharpenLine=function(a){var b,c,d=a.length,e=a[0],f=a[1];for(b=1;d-1>b;b++)c=a[b+1],a[b-1]=2*f-e-c&255,e=f,f=c;return a},d.determineOtsuThreshold=function(a,b){function e(a,b){var c,d=0;for(c=a;b>=c;c++)d+=h[c];return d}function f(a,b){var c,d=0;for(c=a;b>=c;c++)d+=c*h[c];return d}function g(){var g,i,j,k,l,m,n,o=[0],p=(1<k;k++)g=e(0,k),i=e(k+1,p),j=g*i,0===j&&(j=1),l=f(0,k)*i,m=f(k+1,p)*g,n=l-m,o[k]=n*n/j;return c.maxIndex(o)}b||(b=8);var h,i,j=8-b;return i=g(),i<=e;e++)for(f=0;n>f;f++)m[e*n+f]=0,m[(o-1-e)*n+f]=0;for(e=r;o-r>e;e++)for(f=0;r>=f;f++)m[e*n+f]=0,m[e*n+(n-1-f)]=0;for(e=r+1;o-r-1>e;e++)for(f=r+1;n-r>f;f++)g=p[(e-r-1)*n+(f-r-1)],h=p[(e-r-1)*n+(f+r)],i=p[(e+r)*n+(f-r-1)],j=p[(e+r)*n+(f+r)],q=j-i-h+g,k=q/s,m[e*n+f]=l[e*n+f]>k+5?0:1},d.cluster=function(b,c,d){function e(a){var b=!1;for(g=0;gb.x-j&&a.xb.y-k&&a.yd;d++){for(h=Math.floor(Math.random()*a.length),f=[],i=h,f.push(a[i]);null!==(i=c(i,!0));)f.push(a[i]);if(h>0)for(i=h;null!==(i=c(i,!1));)f.push(a[i]);f.length>g.length&&(g=f)}return g}},d.DILATE=1,d.ERODE=2,d.dilate=function(a,b){var c,d,e,f,g,h,i,j=a.data,k=b.data,l=a.size.y,m=a.size.x;for(c=1;l-1>c;c++)for(d=1;m-1>d;d++)f=c-1,g=c+1,h=d-1,i=d+1,e=j[f*m+h]+j[f*m+i]+j[c*m+d]+j[g*m+h]+j[g*m+i],k[c*m+d]=e>0?1:0},d.erode=function(a,b){var c,d,e,f,g,h,i,j=a.data,k=b.data,l=a.size.y,m=a.size.x;for(c=1;l-1>c;c++)for(d=1;m-1>d;d++)f=c-1,g=c+1,h=d-1,i=d+1,e=j[f*m+h]+j[f*m+i]+j[c*m+d]+j[g*m+h]+j[g*m+i],k[c*m+d]=5===e?1:0},d.subtract=function(a,b,c){c||(c=a);for(var d=a.data.length,e=a.data,f=b.data,g=c.data;d--;)g[d]=e[d]-f[d]},d.bitwiseOr=function(a,b,c){c||(c=a);for(var d=a.data.length,e=a.data,f=b.data,g=c.data;d--;)g[d]=e[d]||f[d]},d.countNonZero=function(a){for(var b=a.data.length,c=a.data,d=0;b--;)d+=c[b];return d},d.topGeneric=function(a,b,c){var d,e,f,g,h=0,i=0,j=[];for(d=0;b>d;d++)j[d]={score:0,item:null};for(d=0;di)for(f=j[h],f.score=e,f.item=a[d],i=Number.MAX_VALUE,g=0;b>g;g++)j[g].scoref;){for(d=0;h>d;d++)c[i]=Math.floor((.299*a[4*e+0]+.587*a[4*e+1]+.114*a[4*e+2]+(.299*a[4*(e+1)+0]+.587*a[4*(e+1)+1]+.114*a[4*(e+1)+2])+(.299*a[4*f+0]+.587*a[4*f+1]+.114*a[4*f+2])+(.299*a[4*(f+1)+0]+.587*a[4*(f+1)+1]+.114*a[4*(f+1)+2]))/4),i++,e+=2,f+=2;e+=j,f+=j}},d.computeGray=function(a,b,c){var d,e=a.length/4|0,f=c&&c.singleChannel===!0;if(f)for(d=0;e>d;d++)b[d]=a[4*d+0];else for(d=0;e>d;d++)b[d]=Math.floor(.299*a[4*d+0]+.587*a[4*d+1]+.114*a[4*d+2])},d.loadImageArray=function(a,b,c){c||(c=document.createElement("canvas"));var e=new Image;e.callback=b,e.onload=function(){c.width=this.width,c.height=this.height;var a=c.getContext("2d");a.drawImage(this,0,0);var b=new Uint8Array(this.width*this.height);a.drawImage(this,0,0);var e=a.getImageData(0,0,this.width,this.height).data;d.computeGray(e,b),this.callback(b,{x:this.width,y:this.height},this)},e.src=a},d.halfSample=function(a,b){for(var c=a.data,d=a.size.x,e=b.data,f=0,g=d,h=c.length,i=d/2,j=0;h>g;){for(var k=0;i>k;k++)e[j]=Math.floor((c[f]+c[f+1]+c[g]+c[g+1])/4),j++,f+=2,g+=2;f+=d,g+=d}},d.hsv2rgb=function(a,b){var c=a[0],d=a[1],e=a[2],f=e*d,g=f*(1-Math.abs(c/60%2-1)),h=e-f,i=0,j=0,k=0;return b=b||[0,0,0],60>c?(i=f,j=g):120>c?(i=g,j=f):180>c?(j=f,k=g):240>c?(j=g,k=f):300>c?(i=g,k=f):360>c&&(i=f,k=g),b[0]=255*(i+h)|0,b[1]=255*(j+h)|0,b[2]=255*(k+h)|0,b},d._computeDivisors=function(a){var b,c=[],d=[];for(b=1;bb[d]?d++:c++;return e},d.calculatePatchSize=function(a,b){function c(a){for(var b=0,c=a[Math.floor(a.length/2)];b0&&(c=Math.abs(a[b]-m)>Math.abs(a[b-1]-m)?a[b-1]:a[b]),m/ci[k-1]/i[k]?{x:c,y:c}:null}var d,e=this._computeDivisors(b.x),f=this._computeDivisors(b.y),g=Math.max(b.x,b.y),h=this._computeIntersection(e,f),i=[8,10,15,20,32,60,80],j={"x-small":5,small:4,medium:3,large:2,"x-large":1},k=j[a]||j.medium,l=i[k],m=Math.floor(g/l);return d=c(h),d||(d=c(this._computeDivisors(g)),d||(d=c(this._computeDivisors(m*l)))),d},d._parseCSSDimensionValues=function(a){var b={value:parseFloat(a),unit:(a.indexOf("%")===a.length-1,"%")};return b},d._dimensionsConverters={top:function(a,b){return"%"===a.unit?Math.floor(b.height*(a.value/100)):void 0},right:function(a,b){return"%"===a.unit?Math.floor(b.width-b.width*(a.value/100)):void 0},bottom:function(a,b){return"%"===a.unit?Math.floor(b.height-b.height*(a.value/100)):void 0},left:function(a,b){return"%"===a.unit?Math.floor(b.width*(a.value/100)):void 0}},d.computeImageArea=function(a,b,c){var e={width:a,height:b},f=Object.keys(c).reduce(function(a,b){var f=c[b],g=d._parseCSSDimensionValues(f),h=d._dimensionsConverters[b](g,e);return a[b]=h,a},{});return{sx:f.left,sy:f.top,sw:f.right-f.left,sh:f.bottom-f.top}},d}),d("image_wrapper",["subImage","cv_utils","array_helper"],function(a,b,c){"use strict";function d(a,b,d,e){b?this.data=b:d?(this.data=new d(a.x*a.y),d===Array&&e&&c.init(this.data,0)):(this.data=new Uint8Array(a.x*a.y),Uint8Array===Array&&e&&c.init(this.data,0)),this.size=a}return d.prototype.inImageWithBorder=function(a,b){return a.x>=b&&a.y>=b&&a.x=0&&u>=0&&n-1>v&&o-1>w){for(g=s,h=0;m>h;++h,j.add(g,y))for(k=0;l>k;++k,j.add(g,p))b.set(k,h,x(a,g[0],g[1]));return 0}var z=n-1,A=o-1,B=0;for(g=s,h=0;m>h;++h,j.add(g,y))for(k=0;l>k;++k,j.add(g,p))0<=g[0]&&0<=g[1]&&g[0]c;c++)for(d=0;e>d;d++)a.data[d*f+c]=this.data[(b.y+d)*this.size.x+b.x+c]},d.prototype.copyTo=function(a){for(var b=this.data.length,c=this.data,d=a.data;b--;)d[b]=c[b]},d.prototype.get=function(a,b){return this.data[b*this.size.x+a]},d.prototype.getSafe=function(a,b){var c;if(!this.indexMapping){for(this.indexMapping={x:[],y:[]},c=0;ca;a++)d[a]=d[(c-1)*b+a]=0;for(a=1;c-1>a;a++)d[a*b]=d[a*b+(b-1)]=0},d.prototype.invert=function(){for(var a=this.data,b=a.length;b--;)a[b]=a[b]?0:1},d.prototype.convolve=function(a){var b,c,d,e,f=a.length/2|0,g=0;for(c=0;c=e;e++)for(d=-f;f>=d;d++)g+=a[e+f][d+f]*this.getSafe(b+d,c+e);this.data[c*this.size.x+b]=g}},d.prototype.moments=function(a){var b,c,d,e,f,g,h,i,k,l,m,n,o=this.data,p=this.size.y,q=this.size.x,r=[],s=[],t=Math.PI,u=t/4;if(0>=a)return s;for(f=0;a>f;f++)r[f]={m00:0,m01:0,m10:0,m11:0,m02:0,m20:0,theta:0,rad:0};for(c=0;p>c;c++)for(e=c*c,b=0;q>b;b++)d=o[c*q+b],d>0&&(g=r[d-1],g.m00+=1,g.m01+=c,g.m10+=b,g.m11+=b*c,g.m02+=e,g.m20+=b*b);for(f=0;a>f;f++)g=r[f],isNaN(g.m00)||0===g.m00||(l=g.m10/g.m00,m=g.m01/g.m00,h=g.m11/g.m00-l*m,i=g.m02/g.m00-m*m,k=g.m20/g.m00-l*l,n=(i-k)/(2*h),n=.5*Math.atan(n)+(h>=0?u:-u)+t,g.theta=(180*n/t+90)%180-90,g.theta<0&&(g.theta+=180),g.rad=n>t?n-t:n,g.vec=j.create([Math.cos(n),Math.sin(n)]),s.push(g));return s},d.prototype.show=function(a,b){var c,d,e,f,g,h,i;for(b||(b=1),c=a.getContext("2d"),a.width=this.size.x,a.height=this.size.y,d=c.getImageData(0,0,a.width,a.height),e=d.data,f=0,i=0;ic||c>360)&&(c=360);for(var e=[0,1,1],f=[0,0,0],g=[255,255,255],h=[0,0,0],i=[],j=a.getContext("2d"),k=j.getImageData(d.x,d.y,this.size.x,this.size.y),l=k.data,m=this.data.length;m--;)e[0]=this.data[m]*c,i=e[0]<=0?g:e[0]>=360?h:b.hsv2rgb(e,f),l[4*m+0]=i[0],l[4*m+1]=i[1],l[4*m+2]=i[2],l[4*m+3]=255;j.putImageData(k,d.x,d.y)},d}),d("tracer",[],function(){"use strict";var a={searchDirections:[[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1],[-1,0],[-1,1]],create:function(a,b){function c(a,b,c,d){var e,k,l;for(e=0;7>e;e++){if(k=a.cy+i[a.dir][0],l=a.cx+i[a.dir][1],f=k*j+l,g[f]===b&&(0===h[f]||h[f]===c))return h[f]=c,a.cy=k,a.cx=l,!0;0===h[f]&&(h[f]=d),a.dir=(a.dir+1)%8}return!1}function d(a,b,c){return{dir:c,x:a,y:b,next:null,prev:null}}function e(a,b,e,f,g){var h,i,j,k=null,l={cx:b,cy:a,dir:0};if(c(l,f,e,g)){k=d(b,a,l.dir),h=k,j=l.dir,i=d(l.cx,l.cy,0),i.prev=h,h.next=i,i.next=null,h=i;do l.dir=(l.dir+6)%8,c(l,f,e,g),j!=l.dir?(h.dir=l.dir,i=d(l.cx,l.cy,0),i.prev=h,h.next=i,i.next=null,h=i):(h.dir=j,h.x=l.cx,h.y=l.cy),j=l.dir;while(l.cx!=b||l.cy!=a);k.prev=h.prev,h.prev.next=k}return k}var f,g=a.data,h=b.data,i=this.searchDirections,j=a.size.x;return{trace:function(a,b,d,e){return c(a,b,d,e)},contourTracing:function(a,b,c,d,f){return e(a,b,c,d,f)}}}};return a}),d("rasterizer",["tracer"],function(a){"use strict";var b={createContour2D:function(){return{dir:null,index:null,firstVertex:null,insideContours:null,nextpeer:null,prevpeer:null}},CONTOUR_DIR:{CW_DIR:0,CCW_DIR:1,UNKNOWN_DIR:2},DIR:{OUTSIDE_EDGE:-32767,INSIDE_EDGE:-32766},create:function(c,d){var e=c.data,f=d.data,g=c.size.x,h=c.size.y,i=a.create(c,d);return{rasterize:function(a){var c,d,j,k,l,m,n,o,p,q,r,s,t=[],u=0;for(s=0;400>s;s++)t[s]=0;for(t[0]=e[0],p=null,m=1;h-1>m;m++)for(k=0,d=t[0],l=1;g-1>l;l++)if(r=m*g+l,0===f[r])if(c=e[r],c!==d){if(0===k)j=u+1,t[j]=c,d=c,n=i.contourTracing(m,l,j,c,b.DIR.OUTSIDE_EDGE),null!==n&&(u++,k=j,o=b.createContour2D(),o.dir=b.CONTOUR_DIR.CW_DIR,o.index=k,o.firstVertex=n,o.nextpeer=p,o.insideContours=null,null!==p&&(p.prevpeer=o),p=o);else if(n=i.contourTracing(m,l,b.DIR.INSIDE_EDGE,c,k),null!==n){for(o=b.createContour2D(),o.firstVertex=n,o.insideContours=null,0===a?o.dir=b.CONTOUR_DIR.CCW_DIR:o.dir=b.CONTOUR_DIR.CW_DIR,o.index=a,q=p;null!==q&&q.index!==k;)q=q.nextpeer;null!==q&&(o.nextpeer=q.insideContours,null!==q.insideContours&&(q.insideContours.prevpeer=o),q.insideContours=o)}}else f[r]=k;else f[r]===b.DIR.OUTSIDE_EDGE||f[r]===b.DIR.INSIDE_EDGE?(k=0,d=f[r]===b.DIR.INSIDE_EDGE?e[r]:t[0]):(k=f[r],d=t[k]);for(q=p;null!==q;)q.index=a,q=q.nextpeer;return{cc:p,count:u}},debug:{drawContour:function(a,c){var d,e,f,g=a.getContext("2d"),h=c;for(g.strokeStyle="red",g.fillStyle="red",g.lineWidth=1,d=null!==h?h.insideContours:null;null!==h;){switch(null!==d?(e=d,d=d.nextpeer):(e=h,h=h.nextpeer,d=null!==h?h.insideContours:null),e.dir){case b.CONTOUR_DIR.CW_DIR:g.strokeStyle="red";break;case b.CONTOUR_DIR.CCW_DIR:g.strokeStyle="blue";break;case b.CONTOUR_DIR.UNKNOWN_DIR:g.strokeStyle="green"}f=e.firstVertex,g.beginPath(),g.moveTo(f.x,f.y);do f=f.next,g.lineTo(f.x,f.y);while(f!==e.firstVertex);g.stroke()}}}}}};return b}),d("skeletonizer",[],function(){"use strict";function a(stdlib, foreign, buffer) {"use asm";var images=new stdlib.Uint8Array(buffer),size=foreign.size|0,imul=stdlib.Math.imul;function erode(inImagePtr, outImagePtr) {inImagePtr=inImagePtr|0;outImagePtr=outImagePtr|0;var v=0,u=0,sum=0,yStart1=0,yStart2=0,xStart1=0,xStart2=0,offset=0;for ( v=1; (v|0)<((size - 1)|0); v=(v+1)|0) {offset=(offset+size)|0;for ( u=1; (u|0)<((size - 1)|0); u=(u+1)|0) {yStart1=(offset - size)|0;yStart2=(offset+size)|0;xStart1=(u - 1)|0;xStart2=(u+1)|0;sum=((images[(inImagePtr+yStart1+xStart1)|0]|0)+(images[(inImagePtr+yStart1+xStart2)|0]|0)+(images[(inImagePtr+offset+u)|0]|0)+(images[(inImagePtr+yStart2+xStart1)|0]|0)+(images[(inImagePtr+yStart2+xStart2)|0]|0))|0;if ((sum|0) == (5|0)) {images[(outImagePtr+offset+u)|0]=1;} else {images[(outImagePtr+offset+u)|0]=0;}}}return;}function subtract(aImagePtr, bImagePtr, outImagePtr) {aImagePtr=aImagePtr|0;bImagePtr=bImagePtr|0;outImagePtr=outImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(outImagePtr+length)|0]=((images[(aImagePtr+length)|0]|0) - (images[(bImagePtr+length)|0]|0))|0;}}function bitwiseOr(aImagePtr, bImagePtr, outImagePtr) {aImagePtr=aImagePtr|0;bImagePtr=bImagePtr|0;outImagePtr=outImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(outImagePtr+length)|0]=((images[(aImagePtr+length)|0]|0)|(images[(bImagePtr+length)|0]|0))|0;}}function countNonZero(imagePtr) {imagePtr=imagePtr|0;var sum=0,length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;sum=((sum|0)+(images[(imagePtr+length)|0]|0))|0;}return (sum|0);}function init(imagePtr, value) {imagePtr=imagePtr|0;value=value|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(imagePtr+length)|0]=value;}}function dilate(inImagePtr, outImagePtr) {inImagePtr=inImagePtr|0;outImagePtr=outImagePtr|0;var v=0,u=0,sum=0,yStart1=0,yStart2=0,xStart1=0,xStart2=0,offset=0;for ( v=1; (v|0)<((size - 1)|0); v=(v+1)|0) {offset=(offset+size)|0;for ( u=1; (u|0)<((size - 1)|0); u=(u+1)|0) {yStart1=(offset - size)|0;yStart2=(offset+size)|0;xStart1=(u - 1)|0;xStart2=(u+1)|0;sum=((images[(inImagePtr+yStart1+xStart1)|0]|0)+(images[(inImagePtr+yStart1+xStart2)|0]|0)+(images[(inImagePtr+offset+u)|0]|0)+(images[(inImagePtr+yStart2+xStart1)|0]|0)+(images[(inImagePtr+yStart2+xStart2)|0]|0))|0;if ((sum|0)>(0|0)) {images[(outImagePtr+offset+u)|0]=1;} else {images[(outImagePtr+offset+u)|0]=0;}}}return;}function memcpy(srcImagePtr, dstImagePtr) {srcImagePtr=srcImagePtr|0;dstImagePtr=dstImagePtr|0;var length=0;length=imul(size, size)|0;while ((length|0)>0) {length=(length - 1)|0;images[(dstImagePtr+length)|0]=(images[(srcImagePtr+length)|0]|0);}}function zeroBorder(imagePtr) {imagePtr=imagePtr|0;var x=0,y=0;for ( x=0; (x|0)<((size - 1)|0); x=(x+1)|0) {images[(imagePtr+x)|0]=0;images[(imagePtr+y)|0]=0;y=((y+size) - 1)|0;images[(imagePtr+y)|0]=0;y=(y+1)|0;}for ( x=0; (x|0)<(size|0); x=(x+1)|0) {images[(imagePtr+y)|0]=0;y=(y+1)|0;}}function skeletonize() {var subImagePtr=0,erodedImagePtr=0,tempImagePtr=0,skelImagePtr=0,sum=0,done=0;erodedImagePtr=imul(size, size)|0;tempImagePtr=(erodedImagePtr+erodedImagePtr)|0;skelImagePtr=(tempImagePtr+erodedImagePtr)|0;init(skelImagePtr, 0);zeroBorder(subImagePtr);do {erode(subImagePtr, erodedImagePtr);dilate(erodedImagePtr, tempImagePtr);subtract(subImagePtr, tempImagePtr, tempImagePtr);bitwiseOr(skelImagePtr, tempImagePtr, skelImagePtr);memcpy(erodedImagePtr, subImagePtr);sum=countNonZero(subImagePtr)|0;done=((sum|0) == 0|0);} while(!done);}return {skeletonize : skeletonize};}
+return a}),d("image_debug",[],function(){"use strict";return{drawRect:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=1,c.beginPath(),c.strokeRect(a.x,a.y,b.x,b.y)},drawPath:function(a,b,c,d){c.strokeStyle=d.color,c.fillStyle=d.color,c.lineWidth=d.lineWidth,c.beginPath(),c.moveTo(a[0][b.x],a[0][b.y]);for(var e=1;eb&&(b+=180),b=(180-b)*Math.PI/180,f=i.create([Math.cos(b),-Math.sin(b),Math.sin(b),Math.cos(b)]),c=0;cd;d++)i.xVec2(f,e.box[d]);u.boxFromPatches.showTransformed&&g.drawPath(e.box,{x:0,y:1},G.ctx.binary,{color:"#99ff00",lineWidth:2})}for(c=0;cd;d++)e.box[d][0]n&&(n=e.box[d][0]),e.box[d][1]o&&(o=e.box[d][1]);for(h=[[l,m],[n,m],[n,o],[l,o]],u.boxFromPatches.showTransformedBox&&g.drawPath(h,{x:0,y:1},G.ctx.binary,{color:"#ff0000",lineWidth:2}),k=u.halfSample?2:1,f=i.inverse(f),d=0;4>d;d++)i.xVec2(f,h[d]);for(u.boxFromPatches.showBB&&g.drawPath(h,{x:0,y:1},G.ctx.binary,{color:"#ff0000",lineWidth:2}),d=0;4>d;d++)j.scale(h[d],k);return h}function m(){b.otsuThreshold(v,C),C.zeroBorder(),u.showCanvas&&C.show(G.dom.binary,255)}function n(){var a,b,d,e,h,i,j,k,l=[];for(a=0;ab;b++)d.push(0);for(c=A.data.length;c--;)A.data[c]>0&&d[A.data[c]-1]++;return d=d.map(function(a,b){return{val:a,label:b+1}}),d.sort(function(a,b){return b.val-a.val}),e=d.filter(function(a){return a.val>=5})}function p(a,c){var d,e,f,h,i,j=[],k=[],m=[0,1,1],n=[0,0,0];for(d=0;d=2){for(e=0;em&&k.push(a[e]);if(k.length>=2){for(i=k.length,g=q(k),f=0,e=0;e1&&g.length>=k.length/4*3&&g.length>a.length/4&&(f/=g.length,h={index:b[1]*H.x+b[0],pos:{x:c,y:d},box:[j.create([c,d]),j.create([c+x.size.x,d]),j.create([c+x.size.x,d+x.size.y]),j.create([c,d+x.size.y])],moments:g,rad:f,vec:j.create([Math.cos(f),Math.sin(f)])},l.push(h))}}return l}function t(a){function c(){var a;for(a=0;al&&e(h))):A.data[h]=Number.MAX_VALUE}var h,i,k=0,l=.95,m=0,n=[0,1,1],o=[0,0,0];for(f.init(z.data,0),f.init(A.data,0),f.init(B.data,null),h=0;h0&&A.data[h]<=k&&(i=B.data[h],n[0]=A.data[h]/(k+1)*360,b.hsv2rgb(n,o),g.drawRect(i.pos,x.size,G.ctx.binary,{color:"rgb("+o.join(",")+")",lineWidth:2}));return k}var u,v,w,x,y,z,A,B,C,D,E,F,G={ctx:{binary:null},dom:{binary:null}},H={x:0,y:0},I=this;return{init:function(a,b){u=b,E=a,h(),k()},locate:function(){var a,c,d;if(u.halfSample&&b.halfSample(E,v),m(),a=n(),a.lengthe?null:(c=o(e),0===c.length?null:d=p(c,e))},checkImageConstraints:function(a,c){var d,e,f,g=a.getWidth(),h=a.getHeight(),i=c.halfSample?.5:1;if(a.getConfig().area&&(f=b.computeImageArea(g,h,a.getConfig().area),a.setTopRight({x:f.sx,y:f.sy}),a.setCanvasSize({x:g,y:h}),g=f.sw,h=f.sh),e={x:Math.floor(g*i),y:Math.floor(h*i)},d=b.calculatePatchSize(c.patchSize,e),console.log("Patch-Size: "+JSON.stringify(d)),a.setWidth(Math.floor(Math.floor(e.x/d.x)*(1/i)*d.x)),a.setHeight(Math.floor(Math.floor(e.y/d.y)*(1/i)*d.y)),a.getWidth()%d.x===0&&a.getHeight()%d.y===0)return!0;throw new Error("Image dimensions do not comply with the current settings: Width ("+g+" )and height ("+h+") must a multiple of "+d.x)}}}),d("bresenham",["cv_utils","image_wrapper"],function(a,b){"use strict";var c={},d={DIR:{UP:1,DOWN:-1}};return c.getBarcodeLine=function(a,b,c){function d(a,b){l=s[b*t+a],u+=l,v=v>l?l:v,w=l>w?l:w,r.push(l)}var e,f,g,h,i,j,k,l,m=0|b.x,n=0|b.y,o=0|c.x,p=0|c.y,q=Math.abs(p-n)>Math.abs(o-m),r=[],s=a.data,t=a.size.x,u=0,v=255,w=0;for(q&&(j=m,m=n,n=j,j=o,o=p,p=j),m>o&&(j=m,m=o,o=j,j=n,n=p,p=j),e=o-m,f=Math.abs(p-n),g=e/2|0,i=n,h=p>n?1:-1,k=m;o>k;k++)q?d(i,k):d(k,i),g-=f,0>g&&(i+=h,g+=e);return{line:r,min:v,max:w}},c.toOtsuBinaryLine=function(c){var d=c.line,e=new b({x:d.length-1,y:1},d),f=a.determineOtsuThreshold(e,5);return d=a.sharpenLine(d),a.thresholdImage(e,f),{line:d,threshold:f}},c.toBinaryLine=function(a){var b,c,e,f,g,h,i=a.min,j=a.max,k=a.line,l=i+(j-i)/2,m=[],n=(j-i)/12,o=-n;for(e=k[0]>l?d.DIR.UP:d.DIR.DOWN,m.push({pos:0,val:k[0]}),g=0;gb+c&&k[g+1]<1.5*l?d.DIR.DOWN:b+c>n&&k[g+1]>.5*l?d.DIR.UP:e,e!==f&&(m.push({pos:g,val:k[g]}),e=f);for(m.push({pos:k.length,val:k[k.length-1]}),h=m[0].pos;hl?0:1;for(g=1;gm[g].val?m[g].val+(m[g+1].val-m[g].val)/3*2|0:m[g+1].val+(m[g].val-m[g+1].val)/3|0,h=m[g].pos;hn?0:1;return{line:k,threshold:n}},c.debug={printFrequency:function(a,b){var c,d=b.getContext("2d");for(b.width=a.length,b.height=256,d.beginPath(),d.strokeStyle="blue",c=0;cg)return Number.MAX_VALUE;d+=e}return d/f},a.prototype._nextSet=function(a,b){var c;for(b=b||0,c=b;c1)for(c=0;cd?(j.start=c-g,j.end=c,j.counter=e,j):null;i++,e[i]=1,h=!h}}else for(e.push(0),c=g;ca?0:a,d=a;b>d;d++)if(this._row[d]!==c)return!1;return!0},a.prototype._fillCounters=function(a,b,c){var d,e=this,f=0,g=[];for(c="undefined"!=typeof c?c:!0,a="undefined"!=typeof a?a:e._nextUnset(e._row),b=b||e._row.length,g[f]=0,d=a;b>d;d++)e._row[d]^c?g[f]++:(f++,g[f]=1,c=!c);return g},Object.defineProperty(a.prototype,"FORMAT",{value:"unknown",writeable:!1}),a.DIRECTION={FORWARD:1,REVERSE:-1},a.Exception={StartNotFoundException:"Start-Info was not found!",CodeNotFoundException:"Code could not be found!",PatternNotFoundException:"Pattern could not be found!"},a.CONFIG_KEYS={},a}),d("code_128_reader",["./barcode_reader"],function(a){"use strict";function b(){a.call(this)}var c={CODE_SHIFT:{value:98},CODE_C:{value:99},CODE_B:{value:100},CODE_A:{value:101},START_CODE_A:{value:103},START_CODE_B:{value:104},START_CODE_C:{value:105},STOP_CODE:{value:106},MODULO:{value:11},CODE_PATTERN:{value:[[2,1,2,2,2,2],[2,2,2,1,2,2],[2,2,2,2,2,1],[1,2,1,2,2,3],[1,2,1,3,2,2],[1,3,1,2,2,2],[1,2,2,2,1,3],[1,2,2,3,1,2],[1,3,2,2,1,2],[2,2,1,2,1,3],[2,2,1,3,1,2],[2,3,1,2,1,2],[1,1,2,2,3,2],[1,2,2,1,3,2],[1,2,2,2,3,1],[1,1,3,2,2,2],[1,2,3,1,2,2],[1,2,3,2,2,1],[2,2,3,2,1,1],[2,2,1,1,3,2],[2,2,1,2,3,1],[2,1,3,2,1,2],[2,2,3,1,1,2],[3,1,2,1,3,1],[3,1,1,2,2,2],[3,2,1,1,2,2],[3,2,1,2,2,1],[3,1,2,2,1,2],[3,2,2,1,1,2],[3,2,2,2,1,1],[2,1,2,1,2,3],[2,1,2,3,2,1],[2,3,2,1,2,1],[1,1,1,3,2,3],[1,3,1,1,2,3],[1,3,1,3,2,1],[1,1,2,3,1,3],[1,3,2,1,1,3],[1,3,2,3,1,1],[2,1,1,3,1,3],[2,3,1,1,1,3],[2,3,1,3,1,1],[1,1,2,1,3,3],[1,1,2,3,3,1],[1,3,2,1,3,1],[1,1,3,1,2,3],[1,1,3,3,2,1],[1,3,3,1,2,1],[3,1,3,1,2,1],[2,1,1,3,3,1],[2,3,1,1,3,1],[2,1,3,1,1,3],[2,1,3,3,1,1],[2,1,3,1,3,1],[3,1,1,1,2,3],[3,1,1,3,2,1],[3,3,1,1,2,1],[3,1,2,1,1,3],[3,1,2,3,1,1],[3,3,2,1,1,1],[3,1,4,1,1,1],[2,2,1,4,1,1],[4,3,1,1,1,1],[1,1,1,2,2,4],[1,1,1,4,2,2],[1,2,1,1,2,4],[1,2,1,4,2,1],[1,4,1,1,2,2],[1,4,1,2,2,1],[1,1,2,2,1,4],[1,1,2,4,1,2],[1,2,2,1,1,4],[1,2,2,4,1,1],[1,4,2,1,1,2],[1,4,2,2,1,1],[2,4,1,2,1,1],[2,2,1,1,1,4],[4,1,3,1,1,1],[2,4,1,1,1,2],[1,3,4,1,1,1],[1,1,1,2,4,2],[1,2,1,1,4,2],[1,2,1,2,4,1],[1,1,4,2,1,2],[1,2,4,1,1,2],[1,2,4,2,1,1],[4,1,1,2,1,2],[4,2,1,1,1,2],[4,2,1,2,1,1],[2,1,2,1,4,1],[2,1,4,1,2,1],[4,1,2,1,2,1],[1,1,1,1,4,3],[1,1,1,3,4,1],[1,3,1,1,4,1],[1,1,4,1,1,3],[1,1,4,3,1,1],[4,1,1,1,1,3],[4,1,1,3,1,1],[1,1,3,1,4,1],[1,1,4,1,3,1],[3,1,1,1,4,1],[4,1,1,1,3,1],[2,1,1,4,1,2],[2,1,1,2,1,4],[2,1,1,2,3,2],[2,3,3,1,1,1,2]]},SINGLE_CODE_ERROR:{value:1},AVG_CODE_ERROR:{value:.5},FORMAT:{value:"code_128",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodeCode=function(a){var b,c,d,e,f=[0,0,0,0,0,0],g=this,h=a,i=!g._row[h],j=0,k={error:Number.MAX_VALUE,code:-1,start:a,end:a};for(b=h;bd;d++)g[d]=g[d+2];g[4]=0,g[5]=0,k--}else k++;g[k]=1,j=!j}return null},b.prototype._decode=function(){var a,b,c,d=this,e=d._findStart(),f=null,g=!1,h=[],i=0,j=0,k=[],l=[],m=!1;if(null===e)return null;switch(f={code:e.code,start:e.start,end:e.end},l.push(f),j=f.code,f.code){case d.START_CODE_A:a=d.CODE_A;break;case d.START_CODE_B:a=d.CODE_B;break;case d.START_CODE_C:a=d.CODE_C;break;default:return null}for(;!g;){if(b=m,m=!1,f=d._decodeCode(f.end),null!==f)switch(f.code!==d.STOP_CODE&&(k.push(f.code),i++,j+=i*f.code),l.push(f),a){case d.CODE_A:if(f.code<64)h.push(String.fromCharCode(32+f.code));else if(f.code<96)h.push(String.fromCharCode(f.code-64));else switch(f.code){case d.CODE_SHIFT:m=!0,a=d.CODE_B;break;case d.CODE_B:a=d.CODE_B;break;case d.CODE_C:a=d.CODE_C;break;case d.STOP_CODE:g=!0}break;case d.CODE_B:if(f.code<96)h.push(String.fromCharCode(32+f.code));else switch(f.code!=d.STOP_CODE&&(c=!1),f.code){case d.CODE_SHIFT:m=!0,a=d.CODE_A;break;case d.CODE_A:a=d.CODE_A;break;case d.CODE_C:a=d.CODE_C;break;case d.STOP_CODE:g=!0}break;case d.CODE_C:switch(f.code<100&&h.push(f.code<10?"0"+f.code:f.code),f.code){case d.CODE_A:a=d.CODE_A;break;case d.CODE_B:a=d.CODE_B;break;case d.STOP_CODE:g=!0}}else g=!0;b&&(a=a==d.CODE_A?d.CODE_B:d.CODE_A)}return null===f?null:(f.end=d._nextUnset(d._row,f.end),d._verifyTrailingWhitespace(f)?(j-=i*k[k.length-1],j%103!=k[k.length-1]?null:h.length?(h.splice(h.length-1,1),{code:h.join(""),start:e.start,end:f.end,codeset:a,startInfo:e,decodedCodes:l,endInfo:f}):null):null)},a.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,bd;d++)e=h._matchPattern(f,h.CODE_PATTERN[d]),eh.AVG_CODE_ERROR?null:l}}else k++;g[k]=1,j=!j}return null},b.prototype._findPattern=function(a,b,c,d,e){var f,g,h,i,j,k=[],l=this,m=0,n={error:Number.MAX_VALUE,code:-1,start:0,end:0};for(b||(b=l._nextSet(l._row)),void 0===c&&(c=!1),void 0===d&&(d=!0),void 0===e&&(e=l.AVG_CODE_ERROR),f=0;fg))return n.error=g,n.start=f-i,n.end=f,n;if(!d)return null;for(h=0;h=0&&c._matchRange(a,b.start,0))return b;d=b.end,b=null}},b.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start),bd;d++){if(a=f._decodeCode(a.end),!a)return null;a.code>=f.CODE_G_START?(a.code=a.code-f.CODE_G_START,g|=1<<5-d):g|=0<<5-d,b.push(a.code),c.push(a)}if(e=f._calculateFirstDigit(g),null===e)return null;if(b.unshift(e),a=f._findPattern(f.MIDDLE_PATTERN,a.end,!0,!1),null===a)return null;for(c.push(a),d=0;6>d;d++){if(a=f._decodeCode(a.end,f.CODE_G_START),!a)return null;c.push(a),b.push(a.code)}return a},b.prototype._decode=function(){var a,b,c=this,d=[],e=[];return(a=c._findStart())?(b={code:a.code,start:a.start,end:a.end},e.push(b),(b=c._decodePayload(b,d,e))&&(b=c._findEnd(b.end,!1))?(e.push(b),c._checksum(d)?{code:d.join(""),start:a.start,end:b.end,codeset:"",startInfo:a,decodedCodes:e}:null):null):null},b.prototype._checksum=function(a){var b,c=0;for(b=a.length-2;b>=0;b-=2)c+=a[b];for(c*=3,b=a.length-1;b>=0;b-=2)c+=a[b];return c%10===0},b}),d("code_39_reader",["./barcode_reader","./array_helper"],function(a,b){"use strict";function c(){a.call(this)}var d={ALPHABETH_STRING:{value:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"},ALPHABET:{value:[48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,45,46,32,42,36,47,43,37]},CHARACTER_ENCODINGS:{value:[52,289,97,352,49,304,112,37,292,100,265,73,328,25,280,88,13,268,76,28,259,67,322,19,274,82,7,262,70,22,385,193,448,145,400,208,133,388,196,148,168,162,138,42]},ASTERISK:{value:148},FORMAT:{value:"code_39",writeable:!1}};return c.prototype=Object.create(a.prototype,d),c.prototype.constructor=c,c.prototype._toCounters=function(a,c){var d,e=this,f=c.length,g=e._row.length,h=!e._row[a],i=0;for(b.init(c,0),d=a;g>d;d++)if(e._row[d]^h)c[i]++;else{if(i++,i===f)break;c[i]=1,h=!h}return c},c.prototype._decode=function(){var a,c,d,e,f=this,g=[0,0,0,0,0,0,0,0,0],h=[],i=f._findStart();if(!i)return null;e=f._nextSet(f._row,i.end);do{if(g=f._toCounters(e,g),d=f._toPattern(g),0>d)return null;if(a=f._patternToChar(d),0>a)return null;h.push(a),c=e,e+=b.sum(g),e=f._nextSet(f._row,e)}while("*"!==a);return h.pop(),h.length&&f._verifyTrailingWhitespace(c,e,g)?{code:h.join(""),start:i.start,end:e,startInfo:i,decodedCodes:h}:null},c.prototype._verifyTrailingWhitespace=function(a,c,d){var e,f=b.sum(d);return e=c-a-f,3*e>=f?!0:!1},c.prototype._patternToChar=function(a){var b,c=this;for(b=0;bb&&(d=a[c]);return d},c.prototype._toPattern=function(a){for(var b,c,d=a.length,e=0,f=d,g=0,h=this;f>3;){for(e=h._findNextWidth(a,e),f=0,b=0,c=0;d>c;c++)a[c]>e&&(b|=1<c&&f>0;c++)if(a[c]>e&&(f--,2*a[c]>=g))return-1;return b}}return-1},c.prototype._findStart=function(){var a,b,c,d=this,e=d._nextSet(d._row),f=e,g=[0,0,0,0,0,0,0,0,0],h=0,i=!1;for(a=e;ab;b++)g[b]=g[b+2];g[7]=0,g[8]=0,h--}else h++;g[h]=1,i=!i}return null},c}),d("code_39_vin_reader",["./code_39_reader"],function(a){"use strict";function b(){a.call(this)}var c={IOQ:/[IOQ]/g,AZ09:/[A-Z0-9]{17}/};return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b.prototype._decode=function(){var b=a.prototype._decode.apply(this);if(!b)return null;var d=b.code;if(d)return d=d.replace(c.IOQ,""),d.match(c.AZ09)?this._checkChecksum(d)?(b.code=d,b):null:(console.log("Failed AZ09 pattern code:",d),null)},b.prototype._checkChecksum=function(a){return!!a},b}),d("codabar_reader",["./barcode_reader"],function(a){"use strict";function b(){a.call(this),this._counters=[]}var c={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:[3,6,9,96,18,66,33,36,48,72,12,24,69,81,84,21,26,41,11,14]},START_END:{value:[26,41,11,14]},MIN_ENCODED_CHARS:{value:4},MAX_ACCEPTABLE:{value:2},PADDING:{value:1.5},FORMAT:{value:"codabar",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decode=function(){var a,b,c,d,e,f=this,g=[];if(this._counters=f._fillCounters(),a=f._findStart(),!a)return null;d=a.startCounter;do{if(c=f._toPattern(d),0>c)return null;if(b=f._patternToChar(c),0>b)return null;if(g.push(b),d+=8,g.length>1&&f._isStartEnd(c))break}while(df._counters.length?f._counters.length:d,e=a.start+f._sumCounters(a.startCounter,d-8),{code:g.join(""),start:a.start,end:e,startInfo:a,decodedCodes:g}):null},b.prototype._verifyWhitespace=function(a,b){return(0>=a-1||this._counters[a-1]>=this._calculatePatternLength(a)/2)&&(b+8>=this._counters.length||this._counters[b+7]>=this._calculatePatternLength(b)/2)?!0:!1},b.prototype._calculatePatternLength=function(a){var b,c=0;for(b=a;a+7>b;b++)c+=this._counters[b];return c},b.prototype._thresholdResultPattern=function(a,b){var c,d,e,f,g,h=this,i={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}}},j=b;for(e=0;e=0;f--)c=2===(1&f)?i.bar:i.space,d=1===(1&g)?c.wide:c.narrow,d.size+=h._counters[j+f],d.counts++,g>>=1;j+=8}return["space","bar"].forEach(function(a){var b=i[a];b.wide.min=Math.floor((b.narrow.size/b.narrow.counts+b.wide.size/b.wide.counts)/2),b.narrow.max=Math.ceil(b.wide.min),b.wide.max=Math.ceil((b.wide.size*h.MAX_ACCEPTABLE+h.PADDING)/b.wide.counts)}),i},b.prototype._charToPattern=function(a){var b,c=this,d=a.charCodeAt(0);for(b=0;b=0;d--){if(e=0===(1&d)?j.bar:j.space,f=1===(1&h)?e.wide:e.narrow,g=i._counters[k+d],gf.max)return!1;h>>=1}k+=8}return!0},b.prototype._patternToChar=function(a){var b,c=this;for(b=0;bc;c+=2)d=this._counters[c],d>f&&(f=d),e>d&&(e=d);return(e+f)/2|0},b.prototype._toPattern=function(a){var b,c,d,e,f=7,g=a+f,h=1<this._counters.length)return-1;for(b=this._computeAlternatingThreshold(a,g),c=this._computeAlternatingThreshold(a+1,g),d=0;f>d;d++)e=0===(1&d)?b:c,this._counters[a+d]>e&&(i|=h),h>>=1;return i},b.prototype._isStartEnd=function(a){var b;for(b=0;bc;c++)d+=this._counters[c];return d},b.prototype._findStart=function(){var a,b,c,d=this,e=d._nextUnset(d._row);for(a=1;ad;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;b.push(a.code),c.push(a)}if(a=e._findPattern(e.MIDDLE_PATTERN,a.end,!0,!1),null===a)return null;for(c.push(a),d=0;4>d;d++){if(a=e._decodeCode(a.end,e.CODE_G_START),!a)return null;c.push(a),b.push(a.code)}return a},b}),d("upc_e_reader",["./ean_reader"],function(a){"use strict";function b(){a.call(this)}var c={CODE_FREQUENCY:{value:[[56,52,50,49,44,38,35,42,41,37],[7,11,13,14,19,25,28,21,22,26]]},STOP_PATTERN:{value:[1/6*7,1/6*7,1/6*7,1/6*7,1/6*7,1/6*7]},FORMAT:{value:"upc_e",writeable:!1}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodePayload=function(a,b,c){var d,e=this,f=0;for(d=0;6>d;d++){if(a=e._decodeCode(a.end),!a)return null;a.code>=e.CODE_G_START&&(a.code=a.code-e.CODE_G_START,f|=1<<5-d),b.push(a.code),c.push(a)}return e._determineParity(f,b)?a:null},b.prototype._determineParity=function(a,b){var c,d,e=this;for(d=0;d=c?b.concat(a.slice(1,3)).concat([c,0,0,0,0]).concat(a.slice(3,6)):3===c?b.concat(a.slice(1,4)).concat([0,0,0,0,0]).concat(a.slice(4,6)):4===c?b.concat(a.slice(1,5)).concat([0,0,0,0,0,a[5]]):b.concat(a.slice(1,6)).concat([0,0,0,0,c]),b.push(a[a.length-1]),b},b.prototype._checksum=function(b){return a.prototype._checksum.call(this,this._convertToUPCA(b))},b.prototype._findEnd=function(b,c){return c=!0,a.prototype._findEnd.call(this,b,c)},b.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,bf))return m.error=f,m.start=e-h,m.end=e,m;if(!d)return null;for(g=0;g=0&&c._matchRange(a,b.start,0))return b;d=b.end,b=null}},c.prototype._verifyTrailingWhitespace=function(a){var b,c=this;return b=a.end+(a.end-a.start)/2,bg;){for(d=0;5>d;d++)i[0][d]=a[g]*this.barSpaceRatio[0],i[1][d]=a[g+1]*this.barSpaceRatio[1],g+=2;if(e=f._decodePair(i),!e)return null;for(d=0;d1&&(!d.inImageWithBorder(a[0],0)||!d.inImageWithBorder(a[1],0));)c-=Math.ceil(c/2),e(-c);return a}function i(a){return[{x:(a[1][0]-a[0][0])/2+a[0][0],y:(a[1][1]-a[0][1])/2+a[0][1]},{x:(a[3][0]-a[2][0])/2+a[2][0],y:(a[3][1]-a[2][1])/2+a[2][1]}]}function j(e){var f,g=null,h=a.getBarcodeLine(d,e[0],e[1]);for(c.showFrequency&&(b.drawPath(e,{x:"x",y:"y"},o.ctx.overlay,{color:"red",lineWidth:3}),a.debug.printFrequency(h.line,o.dom.frequency)),a.toBinaryLine(h),c.showPattern&&a.debug.printPattern(h.line,o.dom.pattern),f=0;fd&&null===i;d++)e=g/h*d*(d%2===0?-1:1),f={y:e*k,x:e*l},b[0].y+=f.x,b[0].x-=f.y,b[1].y+=f.x,b[1].x-=f.y,i=j(b);return i}function m(a){return Math.sqrt(Math.pow(Math.abs(a[1].y-a[0].y),2)+Math.pow(Math.abs(a[1].x-a[0].x),2))}function n(a){var d,e,f,g,l=o.ctx.overlay;return c.drawBoundingBox&&l&&b.drawPath(a,{x:0,y:1},l,{color:"blue",lineWidth:2}),d=i(a),g=m(d),e=Math.atan2(d[1].y-d[0].y,d[1].x-d[0].x),d=h(d,e,Math.floor(.1*g)),null===d?null:(f=j(d),null===f&&(f=k(a,d,e)),null===f?null:(f&&c.drawScanline&&l&&b.drawPath(d,{x:"x",y:"y"},l,{color:"red",lineWidth:3}),{codeResult:f.codeResult,line:d,angle:e,pattern:f.barcodeLine.line,threshold:f.barcodeLine.threshold}))}var o={ctx:{frequency:null,pattern:null,overlay:null},dom:{frequency:null,pattern:null,overlay:null}},p=[];return e(),f(),g(),{decodeFromBoundingBox:function(a){return n(a)},decodeFromBoundingBoxes:function(a){var b,c;for(b=0;b0?a.videoWidth>0&&a.videoHeight>0?(console.log(a.videoWidth+"px x "+a.videoHeight+"px"),b()):window.setTimeout(c,500):b("Unable to play video stream. Is webcam working?"),d--}var d=10;c()}function d(a,d,e){b(a,function(a){d.src=a,h&&d.removeEventListener("loadeddata",h,!1),h=c.bind(null,d,e),d.addEventListener("loadeddata",h,!1),d.play()},function(a){e(a)})}function e(b,c){var d={audio:!1,video:!0},e=a.mergeObjects({width:640,height:480,minAspectRatio:0,maxAspectRatio:100,facing:"environment"},b);return"undefined"==typeof MediaStreamTrack||"undefined"==typeof MediaStreamTrack.getSources?(d.video={mediaSource:"camera",width:{min:e.width,max:e.width},height:{min:e.height,max:e.height},require:["width","height"]},c(d)):void MediaStreamTrack.getSources(function(a){for(var b,f=0;f!=a.length;++f){var g=a[f];"video"==g.kind&&g.facing==e.facing&&(b=g.id)}return d.video={mandatory:{minWidth:e.width,minHeight:e.height,minAspectRatio:e.minAspectRatio,maxAspectRatio:e.maxAspectRatio},optional:[{sourceId:b}]},c(d)})}function f(a,b,c){e(b,function(b){d(b,a,c)})}var g,h;return{request:function(a,b,c){f(a,b,c)},release:function(){var a=g&&g.getVideoTracks();a.length&&a[0].stop(),g=null}}}),d("result_collector",["image_debug"],function(a){"use strict";function b(a,b){return b?b.some(function(b){return Object.keys(b).every(function(c){return b[c]===a[c]})}):!1}function c(a,b){return"function"==typeof b?b(a):!0}return{create:function(d){function e(a){return i&&a&&!b(a,d.blacklist)&&c(a,d.filter)}var f=document.createElement("canvas"),g=f.getContext("2d"),h=[],i=d.capacity||20,j=d.capture===!0;return{addResult:function(b,c,d){var k={};e(d)&&(i--,k.codeResult=d,j&&(f.width=c.x,f.height=c.y,a.drawImage(b,c,g),k.frame=f.toDataURL()),h.push(k))},getResults:function(){return h}}}}}),d("quagga",["input_stream","image_wrapper","barcode_locator","barcode_decoder","frame_grabber","html_utils","config","events","camera_access","image_debug","result_collector"],function(b,c,d,e,f,g,h,i,k,l,m){"use strict";function n(a){t(a),K=e.create(h.decoder,I)}function o(){if("undefined"!=typeof document)for(var a=[{node:document.querySelector("div[data-controls]"),prop:h.controls},{node:M.dom.overlay,prop:h.visual.show}],b=0;b0?A(function(){console.log("Workers created"),r(a)}):(n(),r(a))}function r(a){F.play(),a()}function s(){if("undefined"!=typeof document){var a=document.querySelector("#interactive.viewport");if(M.dom.image=document.querySelector("canvas.imgBuffer"),M.dom.image||(M.dom.image=document.createElement("canvas"),M.dom.image.className="imgBuffer",a&&"ImageStream"==h.inputStream.type&&a.appendChild(M.dom.image)),M.ctx.image=M.dom.image.getContext("2d"),M.dom.image.width=F.getCanvasSize().x,M.dom.image.height=F.getCanvasSize().y,M.dom.overlay=document.querySelector("canvas.drawingBuffer"),!M.dom.overlay){M.dom.overlay=document.createElement("canvas"),M.dom.overlay.className="drawingBuffer",a&&a.appendChild(M.dom.overlay);var b=document.createElement("br");b.setAttribute("clear","all"),a&&a.appendChild(b)}M.ctx.overlay=M.dom.overlay.getContext("2d"),M.dom.overlay.width=F.getCanvasSize().x,M.dom.overlay.height=F.getCanvasSize().y}}function t(a){I=a?a:new c({x:F.getWidth(),y:F.getHeight()}),console.log(I.size),J=[j.create([0,0]),j.create([0,I.size.y]),j.create([I.size.x,I.size.y]),j.create([I.size.x,0])],d.init(I,h.locator)}function u(){return h.locate?d.locate():[[j.create(J[0]),j.create(J[1]),j.create(J[2]),j.create(J[3])]]}function v(a){function b(a){for(var b=a.length;b--;)a[b][0]+=f,a[b][1]+=g}function c(a){a[0].x+=f,a[0].y+=g,a[1].x+=f,a[1].y+=g}var d,e=F.getTopRight(),f=e.x,g=e.y;if(a&&(0!==f||0!==g)&&(a.line&&2===a.line.length&&c(a.line),a.boxes&&a.boxes.length>0))for(d=0;d0){if(a=N.filter(function(a){return!a.busy})[0],!a)return;G.attachData(a.imageData)}else G.attachData(I.data);G.grab()&&(a?(a.busy=!0,a.worker.postMessage({cmd:"process",imageData:a.imageData},[a.imageData.buffer])):x())}else x()}function z(){H=!1,function a(){H||(y(),O&&"LiveStream"==h.inputStream.type&&window.requestAnimFrame(a))}()}function A(a){function b(b){N.push(b),N.length>=h.numOfWorkers&&a()}var c;for(N=[],c=0;c0&&N.forEach(function(b){b.worker.postMessage({cmd:"setReaders",readers:a})})}var F,G,H,I,J,K,L,M={ctx:{image:null,overlay:null},dom:{image:null,overlay:null}},N=[],O=!0;return{init:function(a,b,c){return h=g.mergeObjects(h,a),c?(O=!1,n(c),b()):void p(b)},start:function(){z()},stop:function(){H=!0,N.forEach(function(a){a.worker.terminate(),console.log("Worker terminated!")}),N.length=0,"LiveStream"===h.inputStream.type&&(k.release(),F.clearEventHandlers())},pause:function(){H=!0},onDetected:function(a){i.subscribe("detected",a)},offDetected:function(a){i.unsubscribe("detected",a)},onProcessed:function(a){i.subscribe("processed",a)},offProcessed:function(a){i.unsubscribe("processed",a)},setReaders:function(a){E(a)},registerResultCollector:function(a){a&&"function"==typeof a.addResult&&(L=a)},canvas:M,decodeSingle:function(a,b){a=g.mergeObjects({inputStream:{type:"ImageStream",sequence:!1,size:800,src:a.src},numOfWorkers:1,locator:{halfSample:!1}},a),this.init(a,function(){i.once("processed",function(a){H=!0,b.call(null,a)},!0),z()})},ImageWrapper:c,ImageDebug:l,ResultCollector:m}}),c("quagga")});
+>>>>>>> bc7283003570f6aa9b9930de2e1208cd18656951
diff --git a/example/file_input_require.js b/example/file_input_require.js
index 91569d1..cf4655d 100644
--- a/example/file_input_require.js
+++ b/example/file_input_require.js
@@ -116,12 +116,13 @@ define(['quagga'], function(Quagga) {
singleChannel: false
},
locator: {
- patchSize: "medium",
- halfSample: true
+ patchSize: "large",
+ halfSample: true,
+ showCanvas: true
},
numOfWorkers: 0,
decoder: {
- readers: ["code_128_reader"],
+ readers: ["i2of5_reader"],
showFrequency: true,
showPattern: true
},
diff --git a/example/live_w_locator.html b/example/live_w_locator.html
index 72c8d19..739c505 100644
--- a/example/live_w_locator.html
+++ b/example/live_w_locator.html
@@ -41,6 +41,7 @@
+