Initial version for node.js

pull/65/head
Christoph Oberhofer 10 years ago
parent 89da5cc4e7
commit a042422515

@ -0,0 +1,15 @@
var Quagga = require('../lib/quagga');
Quagga.decodeSingle({
src: "../test/fixtures/code_128/image-001.jpg",
numOfWorkers: 0,
inputStream: {
size: 640
}
}, function(result) {
if(result.codeResult) {
console.log("result", result.codeResult.code);
} else {
console.log("not detected");
}
});

@ -0,0 +1,75 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(["cv_utils"], function(CVUtils) {
"use strict";
var FrameGrabber = {};
FrameGrabber.create = function(inputStream) {
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,
_ctx = null,
_data = null;
_sWidth = _video_size.x;
_dWidth = _size.x;
_sHeight = _video_size.y;
_dHeight = _size.y;
_data = new Uint8Array(_size.x * _size.y);
/**
* Uses the given array as frame-buffer
*/
_that.attachData = function(data) {
_data = data;
};
/**
* Returns the used frame-buffer
*/
_that.getData = function() {
return _data;
};
/**
* Fetches a frame from the input-stream and puts into the frame-buffer.
* The image-data is converted to gray-scale and then half-sampled if configured.
*/
_that.grab = function() {
var doHalfSample = _streamConfig.halfSample,
frame = inputStream.getFrame();
if (frame) {
if(doHalfSample){
CVUtils.grayAndHalfSampleFromCanvasData(frame.data, _size, _data);
} else {
CVUtils.computeGray(frame.data, _data);
}
return true;
} else {
return false;
}
};
_that.getSize = function() {
return _size;
};
return _that;
};
return (FrameGrabber);
});

@ -0,0 +1,138 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(function() {
"use strict";
var GetPixels = require("get-pixels");
var InputStream = {};
InputStream.createImageStream = function() {
var that = {};
var _config = null;
var width = 0,
height = 0,
frameIdx = 0,
paused = true,
loaded = false,
frame = null,
baseUrl,
ended = false,
size,
calculatedWidth,
calculatedHeight,
_eventNames = ['canrecord', 'ended'],
_eventHandlers = {};
function loadImages() {
loaded = false;
GetPixels(baseUrl, function(err, pixels) {
if (err) {
console.log(err);
exit(1);
}
loaded = true;
console.log(pixels.shape);
frame = pixels;
width = pixels.shape[0];
height = pixels.shape[1];
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;
setTimeout(function() {
publishEvent("canrecord", []);
}, 0);
});
}
function publishEvent(eventName, args) {
var j,
handlers = _eventHandlers[eventName];
if (handlers && handlers.length > 0) {
for ( j = 0; j < handlers.length; j++) {
handlers[j].apply(that, args);
}
}
}
that.trigger = publishEvent;
that.getWidth = function() {
return calculatedWidth;
};
that.getHeight = function() {
return calculatedHeight;
};
that.setWidth = function(width) {
calculatedWidth = width;
};
that.setHeight = function(height) {
calculatedHeight = height;
};
that.getRealWidth = function() {
return width;
};
that.getRealHeight = function() {
return height;
};
that.setInputStream = function(stream) {
_config = stream;
baseUrl = _config.src;
size = 1;
loadImages();
};
that.ended = function() {
return ended;
};
that.setAttribute = function() {};
that.getConfig = function() {
return _config;
};
that.pause = function() {
paused = true;
};
that.play = function() {
paused = false;
};
that.setCurrentTime = function(time) {
frameIdx = time;
};
that.addEventListener = function(event, f) {
if (_eventNames.indexOf(event) !== -1) {
if (!_eventHandlers[event]) {
_eventHandlers[event] = [];
}
_eventHandlers[event].push(f);
}
};
that.getFrame = function() {
if (!loaded){
return null;
}
return frame;
};
return that;
};
return (InputStream);
});

@ -0,0 +1,12 @@
var requirejs = require('requirejs');
requirejs.config({
"baseUrl" : "../src",
"paths" : {
"typedefs" : "typedefs",
"input_stream": "../lib/input_stream",
"frame_grabber": "../lib/frame_grabber"
}
});
module.exports = requirejs('quagga');

