merged with remote master

pull/99/head
JauernigIT 9 years ago
commit 718a274393

@ -0,0 +1,33 @@
{
"plugins": [
"check-es2015-constants",
"transform-es2015-arrow-functions",
"transform-es2015-block-scoped-functions",
"transform-es2015-block-scoping",
["transform-es2015-classes", { "loose": true }],
["transform-es2015-computed-properties", { "loose": true }],
["transform-es2015-destructuring", { "loose": true }],
["transform-es2015-for-of", { "loose": true }],
"transform-es2015-function-name",
"transform-es2015-literals",
"transform-es2015-object-super",
"transform-es2015-parameters",
"transform-es2015-shorthand-properties",
["transform-es2015-spread", { "loose": true }],
"transform-es2015-sticky-regex",
["transform-es2015-template-literals", { "loose": true }],
"transform-es2015-unicode-regex",
"transform-es2015-typeof-symbol",
"transform-object-rest-spread",
"lodash"
],
"env": {
"commonjs": {
"plugins": [
["transform-es2015-modules-commonjs", { "loose": true }],
"add-module-exports"
]
}
}
}

@ -1,7 +1,8 @@
quaggaJS quaggaJS
======== ========
- [Changelog](#changelog) (2016-02-15) - [Changelog](#changelog) (2016-03-31)
- [Browser Support](#browser-support)
- [Installing](#installing) - [Installing](#installing)
- [Getting Started](#gettingstarted) - [Getting Started](#gettingstarted)
- [API](#api) - [API](#api)
@ -34,18 +35,30 @@ invariant to scale and rotation, whereas other libraries require the barcode to
be aligned with the viewport. be aligned with the viewport.
## Requirements ## <a name="browser-support">Browser Support</a>
In order to take full advantage of quaggaJS, the browser needs to support the Quagga makes use of many modern Web-APIs which are not implemented by all
`getUserMedia` API which is already implemented in recent versions of Firefox, browsers yet. There are two modes in which Quagga operates: 1. analyzing static
Chrome, IE (Edge) and Opera. The API is also available on their mobile images and 2. using a camera to decode the images from a live-stream. The latter
counterparts installed on Android (except IE). Safari does not allow the access requires the presence of the MediaDevices API. You can track the compatibility
to the camera yet, neither on desktop, nor on mobile. You can check of the used Web-APIs for each mode:
[caniuse][caniuse_getusermedia] for updates.
In cases where real-time decoding is not needed, or the platform does not - [Static Images](http://caniuse.com/#feat=webworkers,canvas,typedarrays,bloburls,blobbuilder)
support `getUserMedia` QuaggaJS is also capable of decoding image-files using - [Live Stream](http://caniuse.com/#feat=webworkers,canvas,typedarrays,bloburls,blobbuilder,stream)
the File API or other URL sources.
### Static Images
The following APIs need to be implemented in your browser:
- [webworkers](http://caniuse.com/#feat=webworkers)
- [canvas](http://caniuse.com/#feat=canvas)
- [typedarrays](http://caniuse.com/#feat=typedarrays)
- [bloburls](http://caniuse.com/#feat=bloburls)
- [blobbuilder](http://caniuse.com/#feat=blobbuilder)
### Live Stream
In addition to the APIs mentioned above:
- [MediaDevices](http://caniuse.com/#feat=stream)
## <a name="installing">Installing</a> ## <a name="installing">Installing</a>
@ -61,7 +74,8 @@ the __script__ tag.
And then import it as dependency in your project: And then import it as dependency in your project:
```javascript ```javascript
var Quagga = require('quagga'); import Quagga from 'quagga'; // ES6
const Quagga = require('quagga').default; // Common JS (important: default)
``` ```
Currently, the full functionality is only available through the browser. When Currently, the full functionality is only available through the browser. When
@ -79,7 +93,7 @@ You can also install QuaggaJS through __bower__:
### Script-Tag Anno 1998 ### Script-Tag Anno 1998
You can simply include `dist/quagga.min.js` in your project and you are ready You can simply include `dist/quagga.min.js` in your project and you are ready
to go. to go. The script exposes the library on the global namespace under `Quagga`.
## <a name="gettingstarted">Getting Started</a> ## <a name="gettingstarted">Getting Started</a>
@ -278,6 +292,7 @@ high-level properties:
numOfWorkers: 4, numOfWorkers: 4,
locate: true, locate: true,
inputStream: {...}, inputStream: {...},
frequency: 10,
decoder:{...}, decoder:{...},
locator: {...}, locator: {...},
debug: false, debug: false,
@ -323,7 +338,8 @@ The `inputStream` property defines the sources of images/videos within QuaggaJS.
constraints: { constraints: {
width: 640, width: 640,
height: 480, height: 480,
facing: "environment" facingMode: "environment",
deviceId: "7832475934759384534"
}, },
area: { // defines rectangle of the detection/localization area area: { // defines rectangle of the detection/localization area
top: "0%", // top offset top: "0%", // top offset
@ -340,8 +356,11 @@ First, the `type` property can be set to three different values:
depending on the use-case. Most probably, the default value is sufficient. depending on the use-case. Most probably, the default value is sufficient.
Second, the `constraint` key defines the physical dimensions of the input image Second, the `constraint` key defines the physical dimensions of the input image
and additional properties, such as `facing` which sets the source of the user's and additional properties, such as `facingMode` which sets the source of the
camera in case of multiple attached devices. user's camera in case of multiple attached devices. Additionally, if required,
the `deviceId` can be set if the selection of the camera is given to the user.
This can be easily achieved via
[MediaDevices.enumerateDevices()][enumerateDevices]
Thirdly, the `area` prop restricts the decoding area of the image. The values Thirdly, the `area` prop restricts the decoding area of the image. The values
are given in percentage, similar to the CSS style property when using are given in percentage, similar to the CSS style property when using
@ -354,6 +373,13 @@ color-channel is read instead of calculating the gray-scale values of the
source's RGB. This is useful in combination with the `ResultCollector` where source's RGB. This is useful in combination with the `ResultCollector` where
the gray-scale representations of the wrongly identified images are saved. the gray-scale representations of the wrongly identified images are saved.
### frequency
This top-level property controls the scan-frequency of the video-stream. It's
optional and defines the maximum number of scans per second. This renders
useful for cases where the scan-session is long-running and resources such as
CPU power are of concern.
### decoder ### decoder
QuaggaJS usually runs in a two-stage manner (`locate` is set to `true`) where, QuaggaJS usually runs in a two-stage manner (`locate` is set to `true`) where,
@ -363,13 +389,15 @@ options within the `decoder` are for debugging/visualization purposes only.
```javascript ```javascript
{ {
drawBoundingBox: false,
showFrequency: false,
drawScanline: true,
showPattern: false,
readers: [ readers: [
'code_128_reader' 'code_128_reader'
], ],
debug: {
drawBoundingBox: false,
showFrequency: false,
drawScanline: false,
showPattern: false
}
multiple: false multiple: false
} }
``` ```
@ -404,25 +432,53 @@ The remaining properties `drawBoundingBox`, `showFrequency`, `drawScanline` and
### locator ### locator
The `locator` config is only relevant if the `locate` flag is set to `true`.
It controls the behavior of the localization-process and needs to be adjusted
for each specific use-case. The default settings are simply a combination of
values which worked best during development.
Only two properties are relevant for the use in Quagga (`halfSample` and
`patchSize`) whereas the rest is only needed for development and debugging.
```javascript ```javascript
{ {
halfSample: true, halfSample: true,
patchSize: "medium", // x-small, small, medium, large, x-large patchSize: "medium", // x-small, small, medium, large, x-large
showCanvas: false, debug: {
showPatches: false, showCanvas: false,
showFoundPatches: false, showPatches: false,
showSkeleton: false, showFoundPatches: false,
showLabels: false, showSkeleton: false,
showPatchLabels: false, showLabels: false,
showRemainingPatchLabels: false, showPatchLabels: false,
boxFromPatches: { showRemainingPatchLabels: false,
showTransformed: false, boxFromPatches: {
showTransformedBox: false, showTransformed: false,
showBB: false showTransformedBox: false,
showBB: false
}
} }
} }
``` ```
The `halfSample` flag tells the locator-process whether it should operate on an
image scaled down (half width/height, quarter pixel-count ) or not. Turning
`halfSample` on reduces the processing-time significantly and also helps
finding a barcode pattern due to implicit smoothing.
It should be turned off in cases where the barcode is really small and the full
resolution is needed to find the position. It's recommended to keep it turned
on and use a higher resolution video-image if needed.
The second property `patchSize` defines the density of the search-grid. The
property accepts strings of the value `x-small`, `small`, `medium`, `large` and
`x-large`. The `patchSize` is proportional to the size of the scanned barcodes.
If you have really large barcodes which can be read close-up, then the use of
`large` or `x-large` is recommended. In cases where the barcode is further away
from the camera lens (lack of auto-focus, or small barcodes) then it's advised
to set the size to `small` or even `x-small`. For the latter it's also
recommended to crank up the resolution in order to find a barcode.
## Examples ## Examples
The following example takes an image `src` as input and prints the result on the The following example takes an image `src` as input and prints the result on the
@ -551,6 +607,10 @@ on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.
## <a name="changelog">Changelog</a> ## <a name="changelog">Changelog</a>
### 2016-03-31
Take a look at the release-notes (
[0.10.0](https://github.com/serratus/quaggaJS/releases/tag/v0.10.0))
### 2016-02-18 ### 2016-02-18
- Internal Changes - Internal Changes
@ -559,8 +619,8 @@ on the ``singleChannel`` flag in the configuration when using ``decodeSingle``.
### 2016-02-15 ### 2016-02-15
Take a look at the release-notes ([0.9.0] Take a look at the release-notes (
(https://github.com/serratus/quaggaJS/releases/tag/v0.9.0)) [0.9.0](https://github.com/serratus/quaggaJS/releases/tag/v0.9.0))
### 2015-11-22 ### 2015-11-22
@ -715,3 +775,4 @@ introduced to the API.
[oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/ [oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/
[github_examples]: https://serratus.github.io/quaggaJS/examples [github_examples]: https://serratus.github.io/quaggaJS/examples
[i2of5_wiki]: https://en.wikipedia.org/wiki/Interleaved_2_of_5 [i2of5_wiki]: https://en.wikipedia.org/wiki/Interleaved_2_of_5
[enumerateDevices]: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices

20143
dist/quagga.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -98,8 +98,7 @@ $(function() {
var values = value.split('x'); var values = value.split('x');
return { return {
width: parseInt(values[0]), width: parseInt(values[0]),
height: parseInt(values[1]), height: parseInt(values[1])
facing: "environment"
} }
} }
}, },
@ -118,7 +117,7 @@ $(function() {
constraints: { constraints: {
width: 640, width: 640,
height: 480, height: 480,
facing: "environment" // or user facingMode: "environment"
} }
}, },
locator: { locator: {

@ -1,4 +1,4 @@
var Quagga = require('../lib/quagga'); var Quagga = require('../lib/quagga').default;
Quagga.decodeSingle({ Quagga.decodeSingle({
src: "../test/fixtures/code_128/image-001.jpg", src: "../test/fixtures/code_128/image-001.jpg",
@ -18,4 +18,4 @@ Quagga.decodeSingle({
} else { } else {
console.log("not detected"); console.log("not detected");
} }
}); });

@ -15,23 +15,17 @@ module.exports = function(config) {
}, },
webpack: { webpack: {
module: { module: {
preLoaders: [ loaders: [{
{ test: /\.jsx?$/,
test: /\.js$/, exclude: /node_modules/,
exclude: [ loader: 'babel-loader'
/node_modules/ }]
],
loader: 'babel'
}
]
}, },
resolve: { resolve: {
extensions: ['', '.js', '.jsx'], modules: [
root: path.resolve(__dirname), path.resolve('./src/input/'),
alias: { 'node_modules'
'input_stream$': 'src/input/input_stream', ]
'frame_grabber$': 'src/input/frame_grabber'
}
}, },
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({

@ -14,31 +14,23 @@ module.exports = function(config) {
}, },
webpack: { webpack: {
module: { module: {
preLoaders: [ loaders: [{
{ test: /\.jsx?$/,
test: /\.js$/, exclude: [
exclude: [ path.resolve('node_modules/')
/node_modules/ ],
], loader: 'babel-loader'
loader: 'babel' }, {
}, test: /\.js$/,
{ include: path.resolve('src'),
test: /\.js$/, loader: 'babel-istanbul'
include: [ }]
path.resolve('src')
],
exclude: /node_modules/,
loader: 'isparta'
}
]
}, },
resolve: { resolve: {
extensions: ['', '.js', '.jsx'], modules: [
root: path.resolve(__dirname), path.resolve('./src/input/'),
alias: { 'node_modules'
'input_stream$': 'src/input/input_stream', ]
'frame_grabber$': 'src/input/frame_grabber'
}
}, },
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
@ -48,6 +40,7 @@ module.exports = function(config) {
}, },
plugins: [ plugins: [
'karma-chrome-launcher', 'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-coverage', 'karma-coverage',
'karma-mocha', 'karma-mocha',
'karma-chai', 'karma-chai',

File diff suppressed because one or more lines are too long

@ -1,14 +1,39 @@
{ {
"name": "quagga", "name": "quagga",
"version": "0.9.2", "version": "0.10.2",
"description": "An advanced barcode-scanner written in JavaScript", "description": "An advanced barcode-scanner written in JavaScript",
"main": "lib/quagga.js", "main": "lib/quagga.js",
"browser": "dist/quagga.min.js", "browser": "dist/quagga.min.js",
"devDependencies": { "devDependencies": {
"async": "^1.4.2", "async": "^1.4.2",
"babel-core": "^5.8.25", "babel-cli": "^6.5.1",
"babel-eslint": "^4.1.3", "babel-core": "^6.7.4",
"babel-loader": "^5.3.2", "babel-eslint": "^6.0.0",
"babel-istanbul-loader": "^0.1.0",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-plugin-check-es2015-constants": "^6.3.13",
"babel-plugin-lodash": "^2.2.1",
"babel-plugin-transform-es2015-arrow-functions": "^6.3.13",
"babel-plugin-transform-es2015-block-scoped-functions": "^6.3.13",
"babel-plugin-transform-es2015-block-scoping": "^6.3.13",
"babel-plugin-transform-es2015-classes": "^6.3.13",
"babel-plugin-transform-es2015-computed-properties": "^6.3.13",
"babel-plugin-transform-es2015-destructuring": "^6.3.13",
"babel-plugin-transform-es2015-for-of": "^6.3.13",
"babel-plugin-transform-es2015-function-name": "^6.3.13",
"babel-plugin-transform-es2015-literals": "^6.3.13",
"babel-plugin-transform-es2015-modules-commonjs": "^6.3.13",
"babel-plugin-transform-es2015-object-super": "^6.3.13",
"babel-plugin-transform-es2015-parameters": "^6.3.13",
"babel-plugin-transform-es2015-shorthand-properties": "^6.3.13",
"babel-plugin-transform-es2015-spread": "^6.3.13",
"babel-plugin-transform-es2015-sticky-regex": "^6.3.13",
"babel-plugin-transform-es2015-template-literals": "^6.3.13",
"babel-plugin-transform-es2015-typeof-symbol": "^6.3.13",
"babel-plugin-transform-es2015-unicode-regex": "^6.3.13",
"babel-plugin-transform-object-rest-spread": "^6.5.0",
"babel-plugin-transform-regenerator": "^6.3.13",
"chai": "^3.4.1", "chai": "^3.4.1",
"core-js": "^1.2.1", "core-js": "^1.2.1",
"cross-env": "^1.0.7", "cross-env": "^1.0.7",
@ -17,32 +42,35 @@
"grunt-cli": "^0.1.13", "grunt-cli": "^0.1.13",
"grunt-contrib-nodeunit": "^0.4.1", "grunt-contrib-nodeunit": "^0.4.1",
"grunt-karma": "^0.12.1", "grunt-karma": "^0.12.1",
"isparta-loader": "^1.0.0", "isparta-loader": "^2.0.0",
"karma": "^0.13.9", "karma": "^0.13.9",
"karma-chai": "0.1.0", "karma-chai": "0.1.0",
"karma-chrome-launcher": "^0.2.0", "karma-chrome-launcher": "^0.2.0",
"karma-coverage": "^0.5.2", "karma-coverage": "^0.5.2",
"karma-firefox-launcher": "^0.1.7",
"karma-mocha": "~0.2.0", "karma-mocha": "~0.2.0",
"karma-phantomjs-launcher": "^0.2.1", "karma-phantomjs-launcher": "^0.2.1",
"karma-sinon": "^1.0.4", "karma-sinon": "^1.0.4",
"karma-sinon-chai": "^1.1.0", "karma-sinon-chai": "^1.1.0",
"karma-source-map-support": "^1.1.0", "karma-source-map-support": "^1.1.0",
"karma-webpack": "^1.7.0", "karma-webpack": "^1.7.0",
"lolex": "^1.4.0",
"mocha": "^2.3.2", "mocha": "^2.3.2",
"phantomjs": "^1.9.18", "phantomjs": "^1.9.18",
"sinon": "^1.16.1", "sinon": "^1.16.1",
"webpack": "^1.12.2", "sinon-chai": "^2.8.0",
"webpack-core": "^0.6.8" "webpack": "^2.1.0-beta.4",
"webpack-sources": "^0.1.1"
}, },
"directories": { "directories": {
"doc": "doc" "doc": "doc"
}, },
"scripts": { "scripts": {
"test": "grunt test", "test": "cross-env BABEL_ENV=commonjs grunt test",
"integrationtest": "grunt integrationtest", "integrationtest": "grunt integrationtest",
"build:dev": "cross-env BUILD_ENV=development webpack", "build:dev": "cross-env BUILD_ENV=development webpack",
"build:prod": "cross-env BUILD_ENV=production webpack --config webpack.config.min.js && grunt uglyasm", "build:prod": "cross-env BUILD_ENV=production webpack --config webpack.config.min.js && grunt uglyasm",
"build:node": "cross-env BUILD_ENV=node webpack --config webpack.node.config.js", "build:node": "cross-env BABEL_ENV=commonjs BUILD_ENV=node webpack --config webpack.node.config.js",
"build": "npm run build:dev && npm run build:prod && npm run build:node", "build": "npm run build:dev && npm run build:prod && npm run build:node",
"watch": "cross-env BUILD_ENV=development webpack --watch", "watch": "cross-env BUILD_ENV=development webpack --watch",
"lint": "eslint src" "lint": "eslint src"
@ -74,9 +102,12 @@
}, },
"dependencies": { "dependencies": {
"get-pixels": "^3.2.3", "get-pixels": "^3.2.3",
"gl-matrix": "^2.3.1", "gl-mat2": "^1.0.0",
"lodash": "^3.10.1", "gl-vec2": "^1.0.0",
"gl-vec3": "^1.0.3",
"lodash": "^4.6.1",
"ndarray": "^1.0.18", "ndarray": "^1.0.18",
"ndarray-linear-interpolate": "^1.0.0" "ndarray-linear-interpolate": "^1.0.0",
"webrtc-adapter": "^1.0.6"
} }
} }

@ -1,5 +1,5 @@
var ConcatSource = require("webpack-core/lib/ConcatSource"); var ConcatSource = require("webpack-sources").ConcatSource;
var OriginalSource = require("webpack-core/lib/OriginalSource"); var OriginalSource = require("webpack-sources").OriginalSource;
function MyUmdPlugin(options) { function MyUmdPlugin(options) {
this.name = options.library; this.name = options.library;
@ -13,11 +13,11 @@ MyUmdPlugin.prototype.apply = function(compiler) {
return new ConcatSource(new OriginalSource( return new ConcatSource(new OriginalSource(
"(function webpackUniversalModuleDefinition(root, factory) {\n" + "(function webpackUniversalModuleDefinition(root, factory) {\n" +
" if(typeof exports === 'object' && typeof module === 'object')\n" + " if(typeof exports === 'object' && typeof module === 'object')\n" +
" module.exports = factory(factory.toString());\n" + " module.exports = factory(factory.toString()).default;\n" +
" else if(typeof exports === 'object')\n" + " else if(typeof exports === 'object')\n" +
" exports[\"" + this.name + "\"] = factory(factory.toString());\n" + " exports[\"" + this.name + "\"] = factory(factory.toString()).default;\n" +
" else\n" + " else\n" +
" root[\"" + this.name + "\"] = factory(factory.toString());\n" + " root[\"" + this.name + "\"] = factory(factory.toString()).default;\n" +
"})(this, function(__factorySource__) {\nreturn ", "webpack/myModuleDefinition"), source, "\n});\n"); "})(this, function(__factorySource__) {\nreturn ", "webpack/myModuleDefinition"), source, "\n});\n");
}.bind(this)); }.bind(this));
mainTemplate.plugin("global-hash-paths", function(paths) { mainTemplate.plugin("global-hash-paths", function(paths) {

@ -1,4 +1,7 @@
import {vec2} from 'gl-matrix'; const vec2 = {
clone: require('gl-vec2/clone'),
dot: require('gl-vec2/dot')
}
/** /**
* Creates a cluster for grouping similar orientations of datapoints * Creates a cluster for grouping similar orientations of datapoints
*/ */

@ -1,15 +1,18 @@
import Cluster2 from './cluster'; import Cluster2 from './cluster';
import ArrayHelper from './array_helper'; import ArrayHelper from './array_helper';
import {vec2, vec3} from 'gl-matrix'; const vec2 = {
clone: require('gl-vec2/clone'),
var CVUtils = {}; };
const vec3 = {
clone: require('gl-vec3/clone'),
};
/** /**
* @param x x-coordinate * @param x x-coordinate
* @param y y-coordinate * @param y y-coordinate
* @return ImageReference {x,y} Coordinate * @return ImageReference {x,y} Coordinate
*/ */
CVUtils.imageRef = function(x, y) { export function imageRef(x, y) {
var that = { var that = {
x: x, x: x,
y: y, y: y,
@ -32,7 +35,7 @@ CVUtils.imageRef = function(x, y) {
* Computes an integral image of a given grayscale image. * Computes an integral image of a given grayscale image.
* @param imageDataContainer {ImageDataContainer} the image to be integrated * @param imageDataContainer {ImageDataContainer} the image to be integrated
*/ */
CVUtils.computeIntegralImage2 = function(imageWrapper, integralWrapper) { export function computeIntegralImage2(imageWrapper, integralWrapper) {
var imageData = imageWrapper.data; var imageData = imageWrapper.data;
var width = imageWrapper.size.x; var width = imageWrapper.size.x;
var height = imageWrapper.size.y; var height = imageWrapper.size.y;
@ -75,7 +78,7 @@ CVUtils.computeIntegralImage2 = function(imageWrapper, integralWrapper) {
} }
}; };
CVUtils.computeIntegralImage = function(imageWrapper, integralWrapper) { export function computeIntegralImage(imageWrapper, integralWrapper) {
var imageData = imageWrapper.data; var imageData = imageWrapper.data;
var width = imageWrapper.size.x; var width = imageWrapper.size.x;
var height = imageWrapper.size.y; var height = imageWrapper.size.y;
@ -97,7 +100,7 @@ CVUtils.computeIntegralImage = function(imageWrapper, integralWrapper) {
} }
}; };
CVUtils.thresholdImage = function(imageWrapper, threshold, targetWrapper) { export function thresholdImage(imageWrapper, threshold, targetWrapper) {
if (!targetWrapper) { if (!targetWrapper) {
targetWrapper = imageWrapper; targetWrapper = imageWrapper;
} }
@ -108,7 +111,7 @@ CVUtils.thresholdImage = function(imageWrapper, threshold, targetWrapper) {
} }
}; };
CVUtils.computeHistogram = function(imageWrapper, bitsPerPixel) { export function computeHistogram(imageWrapper, bitsPerPixel) {
if (!bitsPerPixel) { if (!bitsPerPixel) {
bitsPerPixel = 8; bitsPerPixel = 8;
} }
@ -124,7 +127,7 @@ CVUtils.computeHistogram = function(imageWrapper, bitsPerPixel) {
return hist; return hist;
}; };
CVUtils.sharpenLine = function(line) { export function sharpenLine(line) {
var i, var i,
length = line.length, length = line.length,
left = line[0], left = line[0],
@ -141,7 +144,7 @@ CVUtils.sharpenLine = function(line) {
return line; return line;
}; };
CVUtils.determineOtsuThreshold = function(imageWrapper, bitsPerPixel) { export function determineOtsuThreshold(imageWrapper, bitsPerPixel) {
if (!bitsPerPixel) { if (!bitsPerPixel) {
bitsPerPixel = 8; bitsPerPixel = 8;
} }
@ -171,7 +174,7 @@ CVUtils.determineOtsuThreshold = function(imageWrapper, bitsPerPixel) {
var vet = [0], p1, p2, p12, k, m1, m2, m12, var vet = [0], p1, p2, p12, k, m1, m2, m12,
max = (1 << bitsPerPixel) - 1; max = (1 << bitsPerPixel) - 1;
hist = CVUtils.computeHistogram(imageWrapper, bitsPerPixel); hist = computeHistogram(imageWrapper, bitsPerPixel);
for ( k = 1; k < max; k++) { for ( k = 1; k < max; k++) {
p1 = px(0, k); p1 = px(0, k);
p2 = px(k + 1, max); p2 = px(k + 1, max);
@ -191,16 +194,16 @@ CVUtils.determineOtsuThreshold = function(imageWrapper, bitsPerPixel) {
return threshold << bitShift; return threshold << bitShift;
}; };
CVUtils.otsuThreshold = function(imageWrapper, targetWrapper) { export function otsuThreshold(imageWrapper, targetWrapper) {
var threshold = CVUtils.determineOtsuThreshold(imageWrapper); var threshold = determineOtsuThreshold(imageWrapper);
CVUtils.thresholdImage(imageWrapper, threshold, targetWrapper); thresholdImage(imageWrapper, threshold, targetWrapper);
return threshold; return threshold;
}; };
// local thresholding // local thresholding
CVUtils.computeBinaryImage = function(imageWrapper, integralWrapper, targetWrapper) { export function computeBinaryImage(imageWrapper, integralWrapper, targetWrapper) {
CVUtils.computeIntegralImage(imageWrapper, integralWrapper); computeIntegralImage(imageWrapper, integralWrapper);
if (!targetWrapper) { if (!targetWrapper) {
targetWrapper = imageWrapper; targetWrapper = imageWrapper;
@ -241,7 +244,7 @@ CVUtils.computeBinaryImage = function(imageWrapper, integralWrapper, targetWrapp
} }
}; };
CVUtils.cluster = function(points, threshold, property) { export function cluster(points, threshold, property) {
var i, k, cluster, point, clusters = []; var i, k, cluster, point, clusters = [];
if (!property) { if (!property) {
@ -270,7 +273,7 @@ CVUtils.cluster = function(points, threshold, property) {
return clusters; return clusters;
}; };
CVUtils.Tracer = { export const Tracer = {
trace: function(points, vec) { trace: function(points, vec) {
var iteration, maxIterations = 10, top = [], result = [], centerPos = 0, currentPos = 0; var iteration, maxIterations = 10, top = [], result = [], centerPos = 0, currentPos = 0;
@ -340,10 +343,10 @@ CVUtils.Tracer = {
} }
}; };
CVUtils.DILATE = 1; export const DILATE = 1;
CVUtils.ERODE = 2; export const ERODE = 2;
CVUtils.dilate = function(inImageWrapper, outImageWrapper) { export function dilate(inImageWrapper, outImageWrapper) {
var v, var v,
u, u,
inImageData = inImageWrapper.data, inImageData = inImageWrapper.data,
@ -370,7 +373,7 @@ CVUtils.dilate = function(inImageWrapper, outImageWrapper) {
} }
}; };
CVUtils.erode = function(inImageWrapper, outImageWrapper) { export function erode(inImageWrapper, outImageWrapper) {
var v, var v,
u, u,
inImageData = inImageWrapper.data, inImageData = inImageWrapper.data,
@ -397,7 +400,7 @@ CVUtils.erode = function(inImageWrapper, outImageWrapper) {
} }
}; };
CVUtils.subtract = function(aImageWrapper, bImageWrapper, resultImageWrapper) { export function subtract(aImageWrapper, bImageWrapper, resultImageWrapper) {
if (!resultImageWrapper) { if (!resultImageWrapper) {
resultImageWrapper = aImageWrapper; resultImageWrapper = aImageWrapper;
} }
@ -411,7 +414,7 @@ CVUtils.subtract = function(aImageWrapper, bImageWrapper, resultImageWrapper) {
} }
}; };
CVUtils.bitwiseOr = function(aImageWrapper, bImageWrapper, resultImageWrapper) { export function bitwiseOr(aImageWrapper, bImageWrapper, resultImageWrapper) {
if (!resultImageWrapper) { if (!resultImageWrapper) {
resultImageWrapper = aImageWrapper; resultImageWrapper = aImageWrapper;
} }
@ -425,7 +428,7 @@ CVUtils.bitwiseOr = function(aImageWrapper, bImageWrapper, resultImageWrapper) {
} }
}; };
CVUtils.countNonZero = function(imageWrapper) { export function countNonZero(imageWrapper) {
var length = imageWrapper.data.length, data = imageWrapper.data, sum = 0; var length = imageWrapper.data.length, data = imageWrapper.data, sum = 0;
while (length--) { while (length--) {
@ -434,7 +437,7 @@ CVUtils.countNonZero = function(imageWrapper) {
return sum; return sum;
}; };
CVUtils.topGeneric = function(list, top, scoreFunc) { export function topGeneric(list, top, scoreFunc) {
var i, minIdx = 0, min = 0, queue = [], score, hit, pos; var i, minIdx = 0, min = 0, queue = [], score, hit, pos;
for ( i = 0; i < top; i++) { for ( i = 0; i < top; i++) {
@ -463,18 +466,18 @@ CVUtils.topGeneric = function(list, top, scoreFunc) {
return queue; return queue;
}; };
CVUtils.grayArrayFromImage = function(htmlImage, offsetX, ctx, array) { export function grayArrayFromImage(htmlImage, offsetX, ctx, array) {
ctx.drawImage(htmlImage, offsetX, 0, htmlImage.width, htmlImage.height); ctx.drawImage(htmlImage, offsetX, 0, htmlImage.width, htmlImage.height);
var ctxData = ctx.getImageData(offsetX, 0, htmlImage.width, htmlImage.height).data; var ctxData = ctx.getImageData(offsetX, 0, htmlImage.width, htmlImage.height).data;
CVUtils.computeGray(ctxData, array); computeGray(ctxData, array);
}; };
CVUtils.grayArrayFromContext = function(ctx, size, offset, array) { export function grayArrayFromContext(ctx, size, offset, array) {
var ctxData = ctx.getImageData(offset.x, offset.y, size.x, size.y).data; var ctxData = ctx.getImageData(offset.x, offset.y, size.x, size.y).data;
CVUtils.computeGray(ctxData, array); computeGray(ctxData, array);
}; };
CVUtils.grayAndHalfSampleFromCanvasData = function(canvasData, size, outArray) { export function grayAndHalfSampleFromCanvasData(canvasData, size, outArray) {
var topRowIdx = 0; var topRowIdx = 0;
var bottomRowIdx = size.x; var bottomRowIdx = size.x;
var endIdx = Math.floor(canvasData.length / 4); var endIdx = Math.floor(canvasData.length / 4);
@ -507,7 +510,7 @@ CVUtils.grayAndHalfSampleFromCanvasData = function(canvasData, size, outArray) {
} }
}; };
CVUtils.computeGray = function(imageData, outArray, config) { export function computeGray(imageData, outArray, config) {
var l = (imageData.length / 4) | 0, var l = (imageData.length / 4) | 0,
i, i,
singleChannel = config && config.singleChannel === true; singleChannel = config && config.singleChannel === true;
@ -524,7 +527,7 @@ CVUtils.computeGray = function(imageData, outArray, config) {
} }
}; };
CVUtils.loadImageArray = function(src, callback, canvas) { export function loadImageArray(src, callback, canvas) {
if (!canvas) { if (!canvas) {
canvas = document.createElement('canvas'); canvas = document.createElement('canvas');
} }
@ -538,7 +541,7 @@ CVUtils.loadImageArray = function(src, callback, canvas) {
var array = new Uint8Array(this.width * this.height); var array = new Uint8Array(this.width * this.height);
ctx.drawImage(this, 0, 0); ctx.drawImage(this, 0, 0);
var data = ctx.getImageData(0, 0, this.width, this.height).data; var data = ctx.getImageData(0, 0, this.width, this.height).data;
CVUtils.computeGray(data, array); computeGray(data, array);
this.callback(array, { this.callback(array, {
x: this.width, x: this.width,
y: this.height y: this.height
@ -551,7 +554,7 @@ CVUtils.loadImageArray = function(src, callback, canvas) {
* @param inImg {ImageWrapper} input image to be sampled * @param inImg {ImageWrapper} input image to be sampled
* @param outImg {ImageWrapper} to be stored in * @param outImg {ImageWrapper} to be stored in
*/ */
CVUtils.halfSample = function(inImgWrapper, outImgWrapper) { export function halfSample(inImgWrapper, outImgWrapper) {
var inImg = inImgWrapper.data; var inImg = inImgWrapper.data;
var inWidth = inImgWrapper.size.x; var inWidth = inImgWrapper.size.x;
var outImg = outImgWrapper.data; var outImg = outImgWrapper.data;
@ -573,7 +576,7 @@ CVUtils.halfSample = function(inImgWrapper, outImgWrapper) {
} }
}; };
CVUtils.hsv2rgb = function(hsv, rgb) { export function hsv2rgb(hsv, rgb) {
var h = hsv[0], var h = hsv[0],
s = hsv[1], s = hsv[1],
v = hsv[2], v = hsv[2],
@ -611,7 +614,7 @@ CVUtils.hsv2rgb = function(hsv, rgb) {
return rgb; return rgb;
}; };
CVUtils._computeDivisors = function(n) { export function _computeDivisors(n) {
var largeDivisors = [], var largeDivisors = [],
divisors = [], divisors = [],
i; i;
@ -627,7 +630,7 @@ CVUtils._computeDivisors = function(n) {
return divisors.concat(largeDivisors); return divisors.concat(largeDivisors);
}; };
CVUtils._computeIntersection = function(arr1, arr2) { function _computeIntersection(arr1, arr2) {
var i = 0, var i = 0,
j = 0, j = 0,
result = []; result = [];
@ -646,11 +649,11 @@ CVUtils._computeIntersection = function(arr1, arr2) {
return result; return result;
}; };
CVUtils.calculatePatchSize = function(patchSize, imgSize) { export function calculatePatchSize(patchSize, imgSize) {
var divisorsX = this._computeDivisors(imgSize.x), var divisorsX = _computeDivisors(imgSize.x),
divisorsY = this._computeDivisors(imgSize.y), divisorsY = _computeDivisors(imgSize.y),
wideSide = Math.max(imgSize.x, imgSize.y), wideSide = Math.max(imgSize.x, imgSize.y),
common = this._computeIntersection(divisorsX, divisorsY), common = _computeIntersection(divisorsX, divisorsY),
nrOfPatchesList = [8, 10, 15, 20, 32, 60, 80], nrOfPatchesList = [8, 10, 15, 20, 32, 60, 80],
nrOfPatchesMap = { nrOfPatchesMap = {
"x-small": 5, "x-small": 5,
@ -687,15 +690,15 @@ CVUtils.calculatePatchSize = function(patchSize, imgSize) {
optimalPatchSize = findPatchSizeForDivisors(common); optimalPatchSize = findPatchSizeForDivisors(common);
if (!optimalPatchSize) { if (!optimalPatchSize) {
optimalPatchSize = findPatchSizeForDivisors(this._computeDivisors(wideSide)); optimalPatchSize = findPatchSizeForDivisors(_computeDivisors(wideSide));
if (!optimalPatchSize) { if (!optimalPatchSize) {
optimalPatchSize = findPatchSizeForDivisors((this._computeDivisors(desiredPatchSize * nrOfPatches))); optimalPatchSize = findPatchSizeForDivisors((_computeDivisors(desiredPatchSize * nrOfPatches)));
} }
} }
return optimalPatchSize; return optimalPatchSize;
}; };
CVUtils._parseCSSDimensionValues = function(value) { export function _parseCSSDimensionValues(value) {
var dimension = { var dimension = {
value: parseFloat(value), value: parseFloat(value),
unit: value.indexOf("%") === value.length - 1 ? "%" : "px" unit: value.indexOf("%") === value.length - 1 ? "%" : "px"
@ -704,36 +707,36 @@ CVUtils._parseCSSDimensionValues = function(value) {
return dimension; return dimension;
}; };
CVUtils._dimensionsConverters = { export const _dimensionsConverters = {
top: function top(dimension, context) { top: function (dimension, context) {
return Math.floor((dimension.unit === "%") return Math.floor((dimension.unit === "%")
? (context.height * (dimension.value / 100)) ? (context.height * (dimension.value / 100))
: dimension.value); : dimension.value);
}, },
right: function right(dimension, context) { right: function (dimension, context) {
return Math.floor((dimension.unit === "%") return Math.floor((dimension.unit === "%")
? (context.width - context.width * (dimension.value / 100)) ? (context.width - context.width * (dimension.value / 100))
: (context.width - dimension.value)); : (context.width - dimension.value));
}, },
bottom: function bottom(dimension, context) { bottom: function (dimension, context) {
return Math.floor((dimension.unit === "%") return Math.floor((dimension.unit === "%")
? (context.height - context.height * (dimension.value / 100)) ? (context.height - context.height * (dimension.value / 100))
: (context.height - dimension.value)); : (context.height - dimension.value));
}, },
left: function left(dimension, context) { left: function (dimension, context) {
return Math.floor((dimension.unit === "%") return Math.floor((dimension.unit === "%")
? (context.width * (dimension.value / 100)) ? (context.width * (dimension.value / 100))
: dimension.value); : dimension.value);
} }
}; };
CVUtils.computeImageArea = function(inputWidth, inputHeight, area) { export function computeImageArea(inputWidth, inputHeight, area) {
var context = {width: inputWidth, height: inputHeight}; var context = {width: inputWidth, height: inputHeight};
var parsedArea = Object.keys(area).reduce(function(result, key) { var parsedArea = Object.keys(area).reduce(function(result, key) {
var value = area[key], var value = area[key],
parsed = CVUtils._parseCSSDimensionValues(value), parsed = _parseCSSDimensionValues(value),
calculated = CVUtils._dimensionsConverters[key](parsed, context); calculated = _dimensionsConverters[key](parsed, context);
result[key] = calculated; result[key] = calculated;
return result; return result;
@ -746,5 +749,3 @@ CVUtils.computeImageArea = function(inputWidth, inputHeight, area) {
sh: parsedArea.bottom - parsedArea.top sh: parsedArea.bottom - parsedArea.top
}; };
}; };
export default CVUtils;

@ -1,7 +1,9 @@
import SubImage from './subImage'; import SubImage from './subImage';
import CVUtils from '../common/cv_utils'; import {hsv2rgb} from '../common/cv_utils';
import ArrayHelper from '../common/array_helper'; import ArrayHelper from '../common/array_helper';
import {vec2} from 'gl-matrix'; const vec2 = {
clone: require('gl-vec2/clone'),
};
/** /**
* Represents a basic image combining the data and size. * Represents a basic image combining the data and size.
@ -335,7 +337,7 @@ ImageWrapper.prototype.overlay = function(canvas, scale, from) {
var length = this.data.length; var length = this.data.length;
while (length--) { while (length--) {
hsv[0] = this.data[length] * scale; hsv[0] = this.data[length] * scale;
result = hsv[0] <= 0 ? whiteRgb : hsv[0] >= 360 ? blackRgb : CVUtils.hsv2rgb(hsv, rgb); result = hsv[0] <= 0 ? whiteRgb : hsv[0] >= 360 ? blackRgb : hsv2rgb(hsv, rgb);
data[length * 4 + 0] = result[0]; data[length * 4 + 0] = result[0];
data[length * 4 + 1] = result[1]; data[length * 4 + 1] = result[1];
data[length * 4 + 2] = result[2]; data[length * 4 + 2] = result[2];

@ -14,10 +14,6 @@ if (typeof window !== 'undefined') {
window.setTimeout(callback, 1000 / 60); window.setTimeout(callback, 1000 / 60);
}; };
})(); })();
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
} }
Math.imul = Math.imul || function(a, b) { Math.imul = Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xffff, var ah = (a >>> 16) & 0xffff,

@ -5,9 +5,9 @@ module.exports = {
constraints: { constraints: {
width: 640, width: 640,
height: 480, height: 480,
minAspectRatio: 0, // aspectRatio: 640/480, // optional
maxAspectRatio: 100, facingMode: "environment", // or user
facing: "environment" // or user // deviceId: "38745983457387598375983759834"
}, },
area: { area: {
top: "0%", top: "0%",

@ -5,9 +5,9 @@ module.exports = {
constraints: { constraints: {
width: 640, width: 640,
height: 480, height: 480,
minAspectRatio: 0, // aspectRatio: 640/480, // optional
maxAspectRatio: 100, facingMode: "environment", // or user
facing: "environment" // or user // deviceId: "38745983457387598375983759834"
}, },
area: { area: {
top: "0%", top: "0%",

@ -1,4 +1,3 @@
import CVUtils from '../common/cv_utils';
import ImageWrapper from '../common/image_wrapper'; import ImageWrapper from '../common/image_wrapper';
var Bresenham = {}; var Bresenham = {};
@ -90,20 +89,6 @@ Bresenham.getBarcodeLine = function(imageWrapper, p1, p2) {
}; };
}; };
Bresenham.toOtsuBinaryLine = function(result) {
var line = result.line,
image = new ImageWrapper({x: line.length - 1, y: 1}, line),
threshold = CVUtils.determineOtsuThreshold(image, 5);
line = CVUtils.sharpenLine(line);
CVUtils.thresholdImage(image, threshold);
return {
line: line,
threshold: threshold
};
};
/** /**
* Converts the result from getBarcodeLine into a binary representation * Converts the result from getBarcodeLine into a binary representation
* also considering the frequency and slope of the signal for more robust results * also considering the frequency and slope of the signal for more robust results

@ -1,45 +1,29 @@
const merge = require('lodash/object/merge'); import {merge, pick} from 'lodash';
var streamRef, var streamRef,
loadedDataHandler; loadedDataHandler;
/** function waitForVideo(video) {
* Wraps browser-specific getUserMedia return new Promise((resolve, reject) => {
* @param {Object} constraints let attempts = 10;
* @param {Object} success Callback
* @param {Object} failure Callback
*/
function getUserMedia(constraints, success, 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) {
var attempts = 10;
function checkVideo() { function checkVideo() {
if (attempts > 0) { if (attempts > 0) {
if (video.videoWidth > 0 && video.videoHeight > 0) { if (video.videoWidth > 0 && video.videoHeight > 0) {
if (ENV.development) { if (ENV.development) {
console.log(video.videoWidth + "px x " + video.videoHeight + "px"); console.log(video.videoWidth + "px x " + video.videoHeight + "px");
}
resolve();
} else {
window.setTimeout(checkVideo, 500);
} }
callback();
} else { } else {
window.setTimeout(checkVideo, 500); reject('Unable to play video stream. Is webcam working?');
} }
} else { attempts--;
callback('Unable to play video stream. Is webcam working?');
} }
attempts--; checkVideo();
} });
checkVideo();
} }
/** /**
@ -47,89 +31,72 @@ function loadedData(video, callback) {
* and calls the callback function when the content is ready * and calls the callback function when the content is ready
* @param {Object} constraints * @param {Object} constraints
* @param {Object} video * @param {Object} video
* @param {Object} callback
*/ */
function initCamera(constraints, video, callback) { function initCamera(video, constraints) {
getUserMedia(constraints, function(src) { return navigator.mediaDevices.getUserMedia(constraints)
video.src = src; .then((stream) => {
if (loadedDataHandler) { return new Promise((resolve, reject) => {
video.removeEventListener("loadeddata", loadedDataHandler, false); streamRef = stream;
} video.src = window.URL.createObjectURL(stream);
loadedDataHandler = loadedData.bind(null, video, callback); video.onloadedmetadata = (e) => {
video.addEventListener('loadeddata', loadedDataHandler, false); video.play();
video.play(); resolve();
}, function(e) { };
callback(e); });
}); })
.then(waitForVideo.bind(null, video));
} }
/** function deprecatedConstraints(videoConstraints) {
* Normalizes the incoming constraints to satisfy the current browser const normalized = pick(videoConstraints, ["width", "height", "facingMode",
* @param config "aspectRatio", "deviceId"]);
* @param cb Callback which is called whenever constraints are created
* @returns {*}
*/
function normalizeConstraints(config, cb) {
var constraints = {
audio: false,
video: true
},
videoConstraints = merge({
width: 640,
height: 480,
minAspectRatio: 0,
maxAspectRatio: 100,
facing: "environment"
}, config);
if ( typeof MediaStreamTrack !== 'undefined' && typeof MediaStreamTrack.getSources !== 'undefined') { if (typeof videoConstraints["minAspectRatio"] !== 'undefined' &&
MediaStreamTrack.getSources(function(sourceInfos) { videoConstraints["minAspectRatio"] > 0) {
var videoSourceId; normalized["aspectRatio"] = videoConstraints["minAspectRatio"];
for (var i = 0; i < sourceInfos.length; ++i) { console.log("WARNING: Constraint 'minAspectRatio' is deprecated; Use 'aspectRatio' instead");
var sourceInfo = sourceInfos[i]; }
if (sourceInfo.kind === "video" && sourceInfo.facing === videoConstraints.facing) { if (typeof videoConstraints["facing"] !== 'undefined') {
videoSourceId = sourceInfo.id; normalized["facingMode"] = videoConstraints["facing"];
console.log("WARNING: Constraint 'facing' is deprecated. Use 'facingMode' instead'");
}
return normalized;
}
function applyCameraFacing(facing, constraints) {
if (typeof constraints.video.deviceId !== 'undefined' || !facing){
return Promise.resolve(constraints);
}
if ( typeof MediaStreamTrack !== 'undefined' &&
typeof MediaStreamTrack.getSources !== 'undefined') {
return new Promise((resolve, reject) => {
MediaStreamTrack.getSources((sourceInfos) => {
const videoSource = sourceInfos.filter((sourceInfo) => (
sourceInfo.kind === "video" && sourceInfo.facing === facing
))[0];
if (videoSource) {
return resolve(merge({}, constraints,
{video: {deviceId: videoSource.id}}));
} }
} return resolve(constraints);
constraints.video = { });
mandatory: {
minWidth: videoConstraints.width,
minHeight: videoConstraints.height,
minAspectRatio: videoConstraints.minAspectRatio,
maxAspectRatio: videoConstraints.maxAspectRatio
},
optional: [{
sourceId: videoSourceId
}]
};
return cb(constraints);
}); });
} else {
constraints.video = {
mediaSource: "camera",
width: { min: videoConstraints.width, max: videoConstraints.width },
height: { min: videoConstraints.height, max: videoConstraints.height },
require: ["width", "height"]
};
return cb(constraints);
} }
return Promise.resolve(merge({}, constraints, {video: {facingMode: facing}}));
} }
/** function pickConstraints(videoConstraints) {
* Requests the back-facing camera of the user. The callback is called const constraints = {
* whenever the stream is ready to be consumed, or if an error occures. audio: false,
* @param {Object} video video: deprecatedConstraints(videoConstraints)
* @param {Object} callback };
*/ return applyCameraFacing(constraints.video.facingMode, constraints);
function request(video, videoConstraints, callback) {
normalizeConstraints(videoConstraints, function(constraints) {
initCamera(constraints, video, callback);
});
} }
export default { export default {
request: function(video, constraints, callback) { request: function(video, videoConstraints) {
request(video, constraints, callback); return pickConstraints(videoConstraints)
.then(initCamera.bind(null, video));
}, },
release: function() { release: function() {
var tracks = streamRef && streamRef.getVideoTracks(); var tracks = streamRef && streamRef.getVideoTracks();

@ -1,13 +1,17 @@
import CVUtils from '../common/cv_utils'; import {
imageRef,
grayAndHalfSampleFromCanvasData,
computeGray
} from '../common/cv_utils';
var FrameGrabber = {}; var FrameGrabber = {};
FrameGrabber.create = function(inputStream, canvas) { FrameGrabber.create = function(inputStream, canvas) {
var _that = {}, var _that = {},
_streamConfig = inputStream.getConfig(), _streamConfig = inputStream.getConfig(),
_video_size = CVUtils.imageRef(inputStream.getRealWidth(), inputStream.getRealHeight()), _video_size = imageRef(inputStream.getRealWidth(), inputStream.getRealHeight()),
_canvasSize = inputStream.getCanvasSize(), _canvasSize = inputStream.getCanvasSize(),
_size = CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()), _size = imageRef(inputStream.getWidth(), inputStream.getHeight()),
topRight = inputStream.getTopRight(), topRight = inputStream.getTopRight(),
_sx = topRight.x, _sx = topRight.x,
_sy = topRight.y, _sy = topRight.y,
@ -55,9 +59,9 @@ FrameGrabber.create = function(inputStream, canvas) {
_ctx.drawImage(frame, 0, 0, _canvasSize.x, _canvasSize.y); _ctx.drawImage(frame, 0, 0, _canvasSize.x, _canvasSize.y);
ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data; ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if (doHalfSample){ if (doHalfSample){
CVUtils.grayAndHalfSampleFromCanvasData(ctxData, _size, _data); grayAndHalfSampleFromCanvasData(ctxData, _size, _data);
} else { } else {
CVUtils.computeGray(ctxData, _data, _streamConfig); computeGray(ctxData, _data, _streamConfig);
} }
return true; return true;
} else { } else {

@ -1,11 +1,30 @@
import ImageWrapper from '../common/image_wrapper'; import ImageWrapper from '../common/image_wrapper';
import CVUtils from '../common/cv_utils'; import {
calculatePatchSize,
otsuThreshold,
hsv2rgb,
cluster,
topGeneric,
imageRef,
halfSample,
computeImageArea
} from '../common/cv_utils';
import ArrayHelper from '../common/array_helper'; import ArrayHelper from '../common/array_helper';
import ImageDebug from '../common/image_debug'; import ImageDebug from '../common/image_debug';
import Rasterizer from './rasterizer'; import Rasterizer from './rasterizer';
import Tracer from './tracer'; import Tracer from './tracer';
import skeletonizer from './skeletonizer'; import skeletonizer from './skeletonizer';
import {vec2, mat2} from 'gl-matrix'; const vec2 = {
clone: require('gl-vec2/clone'),
dot: require('gl-vec2/dot'),
scale: require('gl-vec2/scale'),
transformMat2: require('gl-vec2/transformMat2')
};
const mat2 = {
copy: require('gl-mat2/copy'),
create: require('gl-mat2/create'),
invert: require('gl-mat2/invert')
}
var _config, var _config,
_currentImageWrapper, _currentImageWrapper,
@ -41,7 +60,7 @@ function initBuffers() {
_currentImageWrapper = _inputImageWrapper; _currentImageWrapper = _inputImageWrapper;
} }
_patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size); _patchSize = calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
_numPatches.x = _currentImageWrapper.size.x / _patchSize.x | 0; _numPatches.x = _currentImageWrapper.size.x / _patchSize.x | 0;
_numPatches.y = _currentImageWrapper.size.y / _patchSize.y | 0; _numPatches.y = _currentImageWrapper.size.y / _patchSize.y | 0;
@ -117,7 +136,7 @@ function boxFromPatches(patches) {
} }
overAvg = (180 - overAvg) * Math.PI / 180; overAvg = (180 - overAvg) * Math.PI / 180;
transMat = mat2.clone([Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]); transMat = mat2.copy(mat2.create(), [Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]);
// iterate over patches and rotate by angle // iterate over patches and rotate by angle
for ( i = 0; i < patches.length; i++) { for ( i = 0; i < patches.length; i++) {
@ -178,9 +197,9 @@ function boxFromPatches(patches) {
* Creates a binary image of the current image * Creates a binary image of the current image
*/ */
function binarizeImage() { function binarizeImage() {
CVUtils.otsuThreshold(_currentImageWrapper, _binaryImageWrapper); otsuThreshold(_currentImageWrapper, _binaryImageWrapper);
_binaryImageWrapper.zeroBorder(); _binaryImageWrapper.zeroBorder();
if (_config.showCanvas) { if (_config.debug.showCanvas) {
_binaryImageWrapper.show(_canvasContainer.dom.binary, 255); _binaryImageWrapper.show(_canvasContainer.dom.binary, 255);
} }
} }
@ -309,7 +328,7 @@ function findBoxes(topLabels, maxLabel) {
for ( j = 0; j < patches.length; j++) { for ( j = 0; j < patches.length; j++) {
patch = patches[j]; patch = patches[j];
hsv[0] = (topLabels[i].label / (maxLabel + 1)) * 360; hsv[0] = (topLabels[i].label / (maxLabel + 1)) * 360;
CVUtils.hsv2rgb(hsv, rgb); hsv2rgb(hsv, rgb);
ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary,
{color: "rgb(" + rgb.join(",") + ")", lineWidth: 2}); {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
} }
@ -324,8 +343,8 @@ function findBoxes(topLabels, maxLabel) {
* @param {Object} moments * @param {Object} moments
*/ */
function similarMoments(moments) { function similarMoments(moments) {
var clusters = CVUtils.cluster(moments, 0.90); var clusters = cluster(moments, 0.90);
var topCluster = CVUtils.topGeneric(clusters, 1, function(e) { var topCluster = topGeneric(clusters, 1, function(e) {
return e.getPoints().length; return e.getPoints().length;
}); });
var points = [], result = []; var points = [], result = [];
@ -339,12 +358,12 @@ function similarMoments(moments) {
} }
function skeletonize(x, y) { function skeletonize(x, y) {
_binaryImageWrapper.subImageAsCopy(_subImageWrapper, CVUtils.imageRef(x, y)); _binaryImageWrapper.subImageAsCopy(_subImageWrapper, imageRef(x, y));
_skeletonizer.skeletonize(); _skeletonizer.skeletonize();
// Show skeleton if requested // Show skeleton if requested
if (ENV.development && _config.debug.showSkeleton) { if (ENV.development && _config.debug.showSkeleton) {
_skelImageWrapper.overlay(_canvasContainer.dom.binary, 360, CVUtils.imageRef(x, y)); _skelImageWrapper.overlay(_canvasContainer.dom.binary, 360, imageRef(x, y));
} }
} }
@ -496,7 +515,7 @@ function rasterizeAngularSimilarity(patchesFound) {
if (_patchLabelGrid.data[j] > 0 && _patchLabelGrid.data[j] <= label) { if (_patchLabelGrid.data[j] > 0 && _patchLabelGrid.data[j] <= label) {
patch = _imageToPatchGrid.data[j]; patch = _imageToPatchGrid.data[j];
hsv[0] = (_patchLabelGrid.data[j] / (label + 1)) * 360; hsv[0] = (_patchLabelGrid.data[j] / (label + 1)) * 360;
CVUtils.hsv2rgb(hsv, rgb); hsv2rgb(hsv, rgb);
ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary, ImageDebug.drawRect(patch.pos, _subImageWrapper.size, _canvasContainer.ctx.binary,
{color: "rgb(" + rgb.join(",") + ")", lineWidth: 2}); {color: "rgb(" + rgb.join(",") + ")", lineWidth: 2});
} }
@ -521,7 +540,7 @@ export default {
boxes; boxes;
if (_config.halfSample) { if (_config.halfSample) {
CVUtils.halfSample(_inputImageWrapper, _currentImageWrapper); halfSample(_inputImageWrapper, _currentImageWrapper);
} }
binarizeImage(); binarizeImage();
@ -557,7 +576,7 @@ export default {
// calculate width and height based on area // calculate width and height based on area
if (inputStream.getConfig().area) { if (inputStream.getConfig().area) {
area = CVUtils.computeImageArea(width, height, inputStream.getConfig().area); area = computeImageArea(width, height, inputStream.getConfig().area);
inputStream.setTopRight({x: area.sx, y: area.sy}); inputStream.setTopRight({x: area.sx, y: area.sy});
inputStream.setCanvasSize({x: width, y: height}); inputStream.setCanvasSize({x: width, y: height});
width = area.sw; width = area.sw;
@ -569,7 +588,7 @@ export default {
y: Math.floor(height * halfSample) y: Math.floor(height * halfSample)
}; };
patchSize = CVUtils.calculatePatchSize(config.patchSize, size); patchSize = calculatePatchSize(config.patchSize, size);
if (ENV.development) { if (ENV.development) {
console.log("Patch-Size: " + JSON.stringify(patchSize)); console.log("Patch-Size: " + JSON.stringify(patchSize));
} }

@ -198,12 +198,10 @@ function Skeletonizer(stdlib, foreign, buffer) {
done = ((sum | 0) == 0 | 0); done = ((sum | 0) == 0 | 0);
} while (!done); } while (!done);
} }
return { return {
skeletonize: skeletonize skeletonize: skeletonize
}; };
} }
/* @preserve ASM END */
export default Skeletonizer; export default Skeletonizer;
/* eslint-enable eqeqeq*/ /* eslint-enable eqeqeq*/
/* @preserve ASM END */

@ -1,17 +1,19 @@
import TypeDefs from './common/typedefs'; // eslint-disable-line no-unused-vars import TypeDefs from './common/typedefs'; // eslint-disable-line no-unused-vars
import WebrtcAdapter from 'webrtc-adapter'; // eslint-disable-line no-unused-vars
import ImageWrapper from './common/image_wrapper'; import ImageWrapper from './common/image_wrapper';
import BarcodeLocator from './locator/barcode_locator'; import BarcodeLocator from './locator/barcode_locator';
import BarcodeDecoder from './decoder/barcode_decoder'; import BarcodeDecoder from './decoder/barcode_decoder';
import Events from './common/events'; import Events from './common/events';
import CameraAccess from './input/camera_access'; import CameraAccess from './input/camera_access';
import ImageDebug from './common/image_debug'; import ImageDebug from './common/image_debug';
import {vec2} from 'gl-matrix';
import ResultCollector from './analytics/result_collector'; import ResultCollector from './analytics/result_collector';
import Config from './config/config'; import Config from './config/config';
import InputStream from 'input_stream'; import InputStream from 'input_stream';
import FrameGrabber from 'frame_grabber'; import FrameGrabber from 'frame_grabber';
import {merge} from 'lodash';
const merge = require('lodash/object/merge'); const vec2 = {
clone: require('gl-vec2/clone')
};
var _inputStream, var _inputStream,
_framegrabber, _framegrabber,
@ -56,12 +58,11 @@ function initInputStream(cb) {
} }
} }
_inputStream = InputStream.createLiveStream(video); _inputStream = InputStream.createLiveStream(video);
CameraAccess.request(video, _config.inputStream.constraints, function(err) { CameraAccess.request(video, _config.inputStream.constraints)
if (!err) { .then(() => {
_inputStream.trigger("canrecord"); _inputStream.trigger("canrecord");
} else { }).catch((err) => {
return cb(err); return cb(err);
}
}); });
} }
@ -236,11 +237,12 @@ function hasCodeResult (result) {
} }
function publishResult(result, imageData) { function publishResult(result, imageData) {
const resultToPublish = result && (result.barcodes || result); let resultToPublish = result;
if (result && _onUIThread) { if (result && _onUIThread) {
transformResult(result); transformResult(result);
addResult(result, imageData); addResult(result, imageData);
resultToPublish = result.barcodes || result;
} }
Events.publish("processed", resultToPublish); Events.publish("processed", resultToPublish);
@ -356,15 +358,24 @@ function initWorker(cb) {
cmd: 'init', cmd: 'init',
size: {x: _inputStream.getWidth(), y: _inputStream.getHeight()}, size: {x: _inputStream.getWidth(), y: _inputStream.getHeight()},
imageData: workerThread.imageData, imageData: workerThread.imageData,
config: _config config: configForWorker(_config)
}, [workerThread.imageData.buffer]); }, [workerThread.imageData.buffer]);
} }
function configForWorker(config) {
return {
...config,
inputStream: {
...config.inputStream,
target: null
}
};
}
function workerInterface(factory) { function workerInterface(factory) {
/* eslint-disable no-undef*/ /* eslint-disable no-undef*/
if (factory) { if (factory) {
var Quagga = factory(); var Quagga = factory().default;
if (!Quagga) { if (!Quagga) {
self.postMessage({'event': 'error', message: 'Quagga could not be created'}); self.postMessage({'event': 'error', message: 'Quagga could not be created'});
return; return;
@ -519,9 +530,9 @@ export default {
halfSample: false halfSample: false
} }
}, config); }, config);
this.init(config, function() { this.init(config, () => {
Events.once("processed", function(result) { Events.once("processed", (result) => {
_stopped = true; this.stop();
resultCallback.call(null, result); resultCallback.call(null, result);
}, true); }, true);
start(); start();

@ -1,5 +1,5 @@
import BarcodeReader from './barcode_reader'; import BarcodeReader from './barcode_reader';
const merge = require('lodash/object/merge'); import {merge} from 'lodash';
function I2of5Reader(opts) { function I2of5Reader(opts) {
opts = merge(getDefaulConfig(), opts); opts = merge(getDefaulConfig(), opts);

@ -11,7 +11,7 @@ module.exports = function(grunt) {
var code = fs.readFileSync('dist/quagga.js', 'utf-8'), var code = fs.readFileSync('dist/quagga.js', 'utf-8'),
minifiedCode = fs.readFileSync('dist/quagga.min.js', 'utf-8'), minifiedCode = fs.readFileSync('dist/quagga.min.js', 'utf-8'),
commentEnd = '/* @preserve ASM END */', commentEnd = '/* @preserve ASM END */',
moduleFunctionRegex = /function\s*\((\w+,\s*\w+)\)\s*\{\s*\/\* \@preserve ASM BEGIN \*\//, moduleFunctionRegex = /function\s*\((\w+,\s*\w+,\s*\w+)\)\s*\{\s*\/\* \@preserve ASM BEGIN \*\//,
commentStartIdx = code.indexOf("/* @preserve ASM BEGIN */"), commentStartIdx = code.indexOf("/* @preserve ASM BEGIN */"),
asmEndIdxTmp = code.indexOf(commentEnd), asmEndIdxTmp = code.indexOf(commentEnd),
asmEndIdx = code.indexOf("}", asmEndIdxTmp), asmEndIdx = code.indexOf("}", asmEndIdxTmp),

@ -1,4 +1,4 @@
const Quagga = require('../../src/quagga'); const Quagga = require('../../src/quagga').default;
const async = require('async'); const async = require('async');
describe('decodeSingle', function () { describe('decodeSingle', function () {

@ -1,4 +1,4 @@
const ArrayHelper = require('../../src/common/array_helper'); import ArrayHelper from '../../src/common/array_helper';
describe('init', function() { describe('init', function() {
it('initializes an array with the given value', function() { it('initializes an array with the given value', function() {

@ -1,6 +1,6 @@
const BarcodeLocator = require('../../src/locator/barcode_locator'); import BarcodeLocator from '../../src/locator/barcode_locator';
const Config = require('../../src/config/config'); import Config from '../../src/config/config';
const merge = require('lodash/object/merge'); import {merge} from 'lodash';
describe('checkImageConstraints', function() { describe('checkImageConstraints', function() {
var config, var config,

@ -1,4 +1,4 @@
const CameraAccess = require('../../src/input/camera_access'); import CameraAccess from '../../src/input/camera_access';
var originalURL, var originalURL,
originalMediaStreamTrack, originalMediaStreamTrack,
@ -13,7 +13,11 @@ beforeEach(function() {
originalURL = window.URL; originalURL = window.URL;
originalMediaStreamTrack = window.MediaStreamTrack; originalMediaStreamTrack = window.MediaStreamTrack;
window.MediaStreamTrack = {}; window.MediaStreamTrack = {};
window.URL = null; window.URL = {
createObjectURL(stream) {
return stream;
}
};
stream = { stream = {
getVideoTracks: function() { getVideoTracks: function() {
@ -43,51 +47,119 @@ afterEach(function() {
describe('success', function() { describe('success', function() {
beforeEach(function() { beforeEach(function() {
sinon.stub(navigator, "getUserMedia", function(constraints, success) { sinon.stub(navigator.mediaDevices, "getUserMedia", function(constraints) {
success(stream); return Promise.resolve(stream);
}); });
}); });
afterEach(function() { afterEach(function() {
navigator.getUserMedia.restore(); navigator.mediaDevices.getUserMedia.restore();
}); });
describe('request', function () { describe('request', function () {
it('should request the camera', function (done) { it('should request the camera', function (done) {
CameraAccess.request(video, {}, function () { CameraAccess.request(video, {})
expect(navigator.getUserMedia.calledOnce).to.equal(true); .then(function () {
expect(navigator.mediaDevices.getUserMedia.calledOnce).to.equal(true);
expect(video.src).to.deep.equal(stream); expect(video.src).to.deep.equal(stream);
done(); done();
}); })
window.setTimeout(() => {
video.onloadedmetadata();
}, 100);
});
it("should allow deprecated constraints to be used", (done) => {
CameraAccess.request(video, {
width: 320,
height: 240,
facing: "user",
minAspectRatio: 2,
maxAspectRatio: 100
})
.then(function () {
const call = navigator.mediaDevices.getUserMedia.getCall(0),
args = call.args;
expect(call).to.be.defined;
expect(args[0].video.width).to.equal(320);
expect(args[0].video.height).to.equal(240);
expect(args[0].video.facingMode).to.equal("user");
expect(args[0].video.aspectRatio).to.equal(2);
expect(args[0].video.facing).not.to.be.defined;
expect(args[0].video.minAspectRatio).not.to.be.defined;
expect(args[0].video.maxAspectRatio).not.to.be.defined;
done();
})
window.setTimeout(() => {
video.onloadedmetadata();
}, 100);
});
});
describe('facingMode fallback in Chrome', () => {
beforeEach(() => {
window.MediaStreamTrack.getSources = (cb) => {
return cb([
{kind: "video", facing: "environment", id: "environment"},
{kind: "audio", id: "audio"},
{kind: "video", facing: "user", id: "user"}
]);
};
});
afterEach(() => {
window.MediaStreamTrack = {};
})
it("should set deviceId in case facingMode is not supported", (done) => {
CameraAccess.request(video, {
facing: "user"
})
.then(function () {
const call = navigator.mediaDevices.getUserMedia.getCall(0),
args = call.args;
expect(call).to.be.defined;
expect(args[0].video.facingMode).not.to.be.defined;
expect(args[0].video.deviceId).to.equal("user");
done();
})
window.setTimeout(() => {
video.onloadedmetadata();
}, 100);
}); });
}); });
describe('release', function () { describe('release', function () {
it('should release the camera', function (done) { it('should release the camera', function (done) {
CameraAccess.request(video, {}, function () { CameraAccess.request(video, {})
.then(function () {
expect(video.src).to.deep.equal(stream); expect(video.src).to.deep.equal(stream);
CameraAccess.release(); CameraAccess.release();
expect(video.src.getVideoTracks()).to.have.length(1); expect(video.src.getVideoTracks()).to.have.length(1);
expect(video.src.getVideoTracks()[0].stop.calledOnce).to.equal(true); expect(video.src.getVideoTracks()[0].stop.calledOnce).to.equal(true);
done(); done();
}); });
window.setTimeout(() => {
video.onloadedmetadata();
}, 100);
}); });
}); });
}); });
describe('failure', function() { describe('failure', function() {
describe("permission denied", function(){ describe("permission denied", function(){
before(function() { beforeEach(function() {
sinon.stub(navigator, "getUserMedia", function(constraints, success, failure) { sinon.stub(navigator.mediaDevices, "getUserMedia", function(constraints, success, failure) {
failure(new Error()); return Promise.reject(new Error());
}); });
}); });
after(function() { afterEach(function() {
navigator.getUserMedia.restore(); navigator.mediaDevices.getUserMedia.restore();
}); });
it('should throw if getUserMedia not available', function(done) { it('should throw if getUserMedia not available', function(done) {
CameraAccess.request(video, {}, function(err) { CameraAccess.request(video, {})
.catch(function (err) {
expect(err).to.be.defined; expect(err).to.be.defined;
done(); done();
}); });
@ -97,17 +169,18 @@ describe('failure', function() {
describe("not available", function(){ describe("not available", function(){
var originalGetUserMedia; var originalGetUserMedia;
before(function() { beforeEach(function() {
originalGetUserMedia = navigator.getUserMedia; originalGetUserMedia = navigator.mediaDevices.getUserMedia;
navigator.getUserMedia = undefined; navigator.mediaDevices.getUserMedia = undefined;
}); });
after(function() { afterEach(function() {
navigator.getUserMedia = originalGetUserMedia; navigator.mediaDevices.getUserMedia = originalGetUserMedia;
}); });
it('should throw if getUserMedia not available', function(done) { it('should throw if getUserMedia not available', function(done) {
CameraAccess.request(video, {}, function(err) { CameraAccess.request(video, {})
.catch((err) => {
expect(err).to.be.defined; expect(err).to.be.defined;
done(); done();
}); });

@ -1,8 +1,14 @@
const CVUtils = require('../../src/common/cv_utils'); const {
imageRef,
calculatePatchSize,
_parseCSSDimensionValues,
_dimensionsConverters,
computeImageArea
} = require('../../src/common/cv_utils');
describe('imageRef', function() { describe('imageRef', function() {
it('gets the image Reference for a coordinate', function() { it('gets the image Reference for a coordinate', function() {
var res = CVUtils.imageRef(1, 2); var res = imageRef(1, 2);
expect(res.x).to.equal(1); expect(res.x).to.equal(1);
expect(res.y).to.equal(2); expect(res.y).to.equal(2);
expect(res.toVec2()[0]).to.equal(1); expect(res.toVec2()[0]).to.equal(1);
@ -12,14 +18,14 @@ describe('imageRef', function() {
describe('calculatePatchSize', function() { describe('calculatePatchSize', function() {
it('should not throw an error in case of valid image size', function() { it('should not throw an error in case of valid image size', function() {
var expected = {x: 32, y: 32}, var expected = {x: 32, y: 32},
patchSize = CVUtils.calculatePatchSize("medium", {x: 640, y: 480}); patchSize = calculatePatchSize("medium", {x: 640, y: 480});
expect(patchSize).to.be.deep.equal(expected); expect(patchSize).to.be.deep.equal(expected);
}); });
it('should thow an error if image size it not valid', function() { it('should thow an error if image size it not valid', function() {
var expected = {x: 32, y: 32}, var expected = {x: 32, y: 32},
patchSize = CVUtils.calculatePatchSize("medium", {x: 640, y: 480}); patchSize = calculatePatchSize("medium", {x: 640, y: 480});
expect(patchSize).to.be.deep.equal(expected); expect(patchSize).to.be.deep.equal(expected);
}); });
@ -31,7 +37,7 @@ describe('_parseCSSDimensionValues', function() {
value: 10, value: 10,
unit: "%" unit: "%"
}, },
result = CVUtils._parseCSSDimensionValues("10%"); result = _parseCSSDimensionValues("10%");
expect(result).to.be.deep.equal(expected); expect(result).to.be.deep.equal(expected);
}); });
@ -41,7 +47,7 @@ describe('_parseCSSDimensionValues', function() {
value: 100, value: 100,
unit: "%" unit: "%"
}, },
result = CVUtils._parseCSSDimensionValues("100%"); result = _parseCSSDimensionValues("100%");
expect(result).to.be.deep.equal(expected); expect(result).to.be.deep.equal(expected);
}); });
@ -51,7 +57,7 @@ describe('_parseCSSDimensionValues', function() {
value: 0, value: 0,
unit: "%" unit: "%"
}, },
result = CVUtils._parseCSSDimensionValues("0%"); result = _parseCSSDimensionValues("0%");
expect(result).to.be.deep.equal(expected); expect(result).to.be.deep.equal(expected);
}); });
@ -61,7 +67,7 @@ describe('_parseCSSDimensionValues', function() {
value: 26.3, value: 26.3,
unit: "%" unit: "%"
}, },
result = CVUtils._parseCSSDimensionValues("26.3px"); result = _parseCSSDimensionValues("26.3px");
console.log(result); console.log(result);
expect(result).to.be.deep.equal(expected); expect(result).to.be.deep.equal(expected);
@ -80,28 +86,28 @@ describe("_dimensionsConverters", function(){
it("should convert a top-value correclty", function() { it("should convert a top-value correclty", function() {
var expected = 48, var expected = 48,
result = CVUtils._dimensionsConverters.top({value: 10, unit: "%"}, context); result = _dimensionsConverters.top({value: 10, unit: "%"}, context);
expect(result).to.be.equal(expected); expect(result).to.be.equal(expected);
}); });
it("should convert a right-value correclty", function() { it("should convert a right-value correclty", function() {
var expected = 640 - 128, var expected = 640 - 128,
result = CVUtils._dimensionsConverters.right({value: 20, unit: "%"}, context); result = _dimensionsConverters.right({value: 20, unit: "%"}, context);
expect(result).to.be.equal(expected); expect(result).to.be.equal(expected);
}); });
it("should convert a bottom-value correclty", function() { it("should convert a bottom-value correclty", function() {
var expected = 480 - 77, var expected = 480 - 77,
result = CVUtils._dimensionsConverters.bottom({value: 16, unit: "%"}, context); result = _dimensionsConverters.bottom({value: 16, unit: "%"}, context);
expect(result).to.be.equal(expected); expect(result).to.be.equal(expected);
}); });
it("should convert a left-value correclty", function() { it("should convert a left-value correclty", function() {
var expected = 57, var expected = 57,
result = CVUtils._dimensionsConverters.left({value: 9, unit: "%"}, context); result = _dimensionsConverters.left({value: 9, unit: "%"}, context);
expect(result).to.be.equal(expected); expect(result).to.be.equal(expected);
}); });
@ -115,7 +121,7 @@ describe("computeImageArea", function() {
sw: 429, sw: 429,
sh: 336 sh: 336
}, },
result = CVUtils.computeImageArea(640, 480, { result = computeImageArea(640, 480, {
top: "10%", top: "10%",
right: "15%", right: "15%",
bottom: "20%", bottom: "20%",
@ -132,7 +138,7 @@ describe("computeImageArea", function() {
sw: 640, sw: 640,
sh: 480 sh: 480
}, },
result = CVUtils.computeImageArea(640, 480, { result = computeImageArea(640, 480, {
top: "0%", top: "0%",
right: "0%", right: "0%",
bottom: "0%", bottom: "0%",

@ -1,4 +1,4 @@
const Events = require('../../src/common/events'); import Events from '../../src/common/events';
beforeEach(function() { beforeEach(function() {
Events.unsubscribe(); Events.unsubscribe();

@ -1,5 +1,5 @@
const ResultCollector = require('../../src/analytics/result_collector'); import ResultCollector from '../../src/analytics/result_collector';
const ImageDebug = require('../../src/common/image_debug'); import ImageDebug from '../../src/common/image_debug';
var canvasMock, var canvasMock,
imageSize, imageSize,

@ -11,16 +11,14 @@ module.exports = {
loaders: [{ loaders: [{
test: /\.jsx?$/, test: /\.jsx?$/,
exclude: /node_modules/, exclude: /node_modules/,
loader: 'babel' loader: 'babel-loader'
}] }]
}, },
resolve: { resolve: {
extensions: ['', '.js', '.jsx'], modules: [
root: path.resolve(__dirname), path.resolve('./src/input/'),
alias: { 'node_modules'
'input_stream$': 'src/input/input_stream', ]
'frame_grabber$': 'src/input/frame_grabber'
}
}, },
output: { output: {
path: __dirname + '/dist', path: __dirname + '/dist',

@ -1,9 +1,21 @@
var webpack = require('webpack'); var webpack = require('webpack');
module.exports = require('./webpack.config.js'); module.exports = require('./webpack.config.js');
module.exports.plugins.unshift( module.exports.plugins = module.exports.plugins.concat([
new webpack.optimize.UglifyJsPlugin() new webpack.LoaderOptionsPlugin({
); minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: /@preserve/
},
sourceMap: false
}),
]);
module.exports.output.filename = 'quagga.min.js'; module.exports.output.filename = 'quagga.min.js';

@ -4,12 +4,10 @@ var webpack = require('webpack'),
module.exports = require('./webpack.config.js'); module.exports = require('./webpack.config.js');
module.exports.resolve = { module.exports.resolve = {
extensions: ['', '.js', '.jsx'], modules: [
root: path.resolve(__dirname), path.resolve('./lib/'),
alias: { 'node_modules'
'input_stream': 'lib/input_stream', ]
'frame_grabber': 'lib/frame_grabber'
}
}; };
module.exports.externals = [ module.exports.externals = [
@ -19,7 +17,8 @@ module.exports.externals = [
"ndarray", "ndarray",
"ndarray-linear-interpolate" "ndarray-linear-interpolate"
]; ];
module.exports.output.libraryTarget = "commonjs2"; module.exports.output.libraryTarget = "umd";
module.exports.output.library = "Quagga";
module.exports.plugins = [ module.exports.plugins = [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
ENV: require(path.join(__dirname, './env/', process.env.BUILD_ENV)) ENV: require(path.join(__dirname, './env/', process.env.BUILD_ENV))

Loading…
Cancel
Save