diff --git a/Gruntfile.js b/Gruntfile.js
index bf51893..5c92a5a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -34,6 +34,7 @@ module.exports = function(grunt) {
},
"baseUrl" : "src",
"name" : "quagga",
+ "useStrict": true,
"out" : "dist/quagga.js",
"include" : ['quagga'],
"optimize" : "none",
diff --git a/README.md b/README.md
index 4524075..ccf7280 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
quaggaJS
========
-- [Changelog](#changelog) (2015-05-20)
+- [Changelog](#changelog) (2015-07-08)
## What is QuaggaJS?
@@ -80,12 +80,16 @@ version `quagga.min.js` and places both files in the `dist` folder.
You can check out the [examples][github_examples] to get an idea of how to
use QuaggaJS. Basically the library exposes the following API:
-### Quagga.init(config, callback)
+### Quagga.init(config, callback)
This method initializes the library for a given configuration `config` (see
-below) and invokes the `callback` when Quagga is ready to start. The
-initialization process also requests for camera access if real-time detection is
-configured.
+below) and invokes the `callback(err)` when Quagga has finished its
+bootstrapping phase. The initialization process also requests for camera
+access if real-time detection is configured. In case of an error, the `err`
+parameter is set and contains information about the cause. A potential cause
+may be the `inputStream.type` is set to `LiveStream`, but the browser does
+not support this API, or simply if the user denies the permission to use the
+camera.
```javascript
Quagga.init({
@@ -96,7 +100,11 @@ Quagga.init({
decoder : {
readers : ["code_128_reader"]
}
- }, function() {
+ }, function(err) {
+ if (err) {
+ console.log(err);
+ return
+ }
console.log("Initialization finished. Ready to start");
Quagga.start();
});
@@ -143,7 +151,8 @@ empty.
```javascript
{
"codeResult": {
- "code": "FANAVF1461710",
+ "code": "FANAVF1461710", // the decoded code as a string
+ "format": "code_128", // or code_39, codabar, ean_13, ean_8, upc_a, upc_e
"start": 355,
"end": 26,
"codeset": 100,
@@ -212,12 +221,19 @@ The default `config` object is set as followed:
```javascript
{
inputStream: { name: "Live",
- type: "LiveStream",
- constraints: {
- width: 640,
- height: 480,
- facing: "environment"
- }
+ type: "LiveStream",
+ constraints: {
+ width: 640,
+ height: 480,
+ facing: "environment"
+ },
+ area: { // defines rectangle of the detection/localization area
+ top: "0%", // top offset
+ right: "0%", // right offset
+ left: "0%", // left offset
+ bottom: "0%" // bottom offset
+ },
+ singleChannel: false // true: only the red color-channel is read
},
tracking: false,
debug: false,
@@ -263,11 +279,13 @@ locating-mechanism for more robust results.
```javascript
Quagga.decodeSingle({
- readers: ['code_128_reader'],
- locate: true, // try to locate the barcode in the image
- src: '/test/fixtures/code_128/image-001.jpg' // or 'data:image/jpg;base64,' + data
+ decoder: {
+ readers: ["code_128_reader"] // List of active readers
+ },
+ locate: true, // try to locate the barcode in the image
+ src: '/test/fixtures/code_128/image-001.jpg' // or 'data:image/jpg;base64,' + data
}, function(result){
- console.log(result);
+ console.log(result);
});
```
@@ -291,8 +309,96 @@ web-workers, and their restriction not to have access to the DOM, the
configuration must be explicitly set to `config.numOfWorkers = 0` in order to
work.
+## ResultCollector
+
+Quagga is not perfect by any means and may produce false positives from time
+to time. In order to find out which images produced those false positives,
+the built-in ``ResultCollector`` will support you and me helping squashing
+bugs in the implementation.
+
+### Creating a ``ResultCollector``
+
+You can easily create a new ``ResultCollector`` by calling its ``create``
+method with a configuration.
+
+```javascript
+var resultCollector = Quagga.ResultCollector.create({
+ capture: true, // keep track of the image producing this result
+ capacity: 20, // maximum number of results to store
+ blacklist: [ // list containing codes which should not be recorded
+ {code: "3574660239843", format: "ean_13"}],
+ filter: function(codeResult) {
+ // only store results which match this constraint
+ // returns true/false
+ // e.g.: return codeResult.format === "ean_13";
+ return true;
+ }
+});
+```
+
+### Using a ``ResultCollector``
+
+After creating a ``ResultCollector`` you have to attach it to Quagga by
+calling ``Quagga.registerResultCollector(resultCollector)``.
+
+### Reading results
+
+After a test/recording session, you can now print the collected results which
+do not fit into a certain schema. Calling ``getResults`` on the
+``resultCollector`` returns an ``Array`` containing objects with:
+
+```javascript
+{
+ codeResult: {}, // same as in onDetected event
+ frame: "data:image/png;base64,iVBOR..." // dataURL of the gray-scaled image
+}
+```
+
+The ``frame`` property is an internal representation of the image and
+therefore only available in gray-scale. The dataURL representation allows
+easy saving/rendering of the image.
+
+### Comparing results
+
+Now, having the frames available on disk, you can load each single image by
+calling ``decodeSingle`` with the same configuration as used during recording
+. In order to reproduce the exact same result, you have to make sure to turn
+on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.
+
## Changelog
+### 2015-07-08
+- Improvements
+ - Parameter tweaking to reduce false-positives significantly (for the
+ entire EAN and UPC family)
+ - Fixing bug in parity check for UPC-E codes
+ - Fixing bug in alignment for EAN-8 codes
+
+### 2015-07-06
+- Improvements
+ - Added `err` parameter to [Quagga.init()](#quaggainit) callback
+ function
+
+### 2015-06-21
+- Features
+ - Added ``singleChannel`` configuration to ``inputStream`` (in [config]
+ (#configobject))
+ - Added ``ResultCollector`` functionality (see [ResultCollector]
+ (#resultcollector))
+
+### 2015-06-13
+- Improvements
+ - Added ``format`` property to ``codeResult`` (in [result](#resultobject))
+
+### 2015-06-13
+- Improvements
+ - Added fixes for ``Code39Reader`` (trailing whitespace was missing)
+
+### 2015-06-09
+- Features
+ - Introduced the ``area`` property
+ - Ability to define a rectangle where localization/decoding should be applied
+
### 2015-05-20
- Improvements
- Making EAN and UPC readers even more restrictive
diff --git a/dist/quagga.js b/dist/quagga.js
index 0089a8d..1436e75 100644
--- a/dist/quagga.js
+++ b/dist/quagga.js
@@ -437,7 +437,7 @@ define("almond", function(){});
define(
'barcode_reader',[],function() {
-
+ "use strict";
function BarcodeReader() {
this._row = [];
@@ -600,6 +600,9 @@ define(
} else {
result.direction = BarcodeReader.DIRECTION.FORWARD;
}
+ if (result) {
+ result.format = self.FORMAT;
+ }
return result;
};
@@ -614,6 +617,11 @@ define(
}
return true;
};
+
+ Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
+ value: 'unknown',
+ writeable: false
+ });
BarcodeReader.DIRECTION = {
FORWARD : 1,
@@ -638,7 +646,7 @@ define(
"./barcode_reader"
],
function(BarcodeReader) {
-
+ "use strict";
function Code128Reader() {
BarcodeReader.call(this);
@@ -764,7 +772,8 @@ define(
[2, 3, 3, 1, 1, 1, 2]
]},
SINGLE_CODE_ERROR: {value: 1},
- AVG_CODE_ERROR: {value: 0.5}
+ AVG_CODE_ERROR: {value: 0.5},
+ FORMAT: {value: "code_128", writeable: false}
};
Code128Reader.prototype = Object.create(BarcodeReader.prototype, properties);
@@ -793,67 +802,17 @@ define(
} else {
if (counterPos === counter.length - 1) {
normalized = self._normalize(counter);
- 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 (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;
- }
- }
- return null;
- };
-
- Code128Reader.prototype._findEnd = function() {
- var counter = [0, 0, 0, 0, 0, 0, 0],
- i,
- self = this,
- offset = self._nextSet(self._row),
- isWhite = !self._row[offset],
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : 0,
- end : 0
- },
- 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, 13);
- error = self._matchPattern(normalized, self.CODE_PATTERN[self.STOP_CODE]);
- if (error < self.AVG_CODE_ERROR) {
- bestMatch.error = error;
- bestMatch.start = i - sum;
bestMatch.end = i;
return bestMatch;
}
-
- for ( j = 0; j < 5; j++) {
- counter[j] = counter[j + 2];
- }
- counter[5] = 0;
- counter[6] = 0;
- counterPos--;
} else {
counterPos++;
}
@@ -893,17 +852,19 @@ define(
sum += counter[j];
}
normalized = self._normalize(counter);
- 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 (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 (bestMatch.error < self.AVG_CODE_ERROR) {
- bestMatch.start = i - sum;
- bestMatch.end = i;
- return bestMatch;
}
for ( j = 0; j < 4; j++) {
@@ -1052,7 +1013,7 @@ define(
// find end bar
code.end = self._nextUnset(self._row, code.end);
- if (code.end === self._row.length) {
+ if(!self._verifyTrailingWhitespace(code)){
return null;
}
@@ -1063,9 +1024,15 @@ define(
return null;
}
+ if (!result.length) {
+ return null;
+ }
+
// remove last code from result (checksum)
result.splice(result.length - 1, 1);
+
+
return {
code : result.join(""),
start : startInfo.start,
@@ -1076,6 +1043,20 @@ define(
endInfo : code
};
};
+
+
+ BarcodeReader.prototype._verifyTrailingWhitespace = function(endInfo) {
+ var self = this,
+ trailingWhitespaceEnd;
+
+ trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
+ }
+ }
+ return null;
+ };
return (Code128Reader);
}
@@ -1088,7 +1069,7 @@ define(
"./barcode_reader"
],
function(BarcodeReader) {
-
+ "use strict";
function EANReader(opts) {
BarcodeReader.call(this, opts);
@@ -1124,8 +1105,9 @@ define(
[2, 1, 1, 3]
]},
CODE_FREQUENCY : {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
- SINGLE_CODE_ERROR: {value: 0.7},
- AVG_CODE_ERROR: {value: 0.3}
+ 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);
@@ -1158,18 +1140,20 @@ define(
} else {
if (counterPos === counter.length - 1) {
normalized = self._normalize(counter);
- for ( code = 0; code < coderange; code++) {
- error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
- if (error < bestMatch.error) {
- bestMatch.code = code;
- bestMatch.error = error;
+ 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;
}
- bestMatch.end = i;
- if (bestMatch.error > self.AVG_CODE_ERROR) {
- return null;
- }
- return bestMatch;
} else {
counterPos++;
}
@@ -1226,13 +1210,15 @@ define(
sum += counter[j];
}
normalized = self._normalize(counter);
- error = self._matchPattern(normalized, pattern);
+ if (normalized) {
+ error = self._matchPattern(normalized, pattern);
- if (error < epsilon) {
- bestMatch.error = error;
- bestMatch.start = i - sum;
- bestMatch.end = i;
- return bestMatch;
+ 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++) {
@@ -1416,7 +1402,7 @@ define(
/* global define */
define('image_loader',[],function() {
-
+ "use strict";
var ImageLoader = {};
ImageLoader.load = function(directory, callback, offset, size, sequence) {
@@ -1480,7 +1466,7 @@ define('image_loader',[],function() {
/* global define */
define('input_stream',["image_loader"], function(ImageLoader) {
-
+ "use strict";
var InputStream = {};
InputStream.createVideoStream = function(video) {
@@ -1489,7 +1475,9 @@ define('input_stream',["image_loader"], function(ImageLoader) {
_eventNames = ['canrecord', 'ended'],
_eventHandlers = {},
_calculatedWidth,
- _calculatedHeight;
+ _calculatedHeight,
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
function initSize() {
var width = video.videoWidth,
@@ -1497,6 +1485,9 @@ define('input_stream',["image_loader"], function(ImageLoader) {
_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;
}
that.getRealWidth = function() {
@@ -1589,6 +1580,24 @@ define('input_stream',["image_loader"], function(ImageLoader) {
}
};
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
+ };
+
+ that.getTopRight = function() {
+ return _topRight;
+ };
+
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
+ };
+
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
+
that.getFrame = function() {
return video;
};
@@ -1624,7 +1633,9 @@ define('input_stream',["image_loader"], function(ImageLoader) {
calculatedWidth,
calculatedHeight,
_eventNames = ['canrecord', 'ended'],
- _eventHandlers = {};
+ _eventHandlers = {},
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
function loadImages() {
loaded = false;
@@ -1634,6 +1645,8 @@ define('input_stream',["image_loader"], function(ImageLoader) {
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() {
@@ -1723,6 +1736,24 @@ define('input_stream',["image_loader"], function(ImageLoader) {
}
};
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
+ };
+
+ that.getTopRight = function() {
+ return _topRight;
+ };
+
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
+ };
+
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
+
that.getFrame = function() {
var frame;
@@ -1782,7 +1813,7 @@ define("typedefs", (function (global) {
/* global define */
define('subImage',["typedefs"], function() {
-
+ "use strict";
/**
* Construct representing a part of another {ImageWrapper}. Shares data
@@ -1879,7 +1910,7 @@ define('subImage',["typedefs"], function() {
/* global define, vec2 */
define('cluster',[],function() {
-
+ "use strict";
/**
* Creates a cluster for grouping similar orientations of datapoints
@@ -4224,7 +4255,7 @@ define("glMatrixAddon", ["glMatrix"], (function (global) {
/* global define */
define('array_helper',[],function() {
-
+ "use strict";
return {
init : function(arr, val) {
@@ -4311,7 +4342,7 @@ define('array_helper',[],function() {
define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrixAddon, ArrayHelper) {
-
+ "use strict";
/*
* cv_utils.js
* Collection of CV functions and libraries
@@ -4792,13 +4823,19 @@ define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster
};
- CVUtils.computeGray = function(imageData, outArray) {
- var l = imageData.length / 4;
- var i = 0;
- for ( i = 0; i < l; i++) {
- //outArray[i] = (0.299*imageData[i*4+0] + 0.587*imageData[i*4+1] + 0.114*imageData[i*4+2]);
+ CVUtils.computeGray = function(imageData, outArray, config) {
+ var l = (imageData.length / 4) | 0,
+ i,
+ singleChannel = config && config.singleChannel === true;
- outArray[i] = Math.floor(0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2]);
+ if (singleChannel) {
+ for (i = 0; i < l; i++) {
+ outArray[i] = imageData[i * 4 + 0];
+ }
+ } else {
+ for (i = 0; i < l; i++) {
+ outArray[i] = Math.floor(0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2]);
+ }
}
};
@@ -4955,21 +4992,64 @@ define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster
optimalPatchSize = findPatchSizeForDivisors(common);
if (!optimalPatchSize) {
optimalPatchSize = findPatchSizeForDivisors(this._computeDivisors(wideSide));
- throw new AdjustToSizeError("", optimalPatchSize);
+ if (!optimalPatchSize) {
+ optimalPatchSize = findPatchSizeForDivisors((this._computeDivisors(desiredPatchSize * nrOfPatches)));
+ }
}
return optimalPatchSize;
};
- function AdjustToSizeError(message, desiredPatchSize) {
- this.name = 'AdjustToSizeError';
- this.message = message || 'AdjustToSizeError';
- this.patchSize = desiredPatchSize;
- }
+ CVUtils._parseCSSDimensionValues = function(value) {
+ var dimension = {
+ value: parseFloat(value),
+ unit: value.indexOf("%") === value.length-1 ? "%" : "%"
+ };
+
+ return dimension;
+ };
+
+ CVUtils._dimensionsConverters = {
+ top: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.height * (dimension.value / 100));
+ }
+ },
+ right: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.width - (context.width * (dimension.value / 100)));
+ }
+ },
+ bottom: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.height - (context.height * (dimension.value / 100)));
+ }
+ },
+ left: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.width * (dimension.value / 100));
+ }
+ }
+ };
- AdjustToSizeError.prototype = Object.create(RangeError.prototype);
- AdjustToSizeError.prototype.constructor = AdjustToSizeError;
+ CVUtils.computeImageArea = function(inputWidth, inputHeight, area) {
+ var context = {width: inputWidth, height: inputHeight};
- CVUtils.AdjustToSizeError = AdjustToSizeError;
+ var parsedArea = Object.keys(area).reduce(function(result, key) {
+ var value = area[key],
+ parsed = CVUtils._parseCSSDimensionValues(value),
+ calculated = CVUtils._dimensionsConverters[key](parsed, context);
+
+ result[key] = calculated;
+ return result;
+ }, {});
+
+ return {
+ sx: parsedArea.left,
+ sy: parsedArea.top,
+ sw: parsedArea.right - parsedArea.left,
+ sh: parsedArea.bottom - parsedArea.top
+ };
+ };
return (CVUtils);
});
@@ -4985,7 +5065,7 @@ define('image_wrapper',[
],
function(SubImage, CVUtils, ArrayHelper) {
-
+ 'use strict';
/**
* Represents a basic image combining the data and size.
@@ -5406,7 +5486,7 @@ define('image_wrapper',[
* http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization
*/
define('tracer',[],function() {
-
+ "use strict";
var Tracer = {
searchDirections : [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]],
@@ -5515,7 +5595,7 @@ define('tracer',[],function() {
* http://www.codeproject.com/Tips/407172/Connected-Component-Labeling-and-Vectorization
*/
define('rasterizer',["tracer"], function(Tracer) {
-
+ "use strict";
var Rasterizer = {
createContour2D : function() {
@@ -5711,7 +5791,7 @@ define('rasterizer',["tracer"], function(Tracer) {
/* global define */
define('skeletonizer',[],function() {
-
+ "use strict";
/* @preserve ASM BEGIN */
function Skeletonizer(stdlib, foreign, buffer) {
@@ -5916,7 +5996,7 @@ define('skeletonizer',[],function() {
/* global define */
define('image_debug',[],function() {
-
+ "use strict";
return {
drawRect: function(pos, size, ctx, style){
@@ -5937,6 +6017,26 @@ define('image_debug',[],function() {
}
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;
}
};
@@ -6430,10 +6530,11 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
initBuffers();
initCanvas();
},
+
locate : function() {
var patchesFound,
- topLabels = [],
- boxes = [];
+ topLabels,
+ boxes;
if (_config.halfSample) {
CVUtils.halfSample(_inputImageWrapper, _currentImageWrapper);
@@ -6460,6 +6561,43 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
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;
+ }
+
+ 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;
+ }
+
+ throw new Error("Image dimensions do not comply with the current settings: Width (" +
+ width + " )and height (" + height +
+ ") must a multiple of " + patchSize.x);
}
};
});
@@ -6469,7 +6607,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
/* global define */
define('bresenham',["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper) {
-
+ "use strict";
var Bresenham = {};
var Slope = {
@@ -6584,6 +6722,7 @@ define('bresenham',["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper
max = result.max,
line = result.line,
slope,
+ slope2,
center = min + (max - min) / 2,
extrema = [],
currentDir,
@@ -6599,11 +6738,12 @@ define('bresenham',["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper
pos : 0,
val : line[0]
});
- for ( i = 0; i < line.length - 1; i++) {
+ for ( i = 0; i < line.length - 2; i++) {
slope = (line[i + 1] - line[i]);
- if (slope < rThreshold && line[i + 1] < (center*1.5)) {
+ slope2 = (line[i + 2] - line[i + 1]);
+ if ((slope + slope2) < rThreshold && line[i + 1] < (center*1.5)) {
dir = Slope.DIR.DOWN;
- } else if (slope > threshold && line[i + 1] > (center*0.5)) {
+ } else if ((slope + slope2) > threshold && line[i + 1] > (center*0.5)) {
dir = Slope.DIR.UP;
} else {
dir = currentDir;
@@ -6689,7 +6829,7 @@ define(
"./array_helper"
],
function(BarcodeReader, ArrayHelper) {
-
+ "use strict";
function Code39Reader() {
BarcodeReader.call(this);
@@ -6699,7 +6839,8 @@ define(
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: [0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A]},
- ASTERISK: {value: 0x094}
+ ASTERISK: {value: 0x094},
+ FORMAT: {value: "code_39", writeable: false}
};
Code39Reader.prototype = Object.create(BarcodeReader.prototype, properties);
@@ -6764,7 +6905,13 @@ define(
} while(decodedChar !== '*');
result.pop();
+ if (!result.length) {
+ return null;
+ }
+ if(!self._verifyTrailingWhitespace(lastStart, nextStart, counters)) {
+ return null;
+ }
return {
code : result.join(""),
@@ -6775,6 +6922,17 @@ define(
};
};
+ Code39Reader.prototype._verifyTrailingWhitespace = function(lastStart, nextStart, counters) {
+ var trailingWhitespaceEnd,
+ patternSize = ArrayHelper.sum(counters);
+
+ trailingWhitespaceEnd = nextStart - lastStart - patternSize;
+ if ((trailingWhitespaceEnd * 3) >= patternSize) {
+ return true;
+ }
+ return false;
+ };
+
Code39Reader.prototype._patternToChar = function(pattern) {
var i,
self = this;
@@ -6891,7 +7049,7 @@ define(
"./code_39_reader"
],
function(Code39Reader) {
-
+ "use strict";
function Code39VINReader() {
Code39Reader.call(this);
@@ -6951,7 +7109,7 @@ define(
"./barcode_reader"
],
function(BarcodeReader) {
-
+ "use strict";
function CodabarReader() {
BarcodeReader.call(this);
@@ -6965,7 +7123,8 @@ define(
START_END: {value: [0x01A, 0x029, 0x00B, 0x00E]},
MIN_ENCODED_CHARS: {value: 4},
MAX_ACCEPTABLE: {value: 2.0},
- PADDING: {value: 1.5}
+ PADDING: {value: 1.5},
+ FORMAT: {value: "codabar", writeable: false}
};
CodabarReader.prototype = Object.create(BarcodeReader.prototype, properties);
@@ -7264,13 +7423,17 @@ define(
"./ean_reader"
],
function(EANReader) {
-
+ "use strict";
function UPCReader() {
EANReader.call(this);
}
- UPCReader.prototype = Object.create(EANReader.prototype);
+ var properties = {
+ FORMAT: {value: "upc_a", writeable: false}
+ };
+
+ UPCReader.prototype = Object.create(EANReader.prototype, properties);
UPCReader.prototype.constructor = UPCReader;
UPCReader.prototype._decode = function() {
@@ -7295,13 +7458,17 @@ define(
"./ean_reader"
],
function(EANReader) {
-
+ "use strict";
function EAN8Reader() {
EANReader.call(this);
}
- EAN8Reader.prototype = Object.create(EANReader.prototype);
+ 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) {
@@ -7317,7 +7484,7 @@ define(
decodedCodes.push(code);
}
- code = self._findPattern(self.MIDDLE_PATTERN, code.end, true);
+ code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
if (code === null) {
return null;
}
@@ -7346,7 +7513,7 @@ define(
"./ean_reader"
],
function(EANReader) {
-
+ "use strict";
function UPCEReader() {
EANReader.call(this);
@@ -7356,7 +7523,8 @@ define(
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]}
+ 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}
};
UPCEReader.prototype = Object.create(EANReader.prototype, properties);
@@ -7375,13 +7543,13 @@ define(
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);
}
- self._determineParity(codeFrequency, result);
+ if (!self._determineParity(codeFrequency, result)) {
+ return null;
+ }
return code;
};
@@ -7396,10 +7564,11 @@ define(
if (codeFrequency === self.CODE_FREQUENCY[nrSystem][i]) {
result.unshift(nrSystem);
result.push(i);
- return;
+ return true;
}
}
}
+ return false;
};
UPCEReader.prototype._convertToUPCA = function(result) {
@@ -7475,7 +7644,7 @@ define('barcode_decoder',[
UPCReader,
EAN8Reader,
UPCEReader) {
-
+ "use strict";
var readers = {
code_128_reader: Code128Reader,
@@ -7501,8 +7670,7 @@ define('barcode_decoder',[
overlay : null
}
},
- _barcodeReaders = [],
- _barcodeReader = null;
+ _barcodeReaders = [];
initCanvas();
initReaders();
@@ -7587,13 +7755,10 @@ define('barcode_decoder',[
// check if inside image
extendLine(ext);
- while (ext > 1 && !inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
- ext -= Math.floor(ext/2);
+ while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0))) {
+ ext -= Math.ceil(ext/2);
extendLine(-ext);
}
- if (ext <= 1) {
- return null;
- }
return line;
}
@@ -7623,9 +7788,6 @@ define('barcode_decoder',[
for ( i = 0; i < _barcodeReaders.length && result === null; i++) {
result = _barcodeReaders[i].decodePattern(barcodeLine.line);
- if (result !== null) {
- _barcodeReader = _barcodeReaders[i];
- }
}
if(result === null){
return null;
@@ -7754,7 +7916,7 @@ define('barcode_decoder',[
/* global define */
define('frame_grabber',["cv_utils"], function(CVUtils) {
-
+ "use strict";
var FrameGrabber = {};
@@ -7762,29 +7924,26 @@ define('frame_grabber',["cv_utils"], function(CVUtils) {
var _that = {},
_streamConfig = inputStream.getConfig(),
_video_size = CVUtils.imageRef(inputStream.getRealWidth(), inputStream.getRealHeight()),
- _size =_streamConfig.size ? CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()) : _video_size,
- _sx = 0,
- _sy = 0,
- _dx = 0,
- _dy = 0,
- _sWidth,
- _dWidth,
- _sHeight,
- _dHeight,
- _canvas = null,
+ _canvasSize = inputStream.getCanvasSize(),
+ _size = CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()),
+ topRight = inputStream.getTopRight(),
+ _sx = topRight.x,
+ _sy = topRight.y,
+ _canvas,
_ctx = null,
_data = null;
- _sWidth = _video_size.x;
- _dWidth = _size.x;
- _sHeight = _video_size.y;
- _dHeight = _size.y;
-
_canvas = canvas ? canvas : document.createElement("canvas");
- _canvas.width = _size.x;
- _canvas.height = _size.y;
+ _canvas.width = _canvasSize.x;
+ _canvas.height = _canvasSize.y;
_ctx = _canvas.getContext("2d");
_data = new Uint8Array(_size.x * _size.y);
+ console.log("FrameGrabber", JSON.stringify({
+ size: _size,
+ topRight: topRight,
+ videoSize: _video_size,
+ canvasSize: _canvasSize
+ }));
/**
* Uses the given array as frame-buffer
@@ -7809,12 +7968,12 @@ define('frame_grabber',["cv_utils"], function(CVUtils) {
frame = inputStream.getFrame(),
ctxData;
if (frame) {
- _ctx.drawImage(frame, _sx, _sy, _sWidth, _sHeight, _dx, _dy, _dWidth, _dHeight);
- ctxData = _ctx.getImageData(0, 0, _size.x, _size.y).data;
+ _ctx.drawImage(frame, 0, 0, _canvasSize.x, _canvasSize.y);
+ ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if(doHalfSample){
CVUtils.grayAndHalfSampleFromCanvasData(ctxData, _size, _data);
} else {
- CVUtils.computeGray(ctxData, _data);
+ CVUtils.computeGray(ctxData, _data, _streamConfig);
}
return true;
} else {
@@ -7836,7 +7995,7 @@ define('frame_grabber',["cv_utils"], function(CVUtils) {
/* global define */
define('html_utils',[], function() {
-
+ "use strict";
function createNode(htmlStr) {
var temp = document.createElement('div');
@@ -7886,7 +8045,14 @@ define('config',[],function(){
minAspectRatio: 0,
maxAspectRatio: 100,
facing: "environment" // or user
- }
+ },
+ area: {
+ top: "0%",
+ right: "0%",
+ left: "0%",
+ bottom: "0%"
+ },
+ singleChannel: false // true: only the red color-channel is read
},
tracking: false,
debug: false,
@@ -7930,7 +8096,7 @@ define('config',[],function(){
/* global define */
define('events',[],function() {
-
+ "use strict";
var _events = function() {
var events = {};
@@ -8021,7 +8187,7 @@ define('events',[],function() {
/* global define, MediaStreamTrack */
define('camera_access',["html_utils"], function(HtmlUtils) {
-
+ "use strict";
var streamRef,
loadedDataHandler;
@@ -8032,11 +8198,15 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
* @param {Object} failure Callback
*/
function getUserMedia(constraints, success, failure) {
- navigator.getUserMedia(constraints, function(stream) {
- streamRef = stream;
- var videoSrc = (window.URL && window.URL.createObjectURL(stream)) || stream;
- success.apply(null, [videoSrc]);
- }, failure);
+ if (typeof navigator.getUserMedia !== 'undefined') {
+ navigator.getUserMedia(constraints, function (stream) {
+ streamRef = stream;
+ var videoSrc = (window.URL && window.URL.createObjectURL(stream)) || stream;
+ success.apply(null, [videoSrc]);
+ }, failure);
+ } else {
+ failure(new TypeError("getUserMedia not available"));
+ }
}
function loadedData(video, callback) {
@@ -8075,7 +8245,7 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
video.addEventListener('loadeddata', loadedDataHandler, false);
video.play();
}, function(e) {
- console.log(e);
+ callback(e);
});
}
@@ -8098,7 +8268,7 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
facing: "environment"
}, config);
- if ( typeof MediaStreamTrack.getSources !== 'undefined') {
+ if ( typeof MediaStreamTrack !== 'undefined' && typeof MediaStreamTrack.getSources !== 'undefined') {
MediaStreamTrack.getSources(function(sourceInfos) {
var videoSourceId;
for (var i = 0; i != sourceInfos.length; ++i) {
@@ -8157,8 +8327,68 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
};
});
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define('result_collector',["image_debug"], function(ImageDebug) {
+ "use strict";
+
+ function contains(codeResult, list) {
+ if (list) {
+ return list.some(function (item) {
+ return Object.keys(item).every(function (key) {
+ return item[key] === codeResult[key];
+ });
+ });
+ }
+ return false;
+ }
+
+ function passesFilter(codeResult, filter) {
+ if (typeof filter === 'function') {
+ return filter(codeResult);
+ }
+ return true;
+ }
+
+ return {
+ create: function(config) {
+ var canvas = document.createElement("canvas"),
+ ctx = canvas.getContext("2d"),
+ results = [],
+ capacity = config.capacity || 20,
+ capture = config.capture === true;
+
+ function matchesConstraints(codeResult) {
+ return capacity && codeResult && !contains(codeResult, config.blacklist) && passesFilter(codeResult, config.filter);
+ }
+
+ return {
+ addResult: function(data, imageSize, codeResult) {
+ var result = {};
+
+ if (matchesConstraints(codeResult)) {
+ capacity--;
+ result.codeResult = codeResult;
+ if (capture) {
+ canvas.width = imageSize.x;
+ canvas.height = imageSize.y;
+ ImageDebug.drawImage(data, imageSize, ctx);
+ result.frame = canvas.toDataURL();
+ }
+ results.push(result);
+ }
+ },
+ getResults: function() {
+ return results;
+ }
+ };
+ }
+ };
+});
+
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
-/* global define, vec2 */
+/* global define, vec2 */
define('quagga',[
@@ -8174,7 +8404,7 @@ define('quagga',[
"events",
"camera_access",
"image_debug",
- "cv_utils"],
+ "result_collector"],
function(Code128Reader,
EANReader,
InputStream,
@@ -8187,8 +8417,8 @@ function(Code128Reader,
Events,
CameraAccess,
ImageDebug,
- CVUtils) {
-
+ ResultCollector) {
+ "use strict";
var _inputStream,
_framegrabber,
@@ -8207,7 +8437,8 @@ function(Code128Reader,
_boxSize,
_decoder,
_workerPool = [],
- _onUIThread = true;
+ _onUIThread = true,
+ _resultCollector;
function initializeData(imageWrapper) {
initBuffers(imageWrapper);
@@ -8215,20 +8446,22 @@ function(Code128Reader,
}
function initConfig() {
- var vis = [{
- node : document.querySelector("div[data-controls]"),
- prop : _config.controls
- }, {
- node : _canvasContainer.dom.overlay,
- prop : _config.visual.show
- }];
-
- for (var i = 0; i < vis.length; i++) {
- if (vis[i].node) {
- if (vis[i].prop === true) {
- vis[i].node.style.display = "block";
- } else {
- vis[i].node.style.display = "none";
+ if (typeof document !== "undefined") {
+ var vis = [{
+ node: document.querySelector("div[data-controls]"),
+ prop: _config.controls
+ }, {
+ node: _canvasContainer.dom.overlay,
+ prop: _config.visual.show
+ }];
+
+ for (var i = 0; i < vis.length; i++) {
+ if (vis[i].node) {
+ if (vis[i].prop === true) {
+ vis[i].node.style.display = "block";
+ } else {
+ vis[i].node.style.display = "none";
+ }
}
}
}
@@ -8255,7 +8488,7 @@ function(Code128Reader,
if (!err) {
_inputStream.trigger("canrecord");
} else {
- console.log(err);
+ return cb(err);
}
});
}
@@ -8266,39 +8499,8 @@ function(Code128Reader,
_inputStream.addEventListener("canrecord", canRecord.bind(undefined, cb));
}
- function checkImageConstraints() {
- var patchSize,
- width = _inputStream.getWidth(),
- height = _inputStream.getHeight(),
- halfSample = _config.locator.halfSample ? 0.5 : 1,
- size = {
- x: Math.floor(width * halfSample),
- y: Math.floor(height * halfSample)
- };
-
- if (_config.locate) {
- try {
- console.log(size);
- patchSize = CVUtils.calculatePatchSize(_config.locator.patchSize, size);
- } catch (error) {
- if (error instanceof CVUtils.AdjustToSizeError) {
- _inputStream.setWidth(Math.floor(Math.floor(size.x/error.patchSize.x)*(1/halfSample)*error.patchSize.x));
- _inputStream.setHeight(Math.floor(Math.floor(size.y/error.patchSize.y)*(1/halfSample)*error.patchSize.y));
- patchSize = error.patchSize;
- }
- }
- console.log("Patch-Size: " + JSON.stringify(patchSize));
- if ((_inputStream.getWidth() % patchSize.x) === 0 && (_inputStream.getHeight() % patchSize.y) === 0) {
- return true;
- }
- }
- throw new Error("Image dimensions do not comply with the current settings: Width (" +
- width + " )and height (" + height +
- ") must a multiple of " + patchSize.x);
- }
-
function canRecord(cb) {
- checkImageConstraints();
+ BarcodeLocator.checkImageConstraints(_inputStream, _config.locator);
initCanvas();
_framegrabber = FrameGrabber.create(_inputStream, _canvasContainer.dom.image);
initConfig();
@@ -8320,35 +8522,37 @@ function(Code128Reader,
}
function initCanvas() {
- var $viewport = document.querySelector("#interactive.viewport");
- _canvasContainer.dom.image = document.querySelector("canvas.imgBuffer");
- if (!_canvasContainer.dom.image) {
- _canvasContainer.dom.image = document.createElement("canvas");
- _canvasContainer.dom.image.className = "imgBuffer";
- if($viewport && _config.inputStream.type == "ImageStream") {
- $viewport.appendChild(_canvasContainer.dom.image);
- }
- }
- _canvasContainer.ctx.image = _canvasContainer.dom.image.getContext("2d");
- _canvasContainer.dom.image.width = _inputStream.getWidth();
- _canvasContainer.dom.image.height = _inputStream.getHeight();
-
- _canvasContainer.dom.overlay = document.querySelector("canvas.drawingBuffer");
- if (!_canvasContainer.dom.overlay) {
- _canvasContainer.dom.overlay = document.createElement("canvas");
- _canvasContainer.dom.overlay.className = "drawingBuffer";
- if($viewport) {
- $viewport.appendChild(_canvasContainer.dom.overlay);
- }
- var clearFix = document.createElement("br");
- clearFix.setAttribute("clear", "all");
- if($viewport) {
- $viewport.appendChild(clearFix);
- }
- }
- _canvasContainer.ctx.overlay = _canvasContainer.dom.overlay.getContext("2d");
- _canvasContainer.dom.overlay.width = _inputStream.getWidth();
- _canvasContainer.dom.overlay.height = _inputStream.getHeight();
+ if (typeof document !== "undefined") {
+ var $viewport = document.querySelector("#interactive.viewport");
+ _canvasContainer.dom.image = document.querySelector("canvas.imgBuffer");
+ if (!_canvasContainer.dom.image) {
+ _canvasContainer.dom.image = document.createElement("canvas");
+ _canvasContainer.dom.image.className = "imgBuffer";
+ if ($viewport && _config.inputStream.type == "ImageStream") {
+ $viewport.appendChild(_canvasContainer.dom.image);
+ }
+ }
+ _canvasContainer.ctx.image = _canvasContainer.dom.image.getContext("2d");
+ _canvasContainer.dom.image.width = _inputStream.getCanvasSize().x;
+ _canvasContainer.dom.image.height = _inputStream.getCanvasSize().y;
+
+ _canvasContainer.dom.overlay = document.querySelector("canvas.drawingBuffer");
+ if (!_canvasContainer.dom.overlay) {
+ _canvasContainer.dom.overlay = document.createElement("canvas");
+ _canvasContainer.dom.overlay.className = "drawingBuffer";
+ if ($viewport) {
+ $viewport.appendChild(_canvasContainer.dom.overlay);
+ }
+ var clearFix = document.createElement("br");
+ clearFix.setAttribute("clear", "all");
+ if ($viewport) {
+ $viewport.appendChild(clearFix);
+ }
+ }
+ _canvasContainer.ctx.overlay = _canvasContainer.dom.overlay.getContext("2d");
+ _canvasContainer.dom.overlay.width = _inputStream.getCanvasSize().x;
+ _canvasContainer.dom.overlay.height = _inputStream.getCanvasSize().y;
+ }
}
function initBuffers(imageWrapper) {
@@ -8363,10 +8567,10 @@ function(Code128Reader,
console.log(_inputImageWrapper.size);
_boxSize = [
- vec2.create([20, _inputImageWrapper.size.y / 2 - 100]),
- vec2.create([20, _inputImageWrapper.size.y / 2 + 100]),
- vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 + 100]),
- vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 - 100])
+ vec2.create([0, 0]),
+ vec2.create([0, _inputImageWrapper.size.y]),
+ vec2.create([_inputImageWrapper.size.x, _inputImageWrapper.size.y]),
+ vec2.create([_inputImageWrapper.size.x, 0])
];
BarcodeLocator.init(_inputImageWrapper, _config.locator);
}
@@ -8375,7 +8579,64 @@ function(Code128Reader,
if (_config.locate) {
return BarcodeLocator.locate();
} else {
- return [_boxSize];
+ return [[
+ vec2.create(_boxSize[0]),
+ vec2.create(_boxSize[1]),
+ vec2.create(_boxSize[2]),
+ vec2.create(_boxSize[3])]];
+ }
+ }
+
+ function transformResult(result) {
+ var topRight = _inputStream.getTopRight(),
+ xOffset = topRight.x,
+ yOffset = topRight.y,
+ i;
+
+ if (!result || (xOffset === 0 && yOffset === 0)) {
+ return;
+ }
+
+
+ if (result.line && result.line.length === 2) {
+ moveLine(result.line);
+ }
+ if (result.boxes && result.boxes.length > 0) {
+ for (i = 0; i < result.boxes.length; i++) {
+ moveBox(result.boxes[i]);
+ }
+ }
+
+ function moveBox(box) {
+ var corner = box.length;
+
+ while(corner--) {
+ box[corner][0] += xOffset;
+ box[corner][1] += yOffset;
+ }
+ }
+
+ function moveLine(line) {
+ line[0].x += xOffset;
+ line[0].y += yOffset;
+ line[1].x += xOffset;
+ line[1].y += yOffset;
+ }
+ }
+
+ function publishResult(result, imageData) {
+ if (_onUIThread) {
+ transformResult(result);
+ if (imageData && result && result.codeResult) {
+ if (_resultCollector) {
+ _resultCollector.addResult(imageData, _inputStream.getCanvasSize(), result.codeResult);
+ }
+ }
+ }
+
+ Events.publish("processed", result);
+ if (result && result.codeResult) {
+ Events.publish("detected", result);
}
}
@@ -8388,14 +8649,10 @@ function(Code128Reader,
result = _decoder.decodeFromBoundingBoxes(boxes);
result = result || {};
result.boxes = boxes;
- Events.publish("processed", result);
- if (result && result.codeResult) {
- Events.publish("detected", result);
- }
+ publishResult(result, _inputImageWrapper.data);
} else {
- Events.publish("processed");
+ publishResult();
}
-
}
function update() {
@@ -8461,7 +8718,7 @@ function(Code128Reader,
function initWorker(cb) {
var blobURL,
workerThread = {
- worker: null,
+ worker: undefined,
imageData: new Uint8Array(_inputStream.getWidth() * _inputStream.getHeight()),
busy: true
};
@@ -8479,10 +8736,7 @@ function(Code128Reader,
} else if (e.data.event === 'processed') {
workerThread.imageData = new Uint8Array(e.data.imageData);
workerThread.busy = false;
- Events.publish("processed", e.data.result);
- if (e.data.result && e.data.result.codeResult) {
- Events.publish("detected", e.data.result);
- }
+ publishResult(e.data.result, workerThread.imageData);
}
};
@@ -8597,6 +8851,11 @@ function(Code128Reader,
setReaders: function(readers) {
setReaders(readers);
},
+ registerResultCollector: function(resultCollector) {
+ if (resultCollector && typeof resultCollector.addResult === 'function') {
+ _resultCollector = resultCollector;
+ }
+ },
canvas : _canvasContainer,
decodeSingle : function(config, resultCallback) {
config = HtmlUtils.mergeObjects({
@@ -8624,7 +8883,8 @@ function(Code128Reader,
Code128Reader : Code128Reader
},
ImageWrapper: ImageWrapper,
- ImageDebug: ImageDebug
+ ImageDebug: ImageDebug,
+ ResultCollector: ResultCollector
};
});
diff --git a/dist/quagga.min.js b/dist/quagga.min.js
index 70f3b86..712e26a 100644
--- a/dist/quagga.min.js
+++ b/dist/quagga.min.js
@@ -1,9 +1,9 @@
-/*! quagga 2015-05-28 */
+/*! quagga 2015-07-08 */
!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
*/
-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;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},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){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}};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;bc;c++)f[c]=f[c+2];f[5]=0,f[6]=0,j--}else j++;f[j]=1,i=!i}return null},b.prototype._findStart=function(){var a,b,c,d,e,f,g=[0,0,0,0,0,0],h=this,i=h._nextSet(h._row),j=!1,k=0,l={error:Number.MAX_VALUE,code:-1,start:0,end:0};for(a=i;ad;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),f.end===d._row.length?null:(j-=i*k[k.length-1],j%103!=k[k.length-1]?null:(h.splice(h.length-1,1),{code:h.join(""),start:e.start,end:f.end,codeset:a,startInfo:e,decodedCodes:l,endInfo:f})))},b}),d("ean_reader",["./barcode_reader"],function(a){function b(b){a.call(this,b)}var c={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:[.2*7,.2*7,.2*7,.2*7,.2*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:.7},AVG_CODE_ERROR:{value:.3}};return b.prototype=Object.create(a.prototype,c),b.prototype.constructor=b,b.prototype._decodeCode=function(a,b){var c,d,e,f,g=[0,0,0,0],h=this,i=a,j=!h._row[i],k=0,l={error:Number.MAX_VALUE,code:-1,start:a,end:a};for(b||(b=h.CODE_PATTERN.length),c=i;cd;d++)e=h._matchPattern(f,h.CODE_PATTERN[d]),eh.AVG_CODE_ERROR?null:l}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(){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}var c,d,e={},f=null,g=["canrecord","ended"],h={};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,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(){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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0,0,0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0]: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(){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){function d(a,b){this.name="AdjustToSizeError",this.message=a||"AdjustToSizeError",this.patchSize=b}var f={};return f.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=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},f.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++},f.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]}},f.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},f.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},f.determineOtsuThreshold=function(a,b){function d(a,b){var c,d=0;for(c=a;b>=c;c++)d+=h[c];return d}function e(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=d(0,k),i=d(k+1,p),j=g*i,0===j&&(j=1),l=e(0,k)*i,m=e(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<=d;d++)for(e=0;n>e;e++)m[d*n+e]=0,m[(o-1-d)*n+e]=0;for(d=r;o-r>d;d++)for(e=0;r>=e;e++)m[d*n+e]=0,m[d*n+(n-1-e)]=0;for(d=r+1;o-r-1>d;d++)for(e=r+1;n-r>e;e++)g=p[(d-r-1)*n+(e-r-1)],h=p[(d-r-1)*n+(e+r)],i=p[(d+r)*n+(e-r-1)],j=p[(d+r)*n+(e+r)],q=j-i-h+g,k=q/s,m[d*n+e]=l[d*n+e]>k+5?0:1},f.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}},f.DILATE=1,f.ERODE=2,f.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},f.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},f.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]},f.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]},f.countNonZero=function(a){for(var b=a.data.length,c=a.data,d=0;b--;)d+=c[b];return d},f.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}},f.computeGray=function(a,b){var c=a.length/4,d=0;for(d=0;c>d;d++)b[d]=Math.floor(.299*a[4*d+0]+.587*a[4*d+1]+.114*a[4*d+2])},f.loadImageArray=function(a,b,c){c||(c=document.createElement("canvas"));var d=new Image;d.callback=b,d.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 d=a.getImageData(0,0,this.width,this.height).data;f.computeGray(d,b),this.callback(b,{x:this.width,y:this.height},this)},d.src=a},f.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}},f.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},f._computeDivisors=function(a){var b,c=[],d=[];for(b=1;bb[d]?d++:c++;return e},f.calculatePatchSize=function(a,b){function c(a){for(var b=0,c=a[Math.floor(a.length/2)];b0&&(c=Math.abs(a[b]-n)>Math.abs(a[b-1]-n)?a[b-1]:a[b]),n/cj[l-1]/j[l]?{x:c,y:c}:null}var e,f=this._computeDivisors(b.x),g=this._computeDivisors(b.y),h=Math.max(b.x,b.y),i=this._computeIntersection(f,g),j=[8,10,15,20,32,60,80],k={"x-small":5,small:4,medium:3,large:2,"x-large":1},l=k[a]||k.medium,m=j[l],n=Math.floor(h/m);if(e=c(i),!e)throw e=c(this._computeDivisors(h)),new d("",e);return e},d.prototype=Object.create(RangeError.prototype),d.prototype.constructor=d,f.AdjustToSizeError=d,f}),d("image_wrapper",["subImage","cv_utils","array_helper"],function(a,b,c){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(){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){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(){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(){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))}}}),d("bresenham",["cv_utils","image_wrapper"],function(a,b){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=a.min,i=a.max,j=a.line,k=h+(i-h)/2,l=[],m=(i-h)/12,n=-m;for(c=j[0]>k?d.DIR.UP:d.DIR.DOWN,l.push({pos:0,val:j[0]}),f=0;fb&&j[f+1]<1.5*k?d.DIR.DOWN:b>m&&j[f+1]>.5*k?d.DIR.UP:c,c!==e&&(l.push({pos:f,val:j[f]}),c=e);for(l.push({pos:j.length,val:j[j.length-1]}),g=l[0].pos;gk?0:1;for(f=1;fl[f].val?l[f].val+(l[f+1].val-l[f].val)/3*2|0:l[f+1].val+(l[f].val-l[f+1].val)/3|0,g=l[f].pos;gm?0:1;return{line:j,threshold:m}},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(),{code:h.join(""),start:i.start,end:e,startInfo:i,decodedCodes:h}},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){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){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}};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),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){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]}};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):f|=0<<5-d,b.push(a.code),c.push(a)}return e._determineParity(f,b),a},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.floor(c/2),e(-c);return 1>=c?null: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=[],q=null;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){console.log(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.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("quagga",["code_128_reader","ean_reader","input_stream","image_wrapper","barcode_locator","barcode_decoder","frame_grabber","html_utils","config","events","camera_access","image_debug","cv_utils"],function(b,c,d,e,f,g,h,i,k,l,m,n,o){function p(a){w(a),L=g.create(k.decoder,J)}function q(){for(var a=[{node:document.querySelector("div[data-controls]"),prop:k.controls},{node:M.dom.overlay,prop:k.visual.show}],b=0;b0?B(function(){console.log("Workers created"),u(a)}):(p(),u(a))}function u(a){G.play(),a()}function v(){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"==k.inputStream.type&&a.appendChild(M.dom.image)),M.ctx.image=M.dom.image.getContext("2d"),M.dom.image.width=G.getWidth(),M.dom.image.height=G.getHeight(),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=G.getWidth(),M.dom.overlay.height=G.getHeight()}function w(a){J=a?a:new e({x:G.getWidth(),y:G.getHeight()}),console.log(J.size),K=[j.create([20,J.size.y/2-100]),j.create([20,J.size.y/2+100]),j.create([J.size.x-20,J.size.y/2+100]),j.create([J.size.x-20,J.size.y/2-100])],f.init(J,k.locator)}function x(){return k.locate?f.locate():[K]}function y(){var a,b;b=x(),b?(a=L.decodeFromBoundingBoxes(b),a=a||{},a.boxes=b,l.publish("processed",a),a&&a.codeResult&&l.publish("detected",a)):l.publish("processed")}function z(){var a;if(O){if(N.length>0){if(a=N.filter(function(a){return!a.busy})[0],!a)return;H.attachData(a.imageData)}else H.attachData(J.data);H.grab()&&(a?(a.busy=!0,a.worker.postMessage({cmd:"process",imageData:a.imageData},[a.imageData.buffer])):y())}else y()}function A(){I=!1,function a(){I||(z(),O&&"LiveStream"==k.inputStream.type&&window.requestAnimFrame(a))}()}function B(a){function b(b){N.push(b),N.length>=k.numOfWorkers&&a()}var c;for(N=[],c=0;c0&&N.forEach(function(b){b.worker.postMessage({cmd:"setReaders",readers:a})})}var 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 k=i.mergeObjects(k,a),c?(O=!1,p(c),b()):void r(b)},start:function(){A()},stop:function(){I=!0,N.forEach(function(a){a.worker.terminate(),console.log("Worker terminated!")}),N.length=0,"LiveStream"===k.inputStream.type&&(m.release(),G.clearEventHandlers())},pause:function(){I=!0},onDetected:function(a){l.subscribe("detected",a)},onProcessed:function(a){l.subscribe("processed",a)},setReaders:function(a){F(a)},canvas:M,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(){l.once("processed",function(a){I=!0,b.call(null,a)},!0),A()})},Reader:{EANReader:c,Code128Reader:b},ImageWrapper:e,ImageDebug:n}}),c("quagga")});
\ No newline at end of file
+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;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;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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0,0,0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0,0,0]: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=new glMatrixArrayType(glMatrixArrayType===Array?[0,0]: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=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,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,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 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;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","result_collector"],function(b,c,d,e,f,g,h,i,k,l,m,n,o){"use strict";function p(a){v(a),M=g.create(k.decoder,K)}function q(){if("undefined"!=typeof document)for(var a=[{node:document.querySelector("div[data-controls]"),prop:k.controls},{node:O.dom.overlay,prop:k.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"==k.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=[j.create([0,0]),j.create([0,K.size.y]),j.create([K.size.x,K.size.y]),j.create([K.size.x,0])],f.init(K,k.locator)}function w(){return k.locate?f.locate():[[j.create(L[0]),j.create(L[1]),j.create(L[2]),j.create(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"==k.inputStream.type&&window.requestAnimFrame(a))}()}function C(a){function b(b){P.push(b),P.length>=k.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;return{init:function(a,b,c){return k=i.mergeObjects(k,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"===k.inputStream.type&&(m.release(),H.clearEventHandlers())},pause:function(){J=!0},onDetected:function(a){l.subscribe("detected",a)},onProcessed:function(a){l.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(){l.once("processed",function(a){J=!0,b.call(null,a)},!0),B()})},Reader:{EANReader:c,Code128Reader:b},ImageWrapper:e,ImageDebug:n,ResultCollector:o}}),c("quagga")});
\ No newline at end of file
diff --git a/example/css/styles.css b/example/css/styles.css
index 16a76e6..a39a361 100644
--- a/example/css/styles.css
+++ b/example/css/styles.css
@@ -74,7 +74,7 @@
padding: 10px 0;
}
/* line 50, ../sass/_viewport.scss */
-#result_strip ul.thumbnails {
+#result_strip > ul {
padding: 0;
margin: 0;
list-style-type: none;
@@ -84,34 +84,34 @@
white-space: nowrap;
}
/* line 59, ../sass/_viewport.scss */
-#result_strip ul.thumbnails > li {
+#result_strip > ul > li {
display: inline-block;
vertical-align: middle;
width: 160px;
}
/* line 63, ../sass/_viewport.scss */
-#result_strip ul.thumbnails > li .thumbnail {
+#result_strip > ul > li .thumbnail {
padding: 5px;
margin: 4px;
border: 1px dashed #CCC;
}
/* line 68, ../sass/_viewport.scss */
-#result_strip ul.thumbnails > li .thumbnail img {
+#result_strip > ul > li .thumbnail img {
max-width: 140px;
}
/* line 71, ../sass/_viewport.scss */
-#result_strip ul.thumbnails > li .thumbnail .caption {
+#result_strip > ul > li .thumbnail .caption {
white-space: normal;
}
/* line 73, ../sass/_viewport.scss */
-#result_strip ul.thumbnails > li .thumbnail .caption h4 {
+#result_strip > ul > li .thumbnail .caption h4 {
text-align: center;
word-wrap: break-word;
height: 40px;
margin: 0px;
}
/* line 83, ../sass/_viewport.scss */
-#result_strip ul.thumbnails:after {
+#result_strip > ul:after {
content: "";
display: table;
clear: both;
diff --git a/example/file_input.html b/example/file_input.html
index f8f7297..a157123 100644
--- a/example/file_input.html
+++ b/example/file_input.html
@@ -77,14 +77,15 @@
Half-Sample
+
diff --git a/example/file_input.js b/example/file_input.js
index 3d374f4..dccbdcf 100644
--- a/example/file_input.js
+++ b/example/file_input.js
@@ -88,17 +88,16 @@ $(function() {
},
state: {
inputStream: {
- size: 640
+ size: 640,
+ singleChannel: false
},
locator: {
patchSize: "large",
halfSample: false
},
- numOfWorkers: 0,
+ numOfWorkers: 1,
decoder: {
- readers: ["code_128_reader"],
- showFrequency: true,
- showPattern: true
+ readers: ["code_128_reader"]
},
locate: true,
src: null
@@ -107,9 +106,31 @@ $(function() {
App.init();
+ function calculateRectFromArea(canvas, area) {
+ var canvasWidth = canvas.width,
+ canvasHeight = canvas.height,
+ top = parseInt(area.top)/100,
+ right = parseInt(area.right)/100,
+ bottom = parseInt(area.bottom)/100,
+ left = parseInt(area.left)/100;
+
+ top *= canvasHeight;
+ right = canvasWidth - canvasWidth*right;
+ bottom = canvasHeight - canvasHeight*bottom;
+ left *= canvasWidth;
+
+ return {
+ x: left,
+ y: top,
+ width: right - left,
+ height: bottom - top
+ };
+ }
+
Quagga.onProcessed(function(result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
- drawingCanvas = Quagga.canvas.dom.overlay;
+ drawingCanvas = Quagga.canvas.dom.overlay,
+ area;
if (result) {
if (result.boxes) {
@@ -128,7 +149,13 @@ $(function() {
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
}
- }
+
+ if (App.state.inputStream.area) {
+ area = calculateRectFromArea(drawingCanvas, App.state.inputStream.area);
+ drawingCtx.strokeStyle = "#0F0";
+ drawingCtx.strokeRect(area.x, area.y, area.width, area.height);
+ }
+ }
});
Quagga.onDetected(function(result) {
diff --git a/example/file_input_require.html b/example/file_input_require.html
index 5aeddaa..f597f97 100644
--- a/example/file_input_require.html
+++ b/example/file_input_require.html
@@ -68,24 +68,19 @@
diff --git a/example/file_input_require.js b/example/file_input_require.js
index e2492c6..91569d1 100644
--- a/example/file_input_require.js
+++ b/example/file_input_require.js
@@ -112,11 +112,12 @@ define(['quagga'], function(Quagga) {
},
state: {
inputStream: {
- size: 640
+ size: 640,
+ singleChannel: false
},
locator: {
- patchSize: "large",
- halfSample: false
+ patchSize: "medium",
+ halfSample: true
},
numOfWorkers: 0,
decoder: {
@@ -162,7 +163,7 @@ define(['quagga'], function(Quagga) {
$node = $('');
$node.find("img").attr("src", canvas.toDataURL());
- $node.find("h4.code").html(code);
+ $node.find("h4.code").html(code + " (" + result.codeResult.format + ")");
$("#result_strip ul.thumbnails").prepend($node);
});
});
\ No newline at end of file
diff --git a/example/live_w_locator.html b/example/live_w_locator.html
index c72eb5b..72c8d19 100644
--- a/example/live_w_locator.html
+++ b/example/live_w_locator.html
@@ -82,6 +82,7 @@
diff --git a/example/live_w_locator.js b/example/live_w_locator.js
index 6394254..d66a21d 100644
--- a/example/live_w_locator.js
+++ b/example/live_w_locator.js
@@ -1,17 +1,37 @@
$(function() {
+ var resultCollector = Quagga.ResultCollector.create({
+ capture: true,
+ capacity: 20,
+ blacklist: [{code: "3574660239843", format: "ean_13"}],
+ filter: function(codeResult) {
+ // only store results which match this constraint
+ // e.g.: codeResult
+ return true;
+ }
+ });
var App = {
init : function() {
- Quagga.init(this.state, function() {
+ var self = this;
+
+ Quagga.init(this.state, function(err) {
+ if (err) {
+ return self.handleError(err);
+ }
+ Quagga.registerResultCollector(resultCollector);
App.attachListeners();
Quagga.start();
});
},
+ handleError: function(err) {
+ console.log(err);
+ },
attachListeners: function() {
var self = this;
$(".controls").on("click", "button.stop", function(e) {
e.preventDefault();
Quagga.stop();
+ self._printCollectedResults();
});
$(".controls .reader-config-group").on("change", "input, select", function(e) {
@@ -25,6 +45,18 @@ $(function() {
self.setState(state, value);
});
},
+ _printCollectedResults: function() {
+ var results = resultCollector.getResults(),
+ $ul = $("#result_strip ul.collector");
+
+ results.forEach(function(result) {
+ var $li = $('');
+
+ $li.find("img").attr("src", result.frame);
+ $li.find("h4.code").html(result.codeResult.code + " (" + result.codeResult.format + ")");
+ $ul.prepend($li);
+ });
+ },
_accessByPath: function(obj, path, val) {
var parts = path.split('.'),
depth = parts.length,
diff --git a/example/sass/_viewport.scss b/example/sass/_viewport.scss
index fca73fa..f0d085b 100644
--- a/example/sass/_viewport.scss
+++ b/example/sass/_viewport.scss
@@ -47,7 +47,7 @@
border-bottom: 1px solid #EEE;
padding: 10px 0;
- ul.thumbnails{
+ & > ul {
padding: 0;
margin: 0;
list-style-type: none;
diff --git a/package.json b/package.json
index 7b3359e..b9a4e70 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "quagga",
- "version": "0.6.6",
+ "version": "0.6.13",
"description": "An advanced barcode-scanner written in JavaScript",
"main": "dist/quagga.js",
"devDependencies": {
@@ -42,6 +42,8 @@
"ean",
"code128",
"code39",
+ "codabar",
+ "upc",
"getusermedia",
"imageprocessing"
],
diff --git a/spec/barcode_locator.spec.js b/spec/barcode_locator.spec.js
new file mode 100644
index 0000000..68f540a
--- /dev/null
+++ b/spec/barcode_locator.spec.js
@@ -0,0 +1,131 @@
+
+define(['barcode_locator', 'config', 'html_utils'],
+ function(BarcodeLocator, Config, HtmlUtils){
+
+ describe('checkImageConstraints', function() {
+ var config,
+ inputStream,
+ imageSize,
+ streamConfig = {};
+
+ beforeEach(function() {
+ imageSize = {
+ x: 640, y: 480
+ };
+ config = HtmlUtils.mergeObjects({}, Config);
+ inputStream = {
+ getWidth: function() {
+ return imageSize.x;
+ },
+ getHeight: function() {
+ return imageSize.y;
+ },
+ setWidth: function() {},
+ setHeight: function() {},
+ setTopRight: function() {},
+ setCanvasSize: function() {},
+ getConfig: function() {
+ return streamConfig;
+ }
+ };
+ sinon.stub(inputStream, "setWidth", function(width) {
+ imageSize.x = width;
+ });
+ sinon.stub(inputStream, "setHeight", function(height) {
+ imageSize.y = height;
+ });
+ sinon.stub(inputStream, "setTopRight");
+ sinon.stub(inputStream, "setCanvasSize");
+ });
+
+ afterEach(function() {
+ inputStream.setWidth.restore();
+ inputStream.setHeight.restore();
+ });
+
+ it('should not adjust the image-size if not needed', function() {
+ var expected = {x: imageSize.x, y: imageSize.y};
+ BarcodeLocator.checkImageConstraints(inputStream, config.locator);
+ expect(inputStream.getWidth()).to.be.equal(expected.x);
+ expect(inputStream.getHeight()).to.be.equal(expected.y);
+ });
+
+ it('should adjust the image-size', function() {
+ var expected = {x: imageSize.x, y: imageSize.y};
+
+ config.locator.halfSample = true;
+ imageSize.y += 1;
+ BarcodeLocator.checkImageConstraints(inputStream, config.locator);
+ expect(inputStream.getWidth()).to.be.equal(expected.x);
+ expect(inputStream.getHeight()).to.be.equal(expected.y);
+ });
+
+ it('should adjust the image-size', function() {
+ var expected = {x: imageSize.x, y: imageSize.y};
+
+ imageSize.y += 1;
+ config.locator.halfSample = false;
+ BarcodeLocator.checkImageConstraints(inputStream, config.locator);
+ expect(inputStream.getHeight()).to.be.equal(expected.y);
+ expect(inputStream.getWidth()).to.be.equal(expected.x);
+ });
+
+ it("should take the defined area into account", function() {
+ var expectedSize = {
+ x: 420,
+ y: 315
+ },
+ expectedTopRight = {
+ x: 115,
+ y: 52
+ },
+ expectedCanvasSize = {
+ x: 640,
+ y: 480
+ };
+
+ streamConfig.area = {
+ top: "11%",
+ right: "15%",
+ bottom: "20%",
+ left: "18%"
+ };
+
+ config.locator.halfSample = false;
+ BarcodeLocator.checkImageConstraints(inputStream, config.locator);
+ expect(inputStream.getHeight()).to.be.equal(expectedSize.y);
+ expect(inputStream.getWidth()).to.be.equal(expectedSize.x);
+ expect(inputStream.setTopRight.getCall(0).args[0]).to.deep.equal(expectedTopRight);
+ expect(inputStream.setCanvasSize.getCall(0).args[0]).to.deep.equal(expectedCanvasSize);
+ });
+
+ it("should return the original size if set to full image", function() {
+ var expectedSize = {
+ x: 640,
+ y: 480
+ },
+ expectedTopRight = {
+ x: 0,
+ y: 0
+ },
+ expectedCanvasSize = {
+ x: 640,
+ y: 480
+ };
+
+ streamConfig.area = {
+ top: "0%",
+ right: "0%",
+ bottom: "0%",
+ left: "0%"
+ };
+
+ config.locator.halfSample = false;
+ BarcodeLocator.checkImageConstraints(inputStream, config.locator);
+ expect(inputStream.getHeight()).to.be.equal(expectedSize.y);
+ expect(inputStream.getWidth()).to.be.equal(expectedSize.x);
+ expect(inputStream.setTopRight.getCall(0).args[0]).to.deep.equal(expectedTopRight);
+ expect(inputStream.setCanvasSize.getCall(0).args[0]).to.deep.equal(expectedCanvasSize);
+ });
+ });
+});
diff --git a/spec/camera_access.spec.js b/spec/camera_access.spec.js
index a47a711..1320606 100644
--- a/spec/camera_access.spec.js
+++ b/spec/camera_access.spec.js
@@ -1,17 +1,15 @@
define(['camera_access'], function(CameraAccess){
var originalURL,
- originalUserMedia,
originalMediaStreamTrack,
video,
stream;
-
+
beforeEach(function() {
var tracks = [{
stop: function() {}
}];
originalURL = window.URL;
- originalUserMedia = window.getUserMedia;
originalMediaStreamTrack = window.MediaStreamTrack;
window.MediaStreamTrack = {};
window.URL = null;
@@ -23,10 +21,7 @@ define(['camera_access'], function(CameraAccess){
}
};
sinon.spy(tracks[0], "stop");
- navigator.getUserMedia = function(constraints, cb) {
- cb(stream);
- };
- sinon.spy(navigator, "getUserMedia");
+
video = {
src: null,
addEventListener: function() {
@@ -48,29 +43,80 @@ define(['camera_access'], function(CameraAccess){
});
afterEach(function() {
- navigator.getUserMedia = originalUserMedia;
window.URL = originalURL;
window.MediaStreamTrack = originalMediaStreamTrack;
});
- describe('request', function() {
- it('should request the camera', function(done) {
- CameraAccess.request(video, {}, function() {
- expect(navigator.getUserMedia.calledOnce).to.equal(true);
- expect(video.src).to.deep.equal(stream);
- done();
+ describe('success', function() {
+ beforeEach(function() {
+ sinon.stub(navigator, "getUserMedia", function(constraints, success) {
+ success(stream);
+ });
+ });
+
+ afterEach(function() {
+ navigator.getUserMedia.restore();
+ });
+ describe('request', function () {
+ it('should request the camera', function (done) {
+ CameraAccess.request(video, {}, function () {
+ expect(navigator.getUserMedia.calledOnce).to.equal(true);
+ expect(video.src).to.deep.equal(stream);
+ done();
+ });
+ });
+ });
+
+ describe('release', function () {
+ it('should release the camera', function (done) {
+ CameraAccess.request(video, {}, function () {
+ expect(video.src).to.deep.equal(stream);
+ CameraAccess.release();
+ expect(video.src.getVideoTracks()).to.have.length(1);
+ expect(video.src.getVideoTracks()[0].stop.calledOnce).to.equal(true);
+ done();
+ });
});
});
});
-
- describe('release', function() {
- it('should release the camera', function(done) {
- CameraAccess.request(video, {}, function() {
- expect(video.src).to.deep.equal(stream);
- CameraAccess.release();
- expect(video.src.getVideoTracks()).to.have.length(1);
- expect(video.src.getVideoTracks()[0].stop.calledOnce).to.equal(true);
- done();
+
+ describe('failure', function() {
+ describe("permission denied", function(){
+ before(function() {
+ sinon.stub(navigator, "getUserMedia", function(constraints, success, failure) {
+ failure(new Error());
+ });
+ });
+
+ after(function() {
+ navigator.getUserMedia.restore();
+ });
+
+ it('should throw if getUserMedia not available', function(done) {
+ CameraAccess.request(video, {}, function(err) {
+ expect(err).to.be.defined;
+ done();
+ });
+ });
+ });
+
+ describe("not available", function(){
+ var originalGetUserMedia;
+
+ before(function() {
+ originalGetUserMedia = navigator.getUserMedia;
+ navigator.getUserMedia = undefined;
+ });
+
+ after(function() {
+ navigator.getUserMedia = originalGetUserMedia;
+ });
+
+ it('should throw if getUserMedia not available', function(done) {
+ CameraAccess.request(video, {}, function(err) {
+ expect(err).to.be.defined;
+ done();
+ });
});
});
});
diff --git a/spec/cv_utils.spec.js b/spec/cv_utils.spec.js
index 2282b01..d490e9c 100644
--- a/spec/cv_utils.spec.js
+++ b/spec/cv_utils.spec.js
@@ -8,4 +8,138 @@ define(['cv_utils'], function(CVUtils){
expect(res.toVec2()[0]).to.equal(1);
});
});
+
+ describe('calculatePatchSize', function() {
+ it('should not throw an error in case of valid image size', function() {
+ var expected = {x: 32, y: 32},
+ patchSize = CVUtils.calculatePatchSize("medium", {x: 640, y: 480});
+
+ expect(patchSize).to.be.deep.equal(expected);
+ });
+
+ it('should thow an error if image size it not valid', function() {
+ var expected = {x: 32, y: 32},
+ patchSize = CVUtils.calculatePatchSize("medium", {x: 640, y: 480});
+
+ expect(patchSize).to.be.deep.equal(expected);
+ });
+ });
+
+ describe('_parseCSSDimensionValues', function() {
+ it("should convert a percentual value correctly", function() {
+ var expected = {
+ value: 10,
+ unit: "%"
+ },
+ result = CVUtils._parseCSSDimensionValues("10%");
+
+ expect(result).to.be.deep.equal(expected);
+ });
+
+ it("should convert a 0% value correctly", function() {
+ var expected = {
+ value: 100,
+ unit: "%"
+ },
+ result = CVUtils._parseCSSDimensionValues("100%");
+
+ expect(result).to.be.deep.equal(expected);
+ });
+
+ it("should convert a 100% value correctly", function() {
+ var expected = {
+ value: 0,
+ unit: "%"
+ },
+ result = CVUtils._parseCSSDimensionValues("0%");
+
+ expect(result).to.be.deep.equal(expected);
+ });
+
+ it("should convert a pixel value to percentage", function() {
+ var expected = {
+ value: 26.3,
+ unit: "%"
+ },
+ result = CVUtils._parseCSSDimensionValues("26.3px");
+
+ console.log(result);
+ expect(result).to.be.deep.equal(expected);
+ });
+ });
+
+ describe("_dimensionsConverters", function(){
+ var context;
+
+ beforeEach(function() {
+ context = {
+ width: 640,
+ height: 480
+ };
+ });
+
+ it("should convert a top-value correclty", function() {
+ var expected = 48,
+ result = CVUtils._dimensionsConverters.top({value: 10, unit: "%"}, context);
+
+ expect(result).to.be.equal(expected);
+ });
+
+ it("should convert a right-value correclty", function() {
+ var expected = 640 - 128,
+ result = CVUtils._dimensionsConverters.right({value: 20, unit: "%"}, context);
+
+ expect(result).to.be.equal(expected);
+ });
+
+ it("should convert a bottom-value correclty", function() {
+ var expected = 480 - 77,
+ result = CVUtils._dimensionsConverters.bottom({value: 16, unit: "%"}, context);
+
+ expect(result).to.be.equal(expected);
+ });
+
+ it("should convert a left-value correclty", function() {
+ var expected = 57,
+ result = CVUtils._dimensionsConverters.left({value: 9, unit: "%"}, context);
+
+ expect(result).to.be.equal(expected);
+ });
+ });
+
+ describe("computeImageArea", function() {
+ it("should calculate an image-area", function() {
+ var expected = {
+ sx: 115,
+ sy: 48,
+ sw: 429,
+ sh: 336
+ },
+ result = CVUtils.computeImageArea(640, 480, {
+ top: "10%",
+ right: "15%",
+ bottom: "20%",
+ left: "18%"
+ });
+
+ expect(result).to.be.deep.equal(expected);
+ });
+
+ it("should calculate full image-area", function() {
+ var expected = {
+ sx: 0,
+ sy: 0,
+ sw: 640,
+ sh: 480
+ },
+ result = CVUtils.computeImageArea(640, 480, {
+ top: "0%",
+ right: "0%",
+ bottom: "0%",
+ left: "0%"
+ });
+
+ expect(result).to.be.deep.equal(expected);
+ });
+ });
});
diff --git a/spec/integration.spec.js b/spec/integration.spec.js
index db4136d..c9c4765 100644
--- a/spec/integration.spec.js
+++ b/spec/integration.spec.js
@@ -35,6 +35,7 @@ define(['quagga', 'async'], function(Quagga, async) {
Quagga.decodeSingle(config, function(result) {
console.log(sample.name);
expect(result.codeResult.code).to.equal(sample.result);
+ expect(result.codeResult.format).to.equal(sample.format);
callback();
});
}, function() {
@@ -45,18 +46,22 @@ define(['quagga', 'async'], function(Quagga, async) {
describe("EAN", function() {
var config = generateConfig(),
- testSet = [
- {"name": "image-001.jpg", "result": "3574660239843"},
- {"name": "image-002.jpg", "result": "8032754490297"},
- {"name": "image-003.jpg", "result": "4006209700068"},
- /* {"name": "image-004.jpg", "result": "9002233139084"}, */
- /* {"name": "image-005.jpg", "result": "8004030044005"}, */
- {"name": "image-006.jpg", "result": "4003626011159"},
- {"name": "image-007.jpg", "result": "2111220009686"},
- {"name": "image-008.jpg", "result": "9000275609022"},
- {"name": "image-009.jpg", "result": "9004593978587"},
- {"name": "image-010.jpg", "result": "9002244845578"}
- ];
+ testSet = [
+ {"name": "image-001.jpg", "result": "3574660239843"},
+ {"name": "image-002.jpg", "result": "8032754490297"},
+ {"name": "image-003.jpg", "result": "4006209700068"},
+ /* {"name": "image-004.jpg", "result": "9002233139084"}, */
+ /* {"name": "image-005.jpg", "result": "8004030044005"}, */
+ {"name": "image-006.jpg", "result": "4003626011159"},
+ {"name": "image-007.jpg", "result": "2111220009686"},
+ {"name": "image-008.jpg", "result": "9000275609022"},
+ {"name": "image-009.jpg", "result": "9004593978587"},
+ {"name": "image-010.jpg", "result": "9002244845578"}
+ ];
+
+ testSet.forEach(function(sample) {
+ sample.format = "ean_13";
+ });
config.decoder.readers = ['ean_reader'];
_runTestSet(testSet, config);
@@ -65,17 +70,21 @@ define(['quagga', 'async'], function(Quagga, async) {
describe("Code128", function() {
var config = generateConfig(),
testSet = [
- {"name": "image-001.jpg", "result": "0001285112001000040801"},
- {"name": "image-002.jpg", "result": "FANAVF1461710"},
- {"name": "image-003.jpg", "result": "673023"},
- // {"name": "image-004.jpg", "result": "010210150301625334"},
- {"name": "image-005.jpg", "result": "419055603900009001012999"},
- {"name": "image-006.jpg", "result": "419055603900009001012999"},
- {"name": "image-007.jpg", "result": "T 000003552345"},
- {"name": "image-008.jpg", "result": "FANAVF1461710"},
- {"name": "image-009.jpg", "result": "0001285112001000040801"},
- {"name": "image-010.jpg", "result": "673023"}
- ];
+ {"name": "image-001.jpg", "result": "0001285112001000040801"},
+ {"name": "image-002.jpg", "result": "FANAVF1461710"},
+ // {"name": "image-003.jpg", "result": "673023"},
+ {"name": "image-004.jpg", "result": "010210150301625334"},
+ {"name": "image-005.jpg", "result": "419055603900009001012999"},
+ {"name": "image-006.jpg", "result": "419055603900009001012999"},
+ {"name": "image-007.jpg", "result": "T 000003552345"},
+ {"name": "image-008.jpg", "result": "FANAVF1461710"},
+ {"name": "image-009.jpg", "result": "0001285112001000040801"},
+ {"name": "image-010.jpg", "result": "673023"}
+ ];
+
+ testSet.forEach(function(sample) {
+ sample.format = "code_128";
+ });
config.decoder.readers = ['code_128_reader'];
_runTestSet(testSet, config);
@@ -84,17 +93,20 @@ define(['quagga', 'async'], function(Quagga, async) {
describe("Code39", function() {
var config = generateConfig(),
testSet = [
- {"name": "image-001.jpg", "result": "B3% $DAD$"},
- /*{"name": "image-002.jpg", "result": "QUAGGAJS"},*/
- {"name": "image-003.jpg", "result": "CODE39"},
- {"name": "image-004.jpg", "result": "QUAGGAJS"},
- /* {"name": "image-005.jpg", "result": "CODE39"}, */
- {"name": "image-006.jpg", "result": "2/4-8/16-32"},
- {"name": "image-007.jpg", "result": "2/4-8/16-32"},
- {"name": "image-008.jpg", "result": "CODE39"},
- {"name": "image-009.jpg", "result": "2/4-8/16-32"},
- {"name": "image-010.jpg", "result": "CODE39"}
- ];
+ {"name": "image-001.jpg", "result": "B3% $DAD$"},
+ {"name": "image-003.jpg", "result": "CODE39"},
+ {"name": "image-004.jpg", "result": "QUAGGAJS"},
+ {"name": "image-005.jpg", "result": "CODE39"},
+ {"name": "image-006.jpg", "result": "2/4-8/16-32"},
+ {"name": "image-007.jpg", "result": "2/4-8/16-32"},
+ {"name": "image-008.jpg", "result": "CODE39"},
+ {"name": "image-009.jpg", "result": "2/4-8/16-32"},
+ {"name": "image-010.jpg", "result": "CODE39"}
+ ];
+
+ testSet.forEach(function(sample) {
+ sample.format = "code_39";
+ });
config.decoder.readers = ['code_39_reader'];
_runTestSet(testSet, config);
@@ -103,17 +115,21 @@ define(['quagga', 'async'], function(Quagga, async) {
describe("EAN-8", function() {
var config = generateConfig(),
testSet = [
- {"name": "image-001.jpg", "result": "42191605"},
- {"name": "image-002.jpg", "result": "42191605"},
- {"name": "image-003.jpg", "result": "90311208"},
- {"name": "image-004.jpg", "result": "24057257"},
- {"name": "image-005.jpg", "result": "90162602"},
- {"name": "image-006.jpg", "result": "24036153"},
- {"name": "image-007.jpg", "result": "42176817"},
- /*{"name": "image-008.jpg", "result": "42191605"},*/
- {"name": "image-009.jpg", "result": "42242215"},
- {"name": "image-010.jpg", "result": "42184799"}
- ];
+ {"name": "image-001.jpg", "result": "42191605"},
+ {"name": "image-002.jpg", "result": "42191605"},
+ {"name": "image-003.jpg", "result": "90311208"},
+ {"name": "image-004.jpg", "result": "24057257"},
+ {"name": "image-005.jpg", "result": "90162602"},
+ {"name": "image-006.jpg", "result": "24036153"},
+ {"name": "image-007.jpg", "result": "42176817"},
+ {"name": "image-008.jpg", "result": "42191605"},
+ {"name": "image-009.jpg", "result": "42242215"},
+ {"name": "image-010.jpg", "result": "42184799"}
+ ];
+
+ testSet.forEach(function(sample) {
+ sample.format = "ean_8";
+ });
config.decoder.readers = ['ean_8_reader'];
_runTestSet(testSet, config);
@@ -127,13 +143,17 @@ define(['quagga', 'async'], function(Quagga, async) {
{"name": "image-003.jpg", "result": "882428015084"},
{"name": "image-004.jpg", "result": "882428015343"},
{"name": "image-005.jpg", "result": "882428015343"},
- {"name": "image-006.jpg", "result": "882428015046"},
+ /* {"name": "image-006.jpg", "result": "882428015046"}, */
{"name": "image-007.jpg", "result": "882428015084"},
{"name": "image-008.jpg", "result": "882428015046"},
{"name": "image-009.jpg", "result": "039047013551"},
{"name": "image-010.jpg", "result": "039047013551"}
];
+ testSet.forEach(function(sample) {
+ sample.format = "upc_a";
+ });
+
config.decoder.readers = ['upc_reader'];
_runTestSet(testSet, config);
});
@@ -153,6 +173,10 @@ define(['quagga', 'async'], function(Quagga, async) {
{"name": "image-010.jpg", "result": "01264904"}
];
+ testSet.forEach(function(sample) {
+ sample.format = "upc_e";
+ });
+
config.decoder.readers = ['upc_e_reader'];
_runTestSet(testSet, config);
});
@@ -167,11 +191,15 @@ define(['quagga', 'async'], function(Quagga, async) {
{"name": "image-005.jpg", "result": "C$399.95A"},
{"name": "image-006.jpg", "result": "B546745735B"},
{"name": "image-007.jpg", "result": "C$399.95A"},
- /* {"name": "image-008.jpg", "result": "01264904"}, */
+ {"name": "image-008.jpg", "result": "A16:9/4:3/3:2D"},
{"name": "image-009.jpg", "result": "C$399.95A"},
{"name": "image-010.jpg", "result": "C$399.95A"}
];
+ testSet.forEach(function(sample) {
+ sample.format = "codabar";
+ });
+
config.decoder.readers = ['codabar_reader'];
_runTestSet(testSet, config);
});
diff --git a/spec/result_collector.spec.js b/spec/result_collector.spec.js
new file mode 100644
index 0000000..dcb927a
--- /dev/null
+++ b/spec/result_collector.spec.js
@@ -0,0 +1,103 @@
+
+define(['result_collector', 'image_debug'], function(ResultCollector, ImageDebug) {
+ var canvasMock,
+ imageSize,
+ config;
+
+ beforeEach(function() {
+ imageSize = {x: 320, y: 240};
+ config = {
+ capture: true,
+ capacity: 20,
+ blacklist: [{code: "3574660239843", format: "ean_13"}],
+ filter: function(codeResult) {
+ return true;
+ }
+ };
+ canvasMock = {
+ getContext: function() {
+ return {};
+ },
+ toDataURL: sinon.spy(),
+ width: 0,
+ height: 0
+ };
+ sinon.stub(document, "createElement", function(type) {
+ if (type === "canvas") {
+ return canvasMock;
+ }
+ });
+ });
+
+ afterEach(function() {
+ document.createElement.restore();
+ });
+
+
+ describe('create', function () {
+ it("should return a new collector", function() {
+ ResultCollector.create(config);
+ expect(document.createElement.calledOnce).to.be.equal(true);
+ expect(document.createElement.getCall(0).args[0]).to.equal("canvas");
+ });
+ });
+
+ describe('addResult', function() {
+ beforeEach(function() {
+ sinon.stub(ImageDebug, "drawImage", function() {});
+ });
+
+ afterEach(function() {
+ ImageDebug.drawImage.restore();
+ });
+
+ it("should not add result if capacity is full", function(){
+ config.capacity = 1;
+ var collector = ResultCollector.create(config);
+ collector.addResult([], imageSize, {});
+ collector.addResult([], imageSize, {});
+ collector.addResult([], imageSize, {});
+ expect(collector.getResults()).to.have.length(1);
+ });
+
+ it("should only add results which match constraints", function(){
+ var collector = ResultCollector.create(config),
+ results;
+
+ collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
+ collector.addResult([], imageSize, {code: "3574660239843", format: "ean_13"});
+ collector.addResult([], imageSize, {code: "3574660239843", format: "code_128"});
+
+ results = collector.getResults();
+ expect(results).to.have.length(2);
+
+ results.forEach(function(result) {
+ expect(result).not.to.deep.equal(config.blacklist[0]);
+ });
+ });
+
+ it("should add result if no filter is set", function() {
+ delete config.filter;
+ var collector = ResultCollector.create(config);
+
+ collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
+ expect(collector.getResults()).to.have.length(1);
+ });
+
+ it("should not add results if filter returns false", function() {
+ config.filter = function(){ return false };
+ var collector = ResultCollector.create(config);
+
+ collector.addResult([], imageSize, {code: "423423443", format: "ean_13"});
+ expect(collector.getResults()).to.have.length(0);
+ });
+
+ it("should add result if no blacklist is set", function() {
+ delete config.blacklist;
+ var collector = ResultCollector.create(config);
+
+ collector.addResult([], imageSize, {code: "3574660239843", format: "ean_13"});
+ expect(collector.getResults()).to.have.length(1);
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/barcode_decoder.js b/src/barcode_decoder.js
index 2e518d0..8f94f03 100644
--- a/src/barcode_decoder.js
+++ b/src/barcode_decoder.js
@@ -49,8 +49,7 @@ define([
overlay : null
}
},
- _barcodeReaders = [],
- _barcodeReader = null;
+ _barcodeReaders = [];
initCanvas();
initReaders();
@@ -135,13 +134,10 @@ define([
// check if inside image
extendLine(ext);
- while (ext > 1 && !inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
- ext -= Math.floor(ext/2);
+ while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0))) {
+ ext -= Math.ceil(ext/2);
extendLine(-ext);
}
- if (ext <= 1) {
- return null;
- }
return line;
}
@@ -171,9 +167,6 @@ define([
for ( i = 0; i < _barcodeReaders.length && result === null; i++) {
result = _barcodeReaders[i].decodePattern(barcodeLine.line);
- if (result !== null) {
- _barcodeReader = _barcodeReaders[i];
- }
}
if(result === null){
return null;
diff --git a/src/barcode_locator.js b/src/barcode_locator.js
index 8d7b2bf..c131e82 100644
--- a/src/barcode_locator.js
+++ b/src/barcode_locator.js
@@ -486,10 +486,11 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
initBuffers();
initCanvas();
},
+
locate : function() {
var patchesFound,
- topLabels = [],
- boxes = [];
+ topLabels,
+ boxes;
if (_config.halfSample) {
CVUtils.halfSample(_inputImageWrapper, _currentImageWrapper);
@@ -516,6 +517,43 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
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;
+ }
+
+ 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;
+ }
+
+ throw new Error("Image dimensions do not comply with the current settings: Width (" +
+ width + " )and height (" + height +
+ ") must a multiple of " + patchSize.x);
}
};
});
diff --git a/src/barcode_reader.js b/src/barcode_reader.js
index aeea175..520d64e 100644
--- a/src/barcode_reader.js
+++ b/src/barcode_reader.js
@@ -166,6 +166,9 @@ define(
} else {
result.direction = BarcodeReader.DIRECTION.FORWARD;
}
+ if (result) {
+ result.format = self.FORMAT;
+ }
return result;
};
@@ -180,6 +183,11 @@ define(
}
return true;
};
+
+ Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
+ value: 'unknown',
+ writeable: false
+ });
BarcodeReader.DIRECTION = {
FORWARD : 1,
diff --git a/src/bresenham.js b/src/bresenham.js
index b9a789c..a59c163 100644
--- a/src/bresenham.js
+++ b/src/bresenham.js
@@ -117,6 +117,7 @@ define(["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper) {
max = result.max,
line = result.line,
slope,
+ slope2,
center = min + (max - min) / 2,
extrema = [],
currentDir,
@@ -132,11 +133,12 @@ define(["cv_utils", "image_wrapper"], function(CVUtils, ImageWrapper) {
pos : 0,
val : line[0]
});
- for ( i = 0; i < line.length - 1; i++) {
+ for ( i = 0; i < line.length - 2; i++) {
slope = (line[i + 1] - line[i]);
- if (slope < rThreshold && line[i + 1] < (center*1.5)) {
+ slope2 = (line[i + 2] - line[i + 1]);
+ if ((slope + slope2) < rThreshold && line[i + 1] < (center*1.5)) {
dir = Slope.DIR.DOWN;
- } else if (slope > threshold && line[i + 1] > (center*0.5)) {
+ } else if ((slope + slope2) > threshold && line[i + 1] > (center*0.5)) {
dir = Slope.DIR.UP;
} else {
dir = currentDir;
diff --git a/src/camera_access.js b/src/camera_access.js
index 44baaaa..bf4e831 100644
--- a/src/camera_access.js
+++ b/src/camera_access.js
@@ -13,11 +13,15 @@ define(["html_utils"], function(HtmlUtils) {
* @param {Object} failure Callback
*/
function getUserMedia(constraints, success, failure) {
- navigator.getUserMedia(constraints, function(stream) {
- streamRef = stream;
- var videoSrc = (window.URL && window.URL.createObjectURL(stream)) || stream;
- success.apply(null, [videoSrc]);
- }, failure);
+ if (typeof navigator.getUserMedia !== 'undefined') {
+ navigator.getUserMedia(constraints, function (stream) {
+ streamRef = stream;
+ var videoSrc = (window.URL && window.URL.createObjectURL(stream)) || stream;
+ success.apply(null, [videoSrc]);
+ }, failure);
+ } else {
+ failure(new TypeError("getUserMedia not available"));
+ }
}
function loadedData(video, callback) {
@@ -56,7 +60,7 @@ define(["html_utils"], function(HtmlUtils) {
video.addEventListener('loadeddata', loadedDataHandler, false);
video.play();
}, function(e) {
- console.log(e);
+ callback(e);
});
}
@@ -79,7 +83,7 @@ define(["html_utils"], function(HtmlUtils) {
facing: "environment"
}, config);
- if ( typeof MediaStreamTrack.getSources !== 'undefined') {
+ if ( typeof MediaStreamTrack !== 'undefined' && typeof MediaStreamTrack.getSources !== 'undefined') {
MediaStreamTrack.getSources(function(sourceInfos) {
var videoSourceId;
for (var i = 0; i != sourceInfos.length; ++i) {
diff --git a/src/codabar_reader.js b/src/codabar_reader.js
index a094071..389e4df 100644
--- a/src/codabar_reader.js
+++ b/src/codabar_reader.js
@@ -20,7 +20,8 @@ define(
START_END: {value: [0x01A, 0x029, 0x00B, 0x00E]},
MIN_ENCODED_CHARS: {value: 4},
MAX_ACCEPTABLE: {value: 2.0},
- PADDING: {value: 1.5}
+ PADDING: {value: 1.5},
+ FORMAT: {value: "codabar", writeable: false}
};
CodabarReader.prototype = Object.create(BarcodeReader.prototype, properties);
diff --git a/src/code_128_reader.js b/src/code_128_reader.js
index 4f5cef1..5327592 100644
--- a/src/code_128_reader.js
+++ b/src/code_128_reader.js
@@ -132,7 +132,8 @@ define(
[2, 3, 3, 1, 1, 1, 2]
]},
SINGLE_CODE_ERROR: {value: 1},
- AVG_CODE_ERROR: {value: 0.5}
+ AVG_CODE_ERROR: {value: 0.5},
+ FORMAT: {value: "code_128", writeable: false}
};
Code128Reader.prototype = Object.create(BarcodeReader.prototype, properties);
@@ -161,67 +162,17 @@ define(
} else {
if (counterPos === counter.length - 1) {
normalized = self._normalize(counter);
- 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 (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;
- }
- }
- return null;
- };
-
- Code128Reader.prototype._findEnd = function() {
- var counter = [0, 0, 0, 0, 0, 0, 0],
- i,
- self = this,
- offset = self._nextSet(self._row),
- isWhite = !self._row[offset],
- counterPos = 0,
- bestMatch = {
- error : Number.MAX_VALUE,
- code : -1,
- start : 0,
- end : 0
- },
- 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, 13);
- error = self._matchPattern(normalized, self.CODE_PATTERN[self.STOP_CODE]);
- if (error < self.AVG_CODE_ERROR) {
- bestMatch.error = error;
- bestMatch.start = i - sum;
bestMatch.end = i;
return bestMatch;
}
-
- for ( j = 0; j < 5; j++) {
- counter[j] = counter[j + 2];
- }
- counter[5] = 0;
- counter[6] = 0;
- counterPos--;
} else {
counterPos++;
}
@@ -261,17 +212,19 @@ define(
sum += counter[j];
}
normalized = self._normalize(counter);
- 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 (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 (bestMatch.error < self.AVG_CODE_ERROR) {
- bestMatch.start = i - sum;
- bestMatch.end = i;
- return bestMatch;
}
for ( j = 0; j < 4; j++) {
@@ -420,7 +373,7 @@ define(
// find end bar
code.end = self._nextUnset(self._row, code.end);
- if (code.end === self._row.length) {
+ if(!self._verifyTrailingWhitespace(code)){
return null;
}
@@ -431,9 +384,15 @@ define(
return null;
}
+ if (!result.length) {
+ return null;
+ }
+
// remove last code from result (checksum)
result.splice(result.length - 1, 1);
+
+
return {
code : result.join(""),
start : startInfo.start,
@@ -444,6 +403,20 @@ define(
endInfo : code
};
};
+
+
+ BarcodeReader.prototype._verifyTrailingWhitespace = function(endInfo) {
+ var self = this,
+ trailingWhitespaceEnd;
+
+ trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
+ if (trailingWhitespaceEnd < self._row.length) {
+ if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
+ return endInfo;
+ }
+ }
+ return null;
+ };
return (Code128Reader);
}
diff --git a/src/code_39_reader.js b/src/code_39_reader.js
index 9a9b985..a02fee5 100644
--- a/src/code_39_reader.js
+++ b/src/code_39_reader.js
@@ -17,7 +17,8 @@ define(
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: [0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A]},
- ASTERISK: {value: 0x094}
+ ASTERISK: {value: 0x094},
+ FORMAT: {value: "code_39", writeable: false}
};
Code39Reader.prototype = Object.create(BarcodeReader.prototype, properties);
@@ -82,7 +83,13 @@ define(
} while(decodedChar !== '*');
result.pop();
+ if (!result.length) {
+ return null;
+ }
+ if(!self._verifyTrailingWhitespace(lastStart, nextStart, counters)) {
+ return null;
+ }
return {
code : result.join(""),
@@ -93,6 +100,17 @@ define(
};
};
+ Code39Reader.prototype._verifyTrailingWhitespace = function(lastStart, nextStart, counters) {
+ var trailingWhitespaceEnd,
+ patternSize = ArrayHelper.sum(counters);
+
+ trailingWhitespaceEnd = nextStart - lastStart - patternSize;
+ if ((trailingWhitespaceEnd * 3) >= patternSize) {
+ return true;
+ }
+ return false;
+ };
+
Code39Reader.prototype._patternToChar = function(pattern) {
var i,
self = this;
diff --git a/src/config.js b/src/config.js
index c7959aa..7236180 100644
--- a/src/config.js
+++ b/src/config.js
@@ -12,7 +12,14 @@ define(function(){
minAspectRatio: 0,
maxAspectRatio: 100,
facing: "environment" // or user
- }
+ },
+ area: {
+ top: "0%",
+ right: "0%",
+ left: "0%",
+ bottom: "0%"
+ },
+ singleChannel: false // true: only the red color-channel is read
},
tracking: false,
debug: false,
diff --git a/src/cv_utils.js b/src/cv_utils.js
index 12ff3d0..edee715 100644
--- a/src/cv_utils.js
+++ b/src/cv_utils.js
@@ -484,13 +484,19 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
};
- CVUtils.computeGray = function(imageData, outArray) {
- var l = imageData.length / 4;
- var i = 0;
- for ( i = 0; i < l; i++) {
- //outArray[i] = (0.299*imageData[i*4+0] + 0.587*imageData[i*4+1] + 0.114*imageData[i*4+2]);
-
- outArray[i] = Math.floor(0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2]);
+ CVUtils.computeGray = function(imageData, outArray, config) {
+ var l = (imageData.length / 4) | 0,
+ i,
+ singleChannel = config && config.singleChannel === true;
+
+ if (singleChannel) {
+ for (i = 0; i < l; i++) {
+ outArray[i] = imageData[i * 4 + 0];
+ }
+ } else {
+ for (i = 0; i < l; i++) {
+ outArray[i] = Math.floor(0.299 * imageData[i * 4 + 0] + 0.587 * imageData[i * 4 + 1] + 0.114 * imageData[i * 4 + 2]);
+ }
}
};
@@ -647,21 +653,64 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
optimalPatchSize = findPatchSizeForDivisors(common);
if (!optimalPatchSize) {
optimalPatchSize = findPatchSizeForDivisors(this._computeDivisors(wideSide));
- throw new AdjustToSizeError("", optimalPatchSize);
+ if (!optimalPatchSize) {
+ optimalPatchSize = findPatchSizeForDivisors((this._computeDivisors(desiredPatchSize * nrOfPatches)));
+ }
}
return optimalPatchSize;
};
- function AdjustToSizeError(message, desiredPatchSize) {
- this.name = 'AdjustToSizeError';
- this.message = message || 'AdjustToSizeError';
- this.patchSize = desiredPatchSize;
- }
+ CVUtils._parseCSSDimensionValues = function(value) {
+ var dimension = {
+ value: parseFloat(value),
+ unit: value.indexOf("%") === value.length-1 ? "%" : "%"
+ };
- AdjustToSizeError.prototype = Object.create(RangeError.prototype);
- AdjustToSizeError.prototype.constructor = AdjustToSizeError;
+ return dimension;
+ };
- CVUtils.AdjustToSizeError = AdjustToSizeError;
+ CVUtils._dimensionsConverters = {
+ top: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.height * (dimension.value / 100));
+ }
+ },
+ right: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.width - (context.width * (dimension.value / 100)));
+ }
+ },
+ bottom: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.height - (context.height * (dimension.value / 100)));
+ }
+ },
+ left: function(dimension, context) {
+ if (dimension.unit === "%") {
+ return Math.floor(context.width * (dimension.value / 100));
+ }
+ }
+ };
+
+ CVUtils.computeImageArea = function(inputWidth, inputHeight, area) {
+ var context = {width: inputWidth, height: inputHeight};
+
+ var parsedArea = Object.keys(area).reduce(function(result, key) {
+ var value = area[key],
+ parsed = CVUtils._parseCSSDimensionValues(value),
+ calculated = CVUtils._dimensionsConverters[key](parsed, context);
+
+ result[key] = calculated;
+ return result;
+ }, {});
+
+ return {
+ sx: parsedArea.left,
+ sy: parsedArea.top,
+ sw: parsedArea.right - parsedArea.left,
+ sh: parsedArea.bottom - parsedArea.top
+ };
+ };
return (CVUtils);
});
diff --git a/src/ean_8_reader.js b/src/ean_8_reader.js
index b6b98da..f76642e 100644
--- a/src/ean_8_reader.js
+++ b/src/ean_8_reader.js
@@ -12,7 +12,11 @@ define(
EANReader.call(this);
}
- EAN8Reader.prototype = Object.create(EANReader.prototype);
+ 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) {
@@ -28,7 +32,7 @@ define(
decodedCodes.push(code);
}
- code = self._findPattern(self.MIDDLE_PATTERN, code.end, true);
+ code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
if (code === null) {
return null;
}
diff --git a/src/ean_reader.js b/src/ean_reader.js
index 249ee54..f207055 100644
--- a/src/ean_reader.js
+++ b/src/ean_reader.js
@@ -42,8 +42,9 @@ define(
[2, 1, 1, 3]
]},
CODE_FREQUENCY : {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
- SINGLE_CODE_ERROR: {value: 0.7},
- AVG_CODE_ERROR: {value: 0.3}
+ 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);
@@ -76,18 +77,20 @@ define(
} else {
if (counterPos === counter.length - 1) {
normalized = self._normalize(counter);
- for ( code = 0; code < coderange; code++) {
- error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
- if (error < bestMatch.error) {
- bestMatch.code = code;
- bestMatch.error = error;
+ 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;
}
- bestMatch.end = i;
- if (bestMatch.error > self.AVG_CODE_ERROR) {
- return null;
- }
- return bestMatch;
} else {
counterPos++;
}
@@ -144,13 +147,15 @@ define(
sum += counter[j];
}
normalized = self._normalize(counter);
- error = self._matchPattern(normalized, pattern);
+ if (normalized) {
+ error = self._matchPattern(normalized, pattern);
- if (error < epsilon) {
- bestMatch.error = error;
- bestMatch.start = i - sum;
- bestMatch.end = i;
- return bestMatch;
+ 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++) {
diff --git a/src/frame_grabber.js b/src/frame_grabber.js
index 830896a..92dcd7a 100644
--- a/src/frame_grabber.js
+++ b/src/frame_grabber.js
@@ -10,29 +10,26 @@ define(["cv_utils"], function(CVUtils) {
var _that = {},
_streamConfig = inputStream.getConfig(),
_video_size = CVUtils.imageRef(inputStream.getRealWidth(), inputStream.getRealHeight()),
- _size =_streamConfig.size ? CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()) : _video_size,
- _sx = 0,
- _sy = 0,
- _dx = 0,
- _dy = 0,
- _sWidth,
- _dWidth,
- _sHeight,
- _dHeight,
- _canvas = null,
+ _canvasSize = inputStream.getCanvasSize(),
+ _size = CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()),
+ topRight = inputStream.getTopRight(),
+ _sx = topRight.x,
+ _sy = topRight.y,
+ _canvas,
_ctx = null,
_data = null;
- _sWidth = _video_size.x;
- _dWidth = _size.x;
- _sHeight = _video_size.y;
- _dHeight = _size.y;
-
_canvas = canvas ? canvas : document.createElement("canvas");
- _canvas.width = _size.x;
- _canvas.height = _size.y;
+ _canvas.width = _canvasSize.x;
+ _canvas.height = _canvasSize.y;
_ctx = _canvas.getContext("2d");
_data = new Uint8Array(_size.x * _size.y);
+ console.log("FrameGrabber", JSON.stringify({
+ size: _size,
+ topRight: topRight,
+ videoSize: _video_size,
+ canvasSize: _canvasSize
+ }));
/**
* Uses the given array as frame-buffer
@@ -57,12 +54,12 @@ define(["cv_utils"], function(CVUtils) {
frame = inputStream.getFrame(),
ctxData;
if (frame) {
- _ctx.drawImage(frame, _sx, _sy, _sWidth, _sHeight, _dx, _dy, _dWidth, _dHeight);
- ctxData = _ctx.getImageData(0, 0, _size.x, _size.y).data;
+ _ctx.drawImage(frame, 0, 0, _canvasSize.x, _canvasSize.y);
+ ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if(doHalfSample){
CVUtils.grayAndHalfSampleFromCanvasData(ctxData, _size, _data);
} else {
- CVUtils.computeGray(ctxData, _data);
+ CVUtils.computeGray(ctxData, _data, _streamConfig);
}
return true;
} else {
diff --git a/src/image_debug.js b/src/image_debug.js
index e0fbde1..3eb9678 100644
--- a/src/image_debug.js
+++ b/src/image_debug.js
@@ -23,6 +23,26 @@ define(function() {
}
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;
}
};
diff --git a/src/input_stream.js b/src/input_stream.js
index 57a1a6e..182d873 100644
--- a/src/input_stream.js
+++ b/src/input_stream.js
@@ -11,7 +11,9 @@ define(["image_loader"], function(ImageLoader) {
_eventNames = ['canrecord', 'ended'],
_eventHandlers = {},
_calculatedWidth,
- _calculatedHeight;
+ _calculatedHeight,
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
function initSize() {
var width = video.videoWidth,
@@ -19,6 +21,9 @@ define(["image_loader"], function(ImageLoader) {
_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;
}
that.getRealWidth = function() {
@@ -111,6 +116,24 @@ define(["image_loader"], function(ImageLoader) {
}
};
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
+ };
+
+ that.getTopRight = function() {
+ return _topRight;
+ };
+
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
+ };
+
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
+
that.getFrame = function() {
return video;
};
@@ -146,7 +169,9 @@ define(["image_loader"], function(ImageLoader) {
calculatedWidth,
calculatedHeight,
_eventNames = ['canrecord', 'ended'],
- _eventHandlers = {};
+ _eventHandlers = {},
+ _topRight = {x: 0, y: 0},
+ _canvasSize = {x: 0, y: 0};
function loadImages() {
loaded = false;
@@ -156,6 +181,8 @@ define(["image_loader"], function(ImageLoader) {
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() {
@@ -245,6 +272,24 @@ define(["image_loader"], function(ImageLoader) {
}
};
+ that.setTopRight = function(topRight) {
+ _topRight.x = topRight.x;
+ _topRight.y = topRight.y;
+ };
+
+ that.getTopRight = function() {
+ return _topRight;
+ };
+
+ that.setCanvasSize = function(size) {
+ _canvasSize.x = size.x;
+ _canvasSize.y = size.y;
+ };
+
+ that.getCanvasSize = function() {
+ return _canvasSize;
+ };
+
that.getFrame = function() {
var frame;
diff --git a/src/quagga.js b/src/quagga.js
index b7ee257..09b5c99 100644
--- a/src/quagga.js
+++ b/src/quagga.js
@@ -1,5 +1,5 @@
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
-/* global define, vec2 */
+/* global define, vec2 */
define([
@@ -15,7 +15,7 @@ define([
"events",
"camera_access",
"image_debug",
- "cv_utils"],
+ "result_collector"],
function(Code128Reader,
EANReader,
InputStream,
@@ -28,7 +28,7 @@ function(Code128Reader,
Events,
CameraAccess,
ImageDebug,
- CVUtils) {
+ ResultCollector) {
"use strict";
var _inputStream,
@@ -48,7 +48,8 @@ function(Code128Reader,
_boxSize,
_decoder,
_workerPool = [],
- _onUIThread = true;
+ _onUIThread = true,
+ _resultCollector;
function initializeData(imageWrapper) {
initBuffers(imageWrapper);
@@ -56,20 +57,22 @@ function(Code128Reader,
}
function initConfig() {
- var vis = [{
- node : document.querySelector("div[data-controls]"),
- prop : _config.controls
- }, {
- node : _canvasContainer.dom.overlay,
- prop : _config.visual.show
- }];
-
- for (var i = 0; i < vis.length; i++) {
- if (vis[i].node) {
- if (vis[i].prop === true) {
- vis[i].node.style.display = "block";
- } else {
- vis[i].node.style.display = "none";
+ if (typeof document !== "undefined") {
+ var vis = [{
+ node: document.querySelector("div[data-controls]"),
+ prop: _config.controls
+ }, {
+ node: _canvasContainer.dom.overlay,
+ prop: _config.visual.show
+ }];
+
+ for (var i = 0; i < vis.length; i++) {
+ if (vis[i].node) {
+ if (vis[i].prop === true) {
+ vis[i].node.style.display = "block";
+ } else {
+ vis[i].node.style.display = "none";
+ }
}
}
}
@@ -96,7 +99,7 @@ function(Code128Reader,
if (!err) {
_inputStream.trigger("canrecord");
} else {
- console.log(err);
+ return cb(err);
}
});
}
@@ -107,39 +110,8 @@ function(Code128Reader,
_inputStream.addEventListener("canrecord", canRecord.bind(undefined, cb));
}
- function checkImageConstraints() {
- var patchSize,
- width = _inputStream.getWidth(),
- height = _inputStream.getHeight(),
- halfSample = _config.locator.halfSample ? 0.5 : 1,
- size = {
- x: Math.floor(width * halfSample),
- y: Math.floor(height * halfSample)
- };
-
- if (_config.locate) {
- try {
- console.log(size);
- patchSize = CVUtils.calculatePatchSize(_config.locator.patchSize, size);
- } catch (error) {
- if (error instanceof CVUtils.AdjustToSizeError) {
- _inputStream.setWidth(Math.floor(Math.floor(size.x/error.patchSize.x)*(1/halfSample)*error.patchSize.x));
- _inputStream.setHeight(Math.floor(Math.floor(size.y/error.patchSize.y)*(1/halfSample)*error.patchSize.y));
- patchSize = error.patchSize;
- }
- }
- console.log("Patch-Size: " + JSON.stringify(patchSize));
- if ((_inputStream.getWidth() % patchSize.x) === 0 && (_inputStream.getHeight() % patchSize.y) === 0) {
- return true;
- }
- }
- throw new Error("Image dimensions do not comply with the current settings: Width (" +
- width + " )and height (" + height +
- ") must a multiple of " + patchSize.x);
- }
-
function canRecord(cb) {
- checkImageConstraints();
+ BarcodeLocator.checkImageConstraints(_inputStream, _config.locator);
initCanvas();
_framegrabber = FrameGrabber.create(_inputStream, _canvasContainer.dom.image);
initConfig();
@@ -161,35 +133,37 @@ function(Code128Reader,
}
function initCanvas() {
- var $viewport = document.querySelector("#interactive.viewport");
- _canvasContainer.dom.image = document.querySelector("canvas.imgBuffer");
- if (!_canvasContainer.dom.image) {
- _canvasContainer.dom.image = document.createElement("canvas");
- _canvasContainer.dom.image.className = "imgBuffer";
- if($viewport && _config.inputStream.type == "ImageStream") {
- $viewport.appendChild(_canvasContainer.dom.image);
- }
- }
- _canvasContainer.ctx.image = _canvasContainer.dom.image.getContext("2d");
- _canvasContainer.dom.image.width = _inputStream.getWidth();
- _canvasContainer.dom.image.height = _inputStream.getHeight();
-
- _canvasContainer.dom.overlay = document.querySelector("canvas.drawingBuffer");
- if (!_canvasContainer.dom.overlay) {
- _canvasContainer.dom.overlay = document.createElement("canvas");
- _canvasContainer.dom.overlay.className = "drawingBuffer";
- if($viewport) {
- $viewport.appendChild(_canvasContainer.dom.overlay);
+ if (typeof document !== "undefined") {
+ var $viewport = document.querySelector("#interactive.viewport");
+ _canvasContainer.dom.image = document.querySelector("canvas.imgBuffer");
+ if (!_canvasContainer.dom.image) {
+ _canvasContainer.dom.image = document.createElement("canvas");
+ _canvasContainer.dom.image.className = "imgBuffer";
+ if ($viewport && _config.inputStream.type == "ImageStream") {
+ $viewport.appendChild(_canvasContainer.dom.image);
+ }
}
- var clearFix = document.createElement("br");
- clearFix.setAttribute("clear", "all");
- if($viewport) {
- $viewport.appendChild(clearFix);
+ _canvasContainer.ctx.image = _canvasContainer.dom.image.getContext("2d");
+ _canvasContainer.dom.image.width = _inputStream.getCanvasSize().x;
+ _canvasContainer.dom.image.height = _inputStream.getCanvasSize().y;
+
+ _canvasContainer.dom.overlay = document.querySelector("canvas.drawingBuffer");
+ if (!_canvasContainer.dom.overlay) {
+ _canvasContainer.dom.overlay = document.createElement("canvas");
+ _canvasContainer.dom.overlay.className = "drawingBuffer";
+ if ($viewport) {
+ $viewport.appendChild(_canvasContainer.dom.overlay);
+ }
+ var clearFix = document.createElement("br");
+ clearFix.setAttribute("clear", "all");
+ if ($viewport) {
+ $viewport.appendChild(clearFix);
+ }
}
+ _canvasContainer.ctx.overlay = _canvasContainer.dom.overlay.getContext("2d");
+ _canvasContainer.dom.overlay.width = _inputStream.getCanvasSize().x;
+ _canvasContainer.dom.overlay.height = _inputStream.getCanvasSize().y;
}
- _canvasContainer.ctx.overlay = _canvasContainer.dom.overlay.getContext("2d");
- _canvasContainer.dom.overlay.width = _inputStream.getWidth();
- _canvasContainer.dom.overlay.height = _inputStream.getHeight();
}
function initBuffers(imageWrapper) {
@@ -204,10 +178,10 @@ function(Code128Reader,
console.log(_inputImageWrapper.size);
_boxSize = [
- vec2.create([20, _inputImageWrapper.size.y / 2 - 100]),
- vec2.create([20, _inputImageWrapper.size.y / 2 + 100]),
- vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 + 100]),
- vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 - 100])
+ vec2.create([0, 0]),
+ vec2.create([0, _inputImageWrapper.size.y]),
+ vec2.create([_inputImageWrapper.size.x, _inputImageWrapper.size.y]),
+ vec2.create([_inputImageWrapper.size.x, 0])
];
BarcodeLocator.init(_inputImageWrapper, _config.locator);
}
@@ -216,7 +190,64 @@ function(Code128Reader,
if (_config.locate) {
return BarcodeLocator.locate();
} else {
- return [_boxSize];
+ return [[
+ vec2.create(_boxSize[0]),
+ vec2.create(_boxSize[1]),
+ vec2.create(_boxSize[2]),
+ vec2.create(_boxSize[3])]];
+ }
+ }
+
+ function transformResult(result) {
+ var topRight = _inputStream.getTopRight(),
+ xOffset = topRight.x,
+ yOffset = topRight.y,
+ i;
+
+ if (!result || (xOffset === 0 && yOffset === 0)) {
+ return;
+ }
+
+
+ if (result.line && result.line.length === 2) {
+ moveLine(result.line);
+ }
+ if (result.boxes && result.boxes.length > 0) {
+ for (i = 0; i < result.boxes.length; i++) {
+ moveBox(result.boxes[i]);
+ }
+ }
+
+ function moveBox(box) {
+ var corner = box.length;
+
+ while(corner--) {
+ box[corner][0] += xOffset;
+ box[corner][1] += yOffset;
+ }
+ }
+
+ function moveLine(line) {
+ line[0].x += xOffset;
+ line[0].y += yOffset;
+ line[1].x += xOffset;
+ line[1].y += yOffset;
+ }
+ }
+
+ function publishResult(result, imageData) {
+ if (_onUIThread) {
+ transformResult(result);
+ if (imageData && result && result.codeResult) {
+ if (_resultCollector) {
+ _resultCollector.addResult(imageData, _inputStream.getCanvasSize(), result.codeResult);
+ }
+ }
+ }
+
+ Events.publish("processed", result);
+ if (result && result.codeResult) {
+ Events.publish("detected", result);
}
}
@@ -229,14 +260,10 @@ function(Code128Reader,
result = _decoder.decodeFromBoundingBoxes(boxes);
result = result || {};
result.boxes = boxes;
- Events.publish("processed", result);
- if (result && result.codeResult) {
- Events.publish("detected", result);
- }
+ publishResult(result, _inputImageWrapper.data);
} else {
- Events.publish("processed");
+ publishResult();
}
-
}
function update() {
@@ -302,7 +329,7 @@ function(Code128Reader,
function initWorker(cb) {
var blobURL,
workerThread = {
- worker: null,
+ worker: undefined,
imageData: new Uint8Array(_inputStream.getWidth() * _inputStream.getHeight()),
busy: true
};
@@ -320,10 +347,7 @@ function(Code128Reader,
} else if (e.data.event === 'processed') {
workerThread.imageData = new Uint8Array(e.data.imageData);
workerThread.busy = false;
- Events.publish("processed", e.data.result);
- if (e.data.result && e.data.result.codeResult) {
- Events.publish("detected", e.data.result);
- }
+ publishResult(e.data.result, workerThread.imageData);
}
};
@@ -438,6 +462,11 @@ function(Code128Reader,
setReaders: function(readers) {
setReaders(readers);
},
+ registerResultCollector: function(resultCollector) {
+ if (resultCollector && typeof resultCollector.addResult === 'function') {
+ _resultCollector = resultCollector;
+ }
+ },
canvas : _canvasContainer,
decodeSingle : function(config, resultCallback) {
config = HtmlUtils.mergeObjects({
@@ -465,6 +494,7 @@ function(Code128Reader,
Code128Reader : Code128Reader
},
ImageWrapper: ImageWrapper,
- ImageDebug: ImageDebug
+ ImageDebug: ImageDebug,
+ ResultCollector: ResultCollector
};
});
diff --git a/src/result_collector.js b/src/result_collector.js
new file mode 100644
index 0000000..f29bf95
--- /dev/null
+++ b/src/result_collector.js
@@ -0,0 +1,59 @@
+/* jshint undef: true, unused: true, browser:true, devel: true */
+/* global define */
+
+define(["image_debug"], function(ImageDebug) {
+ "use strict";
+
+ function contains(codeResult, list) {
+ if (list) {
+ return list.some(function (item) {
+ return Object.keys(item).every(function (key) {
+ return item[key] === codeResult[key];
+ });
+ });
+ }
+ return false;
+ }
+
+ function passesFilter(codeResult, filter) {
+ if (typeof filter === 'function') {
+ return filter(codeResult);
+ }
+ return true;
+ }
+
+ return {
+ create: function(config) {
+ var canvas = document.createElement("canvas"),
+ ctx = canvas.getContext("2d"),
+ results = [],
+ capacity = config.capacity || 20,
+ capture = config.capture === true;
+
+ function matchesConstraints(codeResult) {
+ return capacity && codeResult && !contains(codeResult, config.blacklist) && passesFilter(codeResult, config.filter);
+ }
+
+ return {
+ addResult: function(data, imageSize, codeResult) {
+ var result = {};
+
+ if (matchesConstraints(codeResult)) {
+ capacity--;
+ result.codeResult = codeResult;
+ if (capture) {
+ canvas.width = imageSize.x;
+ canvas.height = imageSize.y;
+ ImageDebug.drawImage(data, imageSize, ctx);
+ result.frame = canvas.toDataURL();
+ }
+ results.push(result);
+ }
+ },
+ getResults: function() {
+ return results;
+ }
+ };
+ }
+ };
+});
diff --git a/src/upc_e_reader.js b/src/upc_e_reader.js
index d32c4b8..d2dfaf0 100644
--- a/src/upc_e_reader.js
+++ b/src/upc_e_reader.js
@@ -16,7 +16,8 @@ define(
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]}
+ 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}
};
UPCEReader.prototype = Object.create(EANReader.prototype, properties);
@@ -35,13 +36,13 @@ define(
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);
}
- self._determineParity(codeFrequency, result);
+ if (!self._determineParity(codeFrequency, result)) {
+ return null;
+ }
return code;
};
@@ -56,10 +57,11 @@ define(
if (codeFrequency === self.CODE_FREQUENCY[nrSystem][i]) {
result.unshift(nrSystem);
result.push(i);
- return;
+ return true;
}
}
}
+ return false;
};
UPCEReader.prototype._convertToUPCA = function(result) {
diff --git a/src/upc_reader.js b/src/upc_reader.js
index c09e863..cd6eef2 100644
--- a/src/upc_reader.js
+++ b/src/upc_reader.js
@@ -12,7 +12,11 @@ define(
EANReader.call(this);
}
- UPCReader.prototype = Object.create(EANReader.prototype);
+ var properties = {
+ FORMAT: {value: "upc_a", writeable: false}
+ };
+
+ UPCReader.prototype = Object.create(EANReader.prototype, properties);
UPCReader.prototype.constructor = UPCReader;
UPCReader.prototype._decode = function() {
diff --git a/test-main.js b/test-main.js
index c9da393..de7b44d 100644
--- a/test-main.js
+++ b/test-main.js
@@ -46,7 +46,8 @@ require.config({
'tracer': 'src/tracer',
'upc_e_reader': 'src/upc_e_reader',
'upc_reader': 'src/upc_reader',
- 'async': 'node_modules/async/lib/async'
+ 'async': 'node_modules/async/lib/async',
+ 'result_collector': 'src/result_collector'
},
deps: allTestFiles,
callback: window.__karma__.start