@ -2,7 +2,8 @@
"name": "quagga",
"version": "0.6.6",
"description": "An advanced barcode-scanner written in JavaScript",
"main": "dist/quagga.js",
"main": "lib/quagga.js",
"browser": "dist/quagga.js",
"devDependencies": {
"async": "^0.9.0",
"grunt": "~0.4.5",
@ -46,5 +47,9 @@
"imageprocessing"
],
"author": "Christoph Oberhofer <ch.oberhofer@gmail.com>",
"license": "MIT"
"license": "MIT",
"dependencies": {
"get-pixels": "^3.2.2",
"gl-matrix": "^2.1.0"
}
}

@ -1,8 +1,8 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, mat2, vec2 */
define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug"],
function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug) {
define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug", "gl-matrix"],
function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug, glMatrix) {
var _config,
_currentImageWrapper,
@ -25,6 +25,8 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
_numPatches = {x: 0, y: 0},
_inputImageWrapper,
_skeletonizer,
vec2 = glMatrix.vec2,
mat2 = glMatrix.mat2,
self = this;
function initBuffers() {
@ -100,15 +102,14 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
overAvg += 180;
}
//console.log(overAvg);
overAvg = (180 - overAvg) * Math.PI / 180;
transMat = mat2.create([Math.cos(overAvg), -Math.sin(overAvg), Math.sin(overAvg), Math.cos(overAvg)]);
transMat = mat2.clone([Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]);
// iterate over patches and rotate by angle
for ( i = 0; i < patches.length; i++) {
patch = patches[i];
for ( j = 0; j < 4; j++) {
mat2.xVec2(transMat, patch.box[j]);
vec2.transformMat2(patch.box[j], patch.box[j], transMat);
}
if (_config.boxFromPatches.showTransformed) {
@ -143,9 +144,9 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
scale = _config.halfSample ? 2 : 1;
// reverse rotation;
transMat = mat2.inverse(transMat);
transMat = mat2.invert(transMat, transMat);
for ( j = 0; j < 4; j++) {
mat2.xVec2(transMat, box[j]);
vec2.transformMat2(box[j], box[j], transMat);
}
if (_config.boxFromPatches.showBB) {
@ -153,7 +154,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
}
for ( j = 0; j < 4; j++) {
vec2.scale(box[j], scale);
vec2.scale(box[j], box[j], scale);
}
return box;
@ -377,10 +378,10 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
x : x,
y : y
},
box : [vec2.create([x, y]), vec2.create([x + _subImageWrapper.size.x, y]), vec2.create([x + _subImageWrapper.size.x, y + _subImageWrapper.size.y]), vec2.create([x, y + _subImageWrapper.size.y])],
box : [vec2.clone([x, y]), vec2.clone([x + _subImageWrapper.size.x, y]), vec2.clone([x + _subImageWrapper.size.x, y + _subImageWrapper.size.y]), vec2.clone([x, y + _subImageWrapper.size.y])],
moments : matchingMoments,
rad : avg,
vec : vec2.create([Math.cos(avg), Math.sin(avg)])
vec : vec2.clone([Math.cos(avg), Math.sin(avg)])
};
patchesFound.push(patch);
}

@ -1,9 +1,10 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2 */
/* global define */
define(function() {
define(["gl-matrix"], function(glMatrix) {
"use strict";
var vec2 = glMatrix.vec2;
/**
* Creates a cluster for grouping similar orientations of datapoints
*/
@ -11,7 +12,7 @@ define(function() {
create : function(point, threshold) {
var points = [], center = {
rad : 0,
vec : vec2.create([0, 0])
vec : vec2.clone([0, 0])
}, pointMap = {};
function init() {
@ -30,7 +31,7 @@ define(function() {
sum += points[i].rad;
}
center.rad = sum / points.length;
center.vec = vec2.create([Math.cos(center.rad), Math.sin(center.rad)]);
center.vec = vec2.clone([Math.cos(center.rad), Math.sin(center.rad)]);
}
init();

@ -1,7 +1,7 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2, vec3 */
/* global define */
define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrixAddon, ArrayHelper) {
define(['cluster', "array_helper", "gl-matrix"], function(Cluster2, ArrayHelper, glMatrix) {
"use strict";
/*
@ -14,7 +14,9 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
* @class Represents a collection of useful CV algorithms/functions
*/
var CVUtils = {};
var CVUtils = {},
vec2 = glMatrix.vec2,
vec3 = glMatrix.vec3;
/**
* @param x x-coordinate
@ -26,10 +28,10 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
x : x,
y : y,
toVec2 : function() {
return vec2.create([this.x, this.y]);
return vec2.clone([this.x, this.y]);
},
toVec3 : function() {
return vec3.create([this.x, this.y, 1]);
return vec3.clone([this.x, this.y, 1]);
},
round : function() {
this.x = this.x > 0.0 ? Math.floor(this.x + 0.5) : Math.floor(this.x - 0.5);

@ -224,7 +224,7 @@ mat2.inverse = function(mat){
};
var vec2 = {};
vec2.create = function(vec){
vec2.clone = function(vec){
var dest;
if(vec) {
@ -324,7 +324,7 @@ vec2.length = function(vec){
};
vec2.perspectiveProject = function(vec){
var result = vec2.create(vec);
var result = vec2.clone(vec);
return vec2.scale(result, 1/vec[2]);
};
@ -333,7 +333,7 @@ vec2.perspectiveProject = function(vec){
* @returns vec2 projected vector
*/
vec3.project = function(vec){
return vec2.scale(vec2.create(vec), 1/vec[2]);
return vec2.scale(vec2.clone(vec), 1/vec[2]);
};
var vec6 = {};

@ -1,14 +1,17 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2, mat2 */
/* global define */
define([
"subImage",
"cv_utils",
"array_helper"
"array_helper",
"gl-matrix"
],
function(SubImage, CVUtils, ArrayHelper) {
function(SubImage, CVUtils, ArrayHelper, glMatrix) {
'use strict';
var vec2 = glMatrix.vec2,
mat2 = glMatrix.mat2;
/**
* Represents a basic image combining the data and size.
@ -62,11 +65,11 @@ define([
*/
ImageWrapper.transform = function(inImg, outImg, M, inOrig, outOrig) {
var w = outImg.size.x, h = outImg.size.y, iw = inImg.size.x, ih = inImg.size.y;
var across = vec2.create([M[0], M[2]]);
var down = vec2.create([M[1], M[3]]);
var across = vec2.clone([M[0], M[2]]);
var down = vec2.clone([M[1], M[3]]);
var defaultValue = 0;
var p0 = vec2.subtract(inOrig, mat2.xVec2(M, outOrig, vec2.create()), vec2.create());
var p0 = vec2.subtract(inOrig, mat2.xVec2(M, outOrig, vec2.clone()), vec2.clone());
var min_x = p0[0], min_y = p0[1];
var max_x = min_x, max_y = min_y;
@ -94,7 +97,7 @@ define([
else
max_y += h * down[1];
var carrigeReturn = vec2.subtract(down, vec2.scale(across, w, vec2.create()), vec2.create());
var carrigeReturn = vec2.subtract(down, vec2.scale(across, w, vec2.clone()), vec2.clone());
if (min_x >= 0 && min_y >= 0 && max_x < iw - 1 && max_y < ih - 1) {
p = p0;
@ -346,7 +349,7 @@ define([
label.theta += 180;
}
label.rad = tmp > PI ? tmp - PI : tmp;
label.vec = vec2.create([Math.cos(tmp), Math.sin(tmp)]);
label.vec = vec2.clone([Math.cos(tmp), Math.sin(tmp)]);
result.push(label);
}
}

@ -1,5 +1,5 @@
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
/* global define, vec2 */
/* global define */
define([
@ -15,7 +15,8 @@ define([
"events",
"camera_access",
"image_debug",
"cv_utils"],
"cv_utils",
"gl-matrix"],
function(Code128Reader,
EANReader,
InputStream,
@ -28,7 +29,8 @@ function(Code128Reader,
Events,
CameraAccess,
ImageDebug,
CVUtils) {
CVUtils,
glMatrix) {
"use strict";
var _inputStream,
@ -48,7 +50,8 @@ function(Code128Reader,
_boxSize,
_decoder,
_workerPool = [],
_onUIThread = true;
_onUIThread = true,
vec2 = glMatrix.vec2;
function initializeData(imageWrapper) {
initBuffers(imageWrapper);
@ -56,20 +59,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";
}
}
}
}
@ -161,35 +166,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.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();
}
_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 +211,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.clone([20, _inputImageWrapper.size.y / 2 - 100]),
vec2.clone([20, _inputImageWrapper.size.y / 2 + 100]),
vec2.clone([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 + 100]),
vec2.clone([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 - 100])
];
BarcodeLocator.init(_inputImageWrapper, _config.locator);
}

@ -4,6 +4,16 @@
define(function() {
"use strict";
Math.imul = Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
// the shift by 0 fixes the sign on the high part
// the final |0 converts the unsigned value into a signed value
return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
};
/* @preserve ASM BEGIN */
function Skeletonizer(stdlib, foreign, buffer) {
"use asm";

Loading…
Cancel
Save