Merged ean-improvement to upc-barcode
@@ -1,7 +1,7 @@
|
|||||||
quaggaJS
|
quaggaJS
|
||||||
========
|
========
|
||||||
|
|
||||||
- [Changelog](#changelog) (2015-04-16)
|
- [Changelog](#changelog) (2015-04-25)
|
||||||
|
|
||||||
## What is QuaggaJS?
|
## What is QuaggaJS?
|
||||||
|
|
||||||
@@ -237,6 +237,7 @@ The default `config` object is set as followed:
|
|||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
halfSample: true,
|
halfSample: true,
|
||||||
|
patchSize: "medium", // x-small, small, medium, large, x-large
|
||||||
showCanvas: false,
|
showCanvas: false,
|
||||||
showPatches: false,
|
showPatches: false,
|
||||||
showFoundPatches: false,
|
showFoundPatches: false,
|
||||||
@@ -291,6 +292,12 @@ work.
|
|||||||
|
|
||||||
## <a name="changelog">Changelog</a>
|
## <a name="changelog">Changelog</a>
|
||||||
|
|
||||||
|
### 2015-04-25
|
||||||
|
- Improvements
|
||||||
|
- Added extended configuration to the file-input example
|
||||||
|
- Configurable ``patchSize`` for better adjustment to small/medium/large
|
||||||
|
barcodes
|
||||||
|
|
||||||
### 2015-04-16
|
### 2015-04-16
|
||||||
- Features
|
- Features
|
||||||
- Added support for [Codabar][codabar_wiki] barcodes
|
- Added support for [Codabar][codabar_wiki] barcodes
|
||||||
|
|||||||
@@ -1240,6 +1240,39 @@ define(
|
|||||||
throw BarcodeReader.PatternNotFoundException;
|
throw BarcodeReader.PatternNotFoundException;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EANReader.prototype._findStart = function() {
|
||||||
|
var self = this,
|
||||||
|
leadingWhitespaceStart,
|
||||||
|
offset = self._nextSet(self._row),
|
||||||
|
startInfo;
|
||||||
|
|
||||||
|
while(!startInfo) {
|
||||||
|
startInfo = self._findPattern(self.START_PATTERN, offset);
|
||||||
|
leadingWhitespaceStart = startInfo.start - (startInfo.end - startInfo.start);
|
||||||
|
if (leadingWhitespaceStart >= 0) {
|
||||||
|
if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
|
||||||
|
return startInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset = startInfo.end;
|
||||||
|
startInfo = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EANReader.prototype._findEnd = function(offset) {
|
||||||
|
var self = this,
|
||||||
|
trailingWhitespaceEnd,
|
||||||
|
endInfo = self._findPattern(self.STOP_PATTERN, offset);
|
||||||
|
|
||||||
|
trailingWhitespaceEnd = endInfo.end + (endInfo.end - endInfo.start);
|
||||||
|
if (trailingWhitespaceEnd < self._row.length) {
|
||||||
|
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
|
||||||
|
return endInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
EANReader.prototype._decode = function() {
|
EANReader.prototype._decode = function() {
|
||||||
var startInfo,
|
var startInfo,
|
||||||
self = this,
|
self = this,
|
||||||
@@ -1250,7 +1283,7 @@ define(
|
|||||||
decodedCodes = [];
|
decodedCodes = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startInfo = self._findPattern(self.START_PATTERN);
|
startInfo = self._findStart();
|
||||||
code = {
|
code = {
|
||||||
code : startInfo.code,
|
code : startInfo.code,
|
||||||
start : startInfo.start,
|
start : startInfo.start,
|
||||||
@@ -1288,7 +1321,11 @@ define(
|
|||||||
result.push(code.code);
|
result.push(code.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
code = self._findPattern(self.STOP_PATTERN, code.end);
|
code = self._findEnd(code.end);
|
||||||
|
if (code === null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
decodedCodes.push(code);
|
decodedCodes.push(code);
|
||||||
|
|
||||||
// Checksum
|
// Checksum
|
||||||
@@ -4724,6 +4761,71 @@ define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster
|
|||||||
return rgb;
|
return rgb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CVUtils._computeDivisors = function(n) {
|
||||||
|
var largeDivisors = [],
|
||||||
|
divisors = [],
|
||||||
|
i;
|
||||||
|
|
||||||
|
for (i = 1; i < Math.sqrt(n) + 1; i++) {
|
||||||
|
if (n % i === 0) {
|
||||||
|
divisors.push(i);
|
||||||
|
if (i !== n/i) {
|
||||||
|
largeDivisors.unshift(Math.floor(n/i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return divisors.concat(largeDivisors);
|
||||||
|
};
|
||||||
|
|
||||||
|
CVUtils._computeIntersection = function(arr1, arr2) {
|
||||||
|
var i = 0,
|
||||||
|
j = 0,
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
while (i < arr1.length && j < arr2.length) {
|
||||||
|
if (arr1[i] === arr2[j]) {
|
||||||
|
result.push(arr1[i]);
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
} else if (arr1[i] > arr2[j]) {
|
||||||
|
j++;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CVUtils.calculatePatchSize = function(patchSize, imgSize) {
|
||||||
|
var divisorsX = this._computeDivisors(imgSize.x),
|
||||||
|
divisorsY = this._computeDivisors(imgSize.y),
|
||||||
|
wideSide = Math.max(imgSize.x, imgSize.y),
|
||||||
|
common = this._computeIntersection(divisorsX, divisorsY),
|
||||||
|
nrOfPatchesMap = {
|
||||||
|
"x-small": 60,
|
||||||
|
"small": 32,
|
||||||
|
"medium": 20,
|
||||||
|
"large": 15,
|
||||||
|
"x-large": 10
|
||||||
|
},
|
||||||
|
nrOfPatches = nrOfPatchesMap[patchSize] || nrOfPatchesMap.medium,
|
||||||
|
i = 0,
|
||||||
|
found = common[Math.floor(common.length/2)],
|
||||||
|
desiredPatchSize = wideSide/nrOfPatches;
|
||||||
|
|
||||||
|
while(i < (common.length - 1) && common[i] < desiredPatchSize) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
if (Math.abs(common[i] - desiredPatchSize) > Math.abs(common[i-1] - desiredPatchSize)) {
|
||||||
|
found = common[i-1];
|
||||||
|
} else {
|
||||||
|
found = common[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {x: found, y: found};
|
||||||
|
};
|
||||||
|
|
||||||
return (CVUtils);
|
return (CVUtils);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -5736,10 +5838,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
|
|||||||
_currentImageWrapper = _inputImageWrapper;
|
_currentImageWrapper = _inputImageWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patchSize = {
|
_patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
|
||||||
x : _config.patchSize * ( _config.halfSample ? 0.5 : 1),
|
|
||||||
y : _config.patchSize * ( _config.halfSample ? 0.5 : 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
_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;
|
||||||
@@ -6322,23 +6421,23 @@ define('bresenham',[],function() {
|
|||||||
extrema = [],
|
extrema = [],
|
||||||
currentDir,
|
currentDir,
|
||||||
dir,
|
dir,
|
||||||
threshold = (max - min) / 8,
|
threshold = (max - min) / 12,
|
||||||
rThreshold = -threshold,
|
rThreshold = -threshold,
|
||||||
i,
|
i,
|
||||||
j;
|
j;
|
||||||
|
|
||||||
// 1. find extrema
|
// 1. find extrema
|
||||||
currentDir = line[0] > center ? Slope.DIR.DOWN : Slope.DIR.UP;
|
currentDir = line[0] > center ? Slope.DIR.UP : Slope.DIR.DOWN;
|
||||||
extrema.push({
|
extrema.push({
|
||||||
pos : 0,
|
pos : 0,
|
||||||
val : line[0]
|
val : line[0]
|
||||||
});
|
});
|
||||||
for ( i = 0; i < line.length - 1; i++) {
|
for ( i = 0; i < line.length - 1; i++) {
|
||||||
slope = (line[i + 1] - line[i]);
|
slope = (line[i + 1] - line[i]);
|
||||||
if (slope < rThreshold) {
|
if (slope < rThreshold && line[i + 1] < (center*1.5)) {
|
||||||
dir = Slope.DIR.UP;
|
|
||||||
} else if (slope > threshold) {
|
|
||||||
dir = Slope.DIR.DOWN;
|
dir = Slope.DIR.DOWN;
|
||||||
|
} else if (slope > threshold && line[i + 1] > (center*0.5)) {
|
||||||
|
dir = Slope.DIR.UP;
|
||||||
} else {
|
} else {
|
||||||
dir = currentDir;
|
dir = currentDir;
|
||||||
}
|
}
|
||||||
@@ -7060,18 +7159,25 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
|
|||||||
* @param {Number} angle
|
* @param {Number} angle
|
||||||
*/
|
*/
|
||||||
function getExtendedLine(line, angle, ext) {
|
function getExtendedLine(line, angle, ext) {
|
||||||
|
function extendLine(amount) {
|
||||||
var extension = {
|
var extension = {
|
||||||
y : ext * Math.sin(angle),
|
y : amount * Math.sin(angle),
|
||||||
x : ext * Math.cos(angle)
|
x : amount * Math.cos(angle)
|
||||||
};
|
};
|
||||||
|
|
||||||
line[0].y -= extension.y;
|
line[0].y -= extension.y;
|
||||||
line[0].x -= extension.x;
|
line[0].x -= extension.x;
|
||||||
line[1].y += extension.y;
|
line[1].y += extension.y;
|
||||||
line[1].x += extension.x;
|
line[1].x += extension.x;
|
||||||
|
}
|
||||||
|
|
||||||
// check if inside image
|
// check if inside image
|
||||||
if (!inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
|
extendLine(ext);
|
||||||
|
while (ext > 1 && !inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
|
||||||
|
ext -= Math.floor(ext/2);
|
||||||
|
extendLine(-ext);
|
||||||
|
}
|
||||||
|
if (ext <= 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
@@ -7151,6 +7257,12 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLineLength(line) {
|
||||||
|
return Math.sqrt(
|
||||||
|
Math.pow(Math.abs(line[1].y - line[0].y), 2) +
|
||||||
|
Math.pow(Math.abs(line[1].x - line[0].x), 2));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* With the help of the configured readers (Code128 or EAN) this function tries to detect a
|
* With the help of the configured readers (Code128 or EAN) this function tries to detect a
|
||||||
* valid barcode pattern within the given area.
|
* valid barcode pattern within the given area.
|
||||||
@@ -7161,15 +7273,17 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
|
|||||||
var line,
|
var line,
|
||||||
lineAngle,
|
lineAngle,
|
||||||
ctx = _canvas.ctx.overlay,
|
ctx = _canvas.ctx.overlay,
|
||||||
result;
|
result,
|
||||||
|
lineLength;
|
||||||
|
|
||||||
if (config.drawBoundingBox && ctx) {
|
if (config.drawBoundingBox && ctx) {
|
||||||
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
|
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
line = getLine(box);
|
line = getLine(box);
|
||||||
|
lineLength = getLineLength(line);
|
||||||
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
||||||
line = getExtendedLine(line, lineAngle, 10);
|
line = getExtendedLine(line, lineAngle, Math.floor(lineLength*0.07));
|
||||||
if(line === null){
|
if(line === null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -7379,18 +7493,18 @@ define('config',[],function(){
|
|||||||
decoder:{
|
decoder:{
|
||||||
drawBoundingBox: false,
|
drawBoundingBox: false,
|
||||||
showFrequency: false,
|
showFrequency: false,
|
||||||
drawScanline: true,
|
drawScanline: false,
|
||||||
showPattern: true,
|
showPattern: false,
|
||||||
readers: [
|
readers: [
|
||||||
'code_128_reader'
|
'code_128_reader'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
halfSample: true,
|
halfSample: true,
|
||||||
patchSize: 64,
|
patchSize: "medium", // x-small, small, medium, large, x-large
|
||||||
showCanvas: true,
|
showCanvas: false,
|
||||||
showPatches: false,
|
showPatches: false,
|
||||||
showFoundPatches: true,
|
showFoundPatches: false,
|
||||||
showSkeleton: false,
|
showSkeleton: false,
|
||||||
showLabels: false,
|
showLabels: false,
|
||||||
showPatchLabels: false,
|
showPatchLabels: false,
|
||||||
@@ -7629,8 +7743,33 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
|
|||||||
/* global define, vec2 */
|
/* global define, vec2 */
|
||||||
|
|
||||||
|
|
||||||
define('quagga',["code_128_reader", "ean_reader", "input_stream", "image_wrapper", "barcode_locator", "barcode_decoder", "frame_grabber", "html_utils", "config", "events", "camera_access", "image_debug"],
|
define('quagga',[
|
||||||
function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, BarcodeDecoder, FrameGrabber, HtmlUtils, _config, Events, CameraAccess, ImageDebug) {
|
"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(Code128Reader,
|
||||||
|
EANReader,
|
||||||
|
InputStream,
|
||||||
|
ImageWrapper,
|
||||||
|
BarcodeLocator,
|
||||||
|
BarcodeDecoder,
|
||||||
|
FrameGrabber,
|
||||||
|
HtmlUtils,
|
||||||
|
_config,
|
||||||
|
Events,
|
||||||
|
CameraAccess,
|
||||||
|
ImageDebug,
|
||||||
|
CVUtils) {
|
||||||
|
|
||||||
|
|
||||||
var _inputStream,
|
var _inputStream,
|
||||||
@@ -7712,17 +7851,23 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
|||||||
function checkImageConstraints() {
|
function checkImageConstraints() {
|
||||||
var patchSize,
|
var patchSize,
|
||||||
width = _inputStream.getWidth(),
|
width = _inputStream.getWidth(),
|
||||||
height = _inputStream.getHeight();
|
height = _inputStream.getHeight(),
|
||||||
|
halfSample = _config.locator.halfSample,
|
||||||
|
size = {
|
||||||
|
x: Math.floor(width * (halfSample ? 0.5 : 1)),
|
||||||
|
y: Math.floor(height * (halfSample ? 0.5 : 1))
|
||||||
|
};
|
||||||
|
|
||||||
if (_config.locate) {
|
if (_config.locate) {
|
||||||
patchSize = _config.locator.patchSize * ( _config.locator.halfSample ? 0.5 : 1);
|
patchSize = CVUtils.calculatePatchSize(_config.locator.patchSize, size);
|
||||||
if ((width % patchSize) === 0 && (height % patchSize) === 0) {
|
console.log("Patch-Size: " + JSON.stringify(patchSize));
|
||||||
|
if ((width % patchSize.x) === 0 && (height % patchSize.y) === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error("Image dimensions do not comply with the current settings: Width (" +
|
throw new Error("Image dimensions do not comply with the current settings: Width (" +
|
||||||
width + " )and height (" + height +
|
width + " )and height (" + height +
|
||||||
") must a multiple of " + patchSize);
|
") must a multiple of " + patchSize.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canRecord(cb) {
|
function canRecord(cb) {
|
||||||
@@ -8021,17 +8166,18 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
|||||||
},
|
},
|
||||||
canvas : _canvasContainer,
|
canvas : _canvasContainer,
|
||||||
decodeSingle : function(config, resultCallback) {
|
decodeSingle : function(config, resultCallback) {
|
||||||
config.inputStream = {
|
config = HtmlUtils.mergeObjects({
|
||||||
|
inputStream: {
|
||||||
type : "ImageStream",
|
type : "ImageStream",
|
||||||
src : config.src,
|
|
||||||
sequence : false,
|
sequence : false,
|
||||||
size: 800
|
size: 800,
|
||||||
};
|
src: config.src
|
||||||
config.numOfWorkers = 0;
|
},
|
||||||
config.locator = {
|
numOfWorkers: 1,
|
||||||
halfSample: false,
|
locator: {
|
||||||
patchSize: 40
|
halfSample: false
|
||||||
};
|
}
|
||||||
|
}, config);
|
||||||
this.init(config, function() {
|
this.init(config, function() {
|
||||||
Events.once("detected", function(result) {
|
Events.once("detected", function(result) {
|
||||||
_stopped = true;
|
_stopped = true;
|
||||||
|
|||||||
@@ -19,12 +19,14 @@
|
|||||||
/* line 1, ../sass/_viewport.scss */
|
/* line 1, ../sass/_viewport.scss */
|
||||||
#interactive.viewport {
|
#interactive.viewport {
|
||||||
width: 640px;
|
width: 640px;
|
||||||
|
height: 480px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line 6, ../sass/_viewport.scss */
|
/* line 6, ../sass/_viewport.scss */
|
||||||
#interactive.viewport canvas, video {
|
#interactive.viewport canvas, video {
|
||||||
float: left;
|
float: left;
|
||||||
width: 640px;
|
width: 640px;
|
||||||
|
height: 480px;
|
||||||
}
|
}
|
||||||
/* line 10, ../sass/_viewport.scss */
|
/* line 10, ../sass/_viewport.scss */
|
||||||
#interactive.viewport canvas.drawingBuffer, video.drawingBuffer {
|
#interactive.viewport canvas.drawingBuffer, video.drawingBuffer {
|
||||||
@@ -32,19 +34,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* line 16, ../sass/_viewport.scss */
|
/* line 16, ../sass/_viewport.scss */
|
||||||
.controls .reader-group {
|
.controls fieldset {
|
||||||
float: right;
|
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
/* line 19, ../sass/_viewport.scss */
|
||||||
|
.controls .input-group {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
/* line 21, ../sass/_viewport.scss */
|
||||||
|
.controls .input-group input, .controls .input-group button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* line 25, ../sass/_viewport.scss */
|
||||||
|
.controls .reader-config-group {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
/* line 28, ../sass/_viewport.scss */
|
||||||
|
.controls .reader-config-group label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* line 30, ../sass/_viewport.scss */
|
||||||
|
.controls .reader-config-group label span {
|
||||||
|
width: 11rem;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
/* line 37, ../sass/_viewport.scss */
|
||||||
|
.controls:after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
/* line 22, ../sass/_viewport.scss */
|
/* line 44, ../sass/_viewport.scss */
|
||||||
#result_strip {
|
#result_strip {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
border-top: 1px solid #EEE;
|
border-top: 1px solid #EEE;
|
||||||
border-bottom: 1px solid #EEE;
|
border-bottom: 1px solid #EEE;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
/* line 28, ../sass/_viewport.scss */
|
/* line 50, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails {
|
#result_strip ul.thumbnails {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -54,34 +83,34 @@
|
|||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
/* line 37, ../sass/_viewport.scss */
|
/* line 59, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails > li {
|
#result_strip ul.thumbnails > li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
/* line 41, ../sass/_viewport.scss */
|
/* line 63, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails > li .thumbnail {
|
#result_strip ul.thumbnails > li .thumbnail {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
border: 1px dashed #CCC;
|
border: 1px dashed #CCC;
|
||||||
}
|
}
|
||||||
/* line 46, ../sass/_viewport.scss */
|
/* line 68, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails > li .thumbnail img {
|
#result_strip ul.thumbnails > li .thumbnail img {
|
||||||
max-width: 140px;
|
max-width: 140px;
|
||||||
}
|
}
|
||||||
/* line 49, ../sass/_viewport.scss */
|
/* line 71, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails > li .thumbnail .caption {
|
#result_strip ul.thumbnails > li .thumbnail .caption {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
/* line 51, ../sass/_viewport.scss */
|
/* line 73, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails > li .thumbnail .caption h4 {
|
#result_strip ul.thumbnails > li .thumbnail .caption h4 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
/* line 61, ../sass/_viewport.scss */
|
/* line 83, ../sass/_viewport.scss */
|
||||||
#result_strip ul.thumbnails:after {
|
#result_strip ul.thumbnails:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: table;
|
display: table;
|
||||||
|
|||||||
@@ -34,18 +34,55 @@
|
|||||||
access through <code>getUserMedia</code> is still very limited.</p>
|
access through <code>getUserMedia</code> is still very limited.</p>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
|
<fieldset class="input-group">
|
||||||
<input type="file" capture/>
|
<input type="file" capture/>
|
||||||
<fieldset class="reader-group">
|
<button>Rerun</button>
|
||||||
<label>UPC</label>
|
</fieldset>
|
||||||
<input type="radio" name="reader" value="upc" checked />
|
<fieldset class="reader-config-group">
|
||||||
<label>Code39</label>
|
<label>
|
||||||
<input type="radio" name="reader" value="codabar" />
|
<span>Barcode-Type</span>
|
||||||
<label>Code128</label>
|
<select name="decoder_readers">
|
||||||
<input type="radio" name="reader" value="code_128"/>
|
<option value="code_128">Code 128</option>
|
||||||
<label>EAN</label>
|
<option value="code_39">Code 39</option>
|
||||||
<input type="radio" name="reader" value="ean"/>
|
<option value="ean" selected="selected">EAN</option>
|
||||||
<label>Code39</label>
|
<option value="codabar">Codabar</option>
|
||||||
<input type="radio" name="reader" value="code_39"/>
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Resolution (long side)</span>
|
||||||
|
<select name="input-stream_size">
|
||||||
|
<option value="320">320px</option>
|
||||||
|
<option selected="selected" value="640">640px</option>
|
||||||
|
<option value="800">800px</option>
|
||||||
|
<option value="1280">1280px</option>
|
||||||
|
<option value="1600">1600px</option>
|
||||||
|
<option value="1920">1920px</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Patch-Size</span>
|
||||||
|
<select name="locator_patch-size">
|
||||||
|
<option value="x-small">x-small</option>
|
||||||
|
<option value="small">small</option>
|
||||||
|
<option value="medium">medium</option>
|
||||||
|
<option selected="selected" value="large">large</option>
|
||||||
|
<option value="x-large">x-large</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Half-Sample</span>
|
||||||
|
<input type="checkbox" name="locator_half-sample" />
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Workers</span>
|
||||||
|
<select name="numOfWorkers">
|
||||||
|
<option selected="selected" value="0">0</option>
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option value="2">2</option>
|
||||||
|
<option value="4">4</option>
|
||||||
|
<option value="8">8</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div id="result_strip">
|
<div id="result_strip">
|
||||||
|
|||||||
@@ -7,31 +7,104 @@ $(function() {
|
|||||||
reader: "upc"
|
reader: "upc"
|
||||||
},
|
},
|
||||||
attachListeners: function() {
|
attachListeners: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
$(".controls input[type=file]").on("change", function(e) {
|
$(".controls input[type=file]").on("change", function(e) {
|
||||||
if (e.target.files && e.target.files.length) {
|
if (e.target.files && e.target.files.length) {
|
||||||
App.decode(URL.createObjectURL(e.target.files[0]));
|
App.decode(URL.createObjectURL(e.target.files[0]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".controls .reader-group").on("change", "input", function(e) {
|
$(".controls button").on("click", function(e) {
|
||||||
|
var input = document.querySelector(".controls input[type=file]");
|
||||||
|
if (input.files && input.files.length) {
|
||||||
|
App.decode(URL.createObjectURL(input.files[0]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".controls .reader-config-group").on("change", "input, select", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
App.detachListeners();
|
var $target = $(e.target),
|
||||||
App.config.reader = e.target.value;
|
value = $target.attr("type") === "checkbox" ? $target.prop("checked") : $target.val(),
|
||||||
App.init();
|
name = $target.attr("name"),
|
||||||
|
state = self._convertNameToState(name);
|
||||||
|
|
||||||
|
console.log("Value of "+ state + " changed to " + value);
|
||||||
|
self.setState(state, value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_accessByPath: function(obj, path, val) {
|
||||||
|
var parts = path.split('.'),
|
||||||
|
depth = parts.length,
|
||||||
|
setter = (typeof val !== "undefined") ? true : false;
|
||||||
|
|
||||||
|
return parts.reduce(function(o, key, i) {
|
||||||
|
if (setter && (i + 1) === depth) {
|
||||||
|
o[key] = val;
|
||||||
|
}
|
||||||
|
return key in o ? o[key] : {};
|
||||||
|
}, obj);
|
||||||
|
},
|
||||||
|
_convertNameToState: function(name) {
|
||||||
|
return name.replace("_", ".").split("-").reduce(function(result, value) {
|
||||||
|
return result + value.charAt(0).toUpperCase() + value.substring(1);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
detachListeners: function() {
|
detachListeners: function() {
|
||||||
$(".controls input[type=file]").off("change");
|
$(".controls input[type=file]").off("change");
|
||||||
$(".controls .reader-group").off("change", "input");
|
$(".controls .reader-config-group").off("change", "input, select");
|
||||||
|
$(".controls button").off("click");
|
||||||
},
|
},
|
||||||
decode: function(src) {
|
decode: function(src) {
|
||||||
Quagga.decodeSingle({
|
var self = this,
|
||||||
decoder: {
|
config = $.extend({}, self.state, {src: src});
|
||||||
readers : [App.config.reader + '_reader']
|
|
||||||
|
Quagga.decodeSingle(config, function(result) {});
|
||||||
},
|
},
|
||||||
locate : true,
|
setState: function(path, value) {
|
||||||
src : src
|
var self = this;
|
||||||
}, function(result) {});
|
|
||||||
|
if (typeof self._accessByPath(self.inputMapper, path) === "function") {
|
||||||
|
value = self._accessByPath(self.inputMapper, path)(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
self._accessByPath(self.state, path, value);
|
||||||
|
|
||||||
|
console.log(JSON.stringify(self.state));
|
||||||
|
App.detachListeners();
|
||||||
|
App.init();
|
||||||
|
},
|
||||||
|
inputMapper: {
|
||||||
|
inputStream: {
|
||||||
|
size: function(value){
|
||||||
|
return parseInt(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
numOfWorkers: function(value) {
|
||||||
|
return parseInt(value);
|
||||||
|
},
|
||||||
|
decoder: {
|
||||||
|
readers: function(value) {
|
||||||
|
return [value + "_reader"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
inputStream: {
|
||||||
|
size: 640
|
||||||
|
},
|
||||||
|
locator: {
|
||||||
|
patchSize: "large",
|
||||||
|
halfSample: false
|
||||||
|
},
|
||||||
|
numOfWorkers: 0,
|
||||||
|
decoder: {
|
||||||
|
readers: ["ean_reader"],
|
||||||
|
showFrequency: true,
|
||||||
|
showPattern: true
|
||||||
|
},
|
||||||
|
locate: true,
|
||||||
|
src: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
.reader-group {
|
fieldset {
|
||||||
float: right;
|
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
.input-group {
|
||||||
|
float: left;
|
||||||
|
input, button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.reader-config-group {
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
span {
|
||||||
|
width: 11rem;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content:'';
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#result_strip{
|
#result_strip{
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<fieldset class="reader-group">
|
<fieldset class="reader-group">
|
||||||
<label>UPC</label>
|
<label>UPC</label>
|
||||||
<input type="radio" name="reader" value="upc" checked />
|
<input type="radio" name="reader" value="upc" checked />
|
||||||
<label>Code39</label>
|
<label>Codabar</label>
|
||||||
<input type="radio" name="reader" value="codabar" />
|
<input type="radio" name="reader" value="codabar" />
|
||||||
<label>Code39</label>
|
<label>Code39</label>
|
||||||
<input type="radio" name="reader" value="code_39" />
|
<input type="radio" name="reader" value="code_39" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "An advanced barcode-scanner written in JavaScript",
|
"description": "An advanced barcode-scanner written in JavaScript",
|
||||||
"main": "dist/quagga.js",
|
"main": "dist/quagga.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt": "~0.4.5",
|
"grunt": "~0.4.6",
|
||||||
"grunt-contrib-jshint": "~0.10.0",
|
"grunt-contrib-jshint": "~0.10.0",
|
||||||
"grunt-contrib-nodeunit": "~0.4.1",
|
"grunt-contrib-nodeunit": "~0.4.1",
|
||||||
"grunt-contrib-uglify": "~0.5.0",
|
"grunt-contrib-uglify": "~0.5.0",
|
||||||
|
|||||||
@@ -97,18 +97,25 @@ define(["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_re
|
|||||||
* @param {Number} angle
|
* @param {Number} angle
|
||||||
*/
|
*/
|
||||||
function getExtendedLine(line, angle, ext) {
|
function getExtendedLine(line, angle, ext) {
|
||||||
|
function extendLine(amount) {
|
||||||
var extension = {
|
var extension = {
|
||||||
y : ext * Math.sin(angle),
|
y : amount * Math.sin(angle),
|
||||||
x : ext * Math.cos(angle)
|
x : amount * Math.cos(angle)
|
||||||
};
|
};
|
||||||
|
|
||||||
line[0].y -= extension.y;
|
line[0].y -= extension.y;
|
||||||
line[0].x -= extension.x;
|
line[0].x -= extension.x;
|
||||||
line[1].y += extension.y;
|
line[1].y += extension.y;
|
||||||
line[1].x += extension.x;
|
line[1].x += extension.x;
|
||||||
|
}
|
||||||
|
|
||||||
// check if inside image
|
// check if inside image
|
||||||
if (!inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
|
extendLine(ext);
|
||||||
|
while (ext > 1 && !inputImageWrapper.inImageWithBorder(line[0], 0) || !inputImageWrapper.inImageWithBorder(line[1], 0)) {
|
||||||
|
ext -= Math.floor(ext/2);
|
||||||
|
extendLine(-ext);
|
||||||
|
}
|
||||||
|
if (ext <= 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
@@ -188,6 +195,12 @@ define(["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_re
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLineLength(line) {
|
||||||
|
return Math.sqrt(
|
||||||
|
Math.pow(Math.abs(line[1].y - line[0].y), 2) +
|
||||||
|
Math.pow(Math.abs(line[1].x - line[0].x), 2));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* With the help of the configured readers (Code128 or EAN) this function tries to detect a
|
* With the help of the configured readers (Code128 or EAN) this function tries to detect a
|
||||||
* valid barcode pattern within the given area.
|
* valid barcode pattern within the given area.
|
||||||
@@ -198,15 +211,17 @@ define(["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_re
|
|||||||
var line,
|
var line,
|
||||||
lineAngle,
|
lineAngle,
|
||||||
ctx = _canvas.ctx.overlay,
|
ctx = _canvas.ctx.overlay,
|
||||||
result;
|
result,
|
||||||
|
lineLength;
|
||||||
|
|
||||||
if (config.drawBoundingBox && ctx) {
|
if (config.drawBoundingBox && ctx) {
|
||||||
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
|
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
line = getLine(box);
|
line = getLine(box);
|
||||||
|
lineLength = getLineLength(line);
|
||||||
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
||||||
line = getExtendedLine(line, lineAngle, 10);
|
line = getExtendedLine(line, lineAngle, Math.floor(lineLength*0.07));
|
||||||
if(line === null){
|
if(line === null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
|
|||||||
_currentImageWrapper = _inputImageWrapper;
|
_currentImageWrapper = _inputImageWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patchSize = {
|
_patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
|
||||||
x : _config.patchSize * ( _config.halfSample ? 0.5 : 1),
|
|
||||||
y : _config.patchSize * ( _config.halfSample ? 0.5 : 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
_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;
|
||||||
|
|||||||
@@ -107,23 +107,23 @@ define(function() {
|
|||||||
extrema = [],
|
extrema = [],
|
||||||
currentDir,
|
currentDir,
|
||||||
dir,
|
dir,
|
||||||
threshold = (max - min) / 8,
|
threshold = (max - min) / 12,
|
||||||
rThreshold = -threshold,
|
rThreshold = -threshold,
|
||||||
i,
|
i,
|
||||||
j;
|
j;
|
||||||
|
|
||||||
// 1. find extrema
|
// 1. find extrema
|
||||||
currentDir = line[0] > center ? Slope.DIR.DOWN : Slope.DIR.UP;
|
currentDir = line[0] > center ? Slope.DIR.UP : Slope.DIR.DOWN;
|
||||||
extrema.push({
|
extrema.push({
|
||||||
pos : 0,
|
pos : 0,
|
||||||
val : line[0]
|
val : line[0]
|
||||||
});
|
});
|
||||||
for ( i = 0; i < line.length - 1; i++) {
|
for ( i = 0; i < line.length - 1; i++) {
|
||||||
slope = (line[i + 1] - line[i]);
|
slope = (line[i + 1] - line[i]);
|
||||||
if (slope < rThreshold) {
|
if (slope < rThreshold && line[i + 1] < (center*1.5)) {
|
||||||
dir = Slope.DIR.UP;
|
|
||||||
} else if (slope > threshold) {
|
|
||||||
dir = Slope.DIR.DOWN;
|
dir = Slope.DIR.DOWN;
|
||||||
|
} else if (slope > threshold && line[i + 1] > (center*0.5)) {
|
||||||
|
dir = Slope.DIR.UP;
|
||||||
} else {
|
} else {
|
||||||
dir = currentDir;
|
dir = currentDir;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,18 +23,18 @@ define(function(){
|
|||||||
decoder:{
|
decoder:{
|
||||||
drawBoundingBox: false,
|
drawBoundingBox: false,
|
||||||
showFrequency: false,
|
showFrequency: false,
|
||||||
drawScanline: true,
|
drawScanline: false,
|
||||||
showPattern: true,
|
showPattern: false,
|
||||||
readers: [
|
readers: [
|
||||||
'code_128_reader'
|
'code_128_reader'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
halfSample: true,
|
halfSample: true,
|
||||||
patchSize: 64,
|
patchSize: "medium", // x-small, small, medium, large, x-large
|
||||||
showCanvas: true,
|
showCanvas: false,
|
||||||
showPatches: false,
|
showPatches: false,
|
||||||
showFoundPatches: true,
|
showFoundPatches: false,
|
||||||
showSkeleton: false,
|
showSkeleton: false,
|
||||||
showLabels: false,
|
showLabels: false,
|
||||||
showPatchLabels: false,
|
showPatchLabels: false,
|
||||||
|
|||||||
@@ -539,6 +539,71 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
|
|||||||
return rgb;
|
return rgb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CVUtils._computeDivisors = function(n) {
|
||||||
|
var largeDivisors = [],
|
||||||
|
divisors = [],
|
||||||
|
i;
|
||||||
|
|
||||||
|
for (i = 1; i < Math.sqrt(n) + 1; i++) {
|
||||||
|
if (n % i === 0) {
|
||||||
|
divisors.push(i);
|
||||||
|
if (i !== n/i) {
|
||||||
|
largeDivisors.unshift(Math.floor(n/i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return divisors.concat(largeDivisors);
|
||||||
|
};
|
||||||
|
|
||||||
|
CVUtils._computeIntersection = function(arr1, arr2) {
|
||||||
|
var i = 0,
|
||||||
|
j = 0,
|
||||||
|
result = [];
|
||||||
|
|
||||||
|
while (i < arr1.length && j < arr2.length) {
|
||||||
|
if (arr1[i] === arr2[j]) {
|
||||||
|
result.push(arr1[i]);
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
} else if (arr1[i] > arr2[j]) {
|
||||||
|
j++;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
CVUtils.calculatePatchSize = function(patchSize, imgSize) {
|
||||||
|
var divisorsX = this._computeDivisors(imgSize.x),
|
||||||
|
divisorsY = this._computeDivisors(imgSize.y),
|
||||||
|
wideSide = Math.max(imgSize.x, imgSize.y),
|
||||||
|
common = this._computeIntersection(divisorsX, divisorsY),
|
||||||
|
nrOfPatchesMap = {
|
||||||
|
"x-small": 60,
|
||||||
|
"small": 32,
|
||||||
|
"medium": 20,
|
||||||
|
"large": 15,
|
||||||
|
"x-large": 10
|
||||||
|
},
|
||||||
|
nrOfPatches = nrOfPatchesMap[patchSize] || nrOfPatchesMap.medium,
|
||||||
|
i = 0,
|
||||||
|
found = common[Math.floor(common.length/2)],
|
||||||
|
desiredPatchSize = wideSide/nrOfPatches;
|
||||||
|
|
||||||
|
while(i < (common.length - 1) && common[i] < desiredPatchSize) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
if (Math.abs(common[i] - desiredPatchSize) > Math.abs(common[i-1] - desiredPatchSize)) {
|
||||||
|
found = common[i-1];
|
||||||
|
} else {
|
||||||
|
found = common[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {x: found, y: found};
|
||||||
|
};
|
||||||
|
|
||||||
return (CVUtils);
|
return (CVUtils);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,39 @@ define(
|
|||||||
throw BarcodeReader.PatternNotFoundException;
|
throw BarcodeReader.PatternNotFoundException;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EANReader.prototype._findStart = function() {
|
||||||
|
var self = this,
|
||||||
|
leadingWhitespaceStart,
|
||||||
|
offset = self._nextSet(self._row),
|
||||||
|
startInfo;
|
||||||
|
|
||||||
|
while(!startInfo) {
|
||||||
|
startInfo = self._findPattern(self.START_PATTERN, offset);
|
||||||
|
leadingWhitespaceStart = startInfo.start - (startInfo.end - startInfo.start);
|
||||||
|
if (leadingWhitespaceStart >= 0) {
|
||||||
|
if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
|
||||||
|
return startInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset = startInfo.end;
|
||||||
|
startInfo = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EANReader.prototype._findEnd = function(offset) {
|
||||||
|
var self = this,
|
||||||
|
trailingWhitespaceEnd,
|
||||||
|
endInfo = self._findPattern(self.STOP_PATTERN, offset);
|
||||||
|
|
||||||
|
trailingWhitespaceEnd = endInfo.end + (endInfo.end - endInfo.start);
|
||||||
|
if (trailingWhitespaceEnd < self._row.length) {
|
||||||
|
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
|
||||||
|
return endInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
EANReader.prototype._decode = function() {
|
EANReader.prototype._decode = function() {
|
||||||
var startInfo,
|
var startInfo,
|
||||||
self = this,
|
self = this,
|
||||||
@@ -177,7 +210,7 @@ define(
|
|||||||
decodedCodes = [];
|
decodedCodes = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
startInfo = self._findPattern(self.START_PATTERN);
|
startInfo = self._findStart();
|
||||||
code = {
|
code = {
|
||||||
code : startInfo.code,
|
code : startInfo.code,
|
||||||
start : startInfo.start,
|
start : startInfo.start,
|
||||||
@@ -215,7 +248,11 @@ define(
|
|||||||
result.push(code.code);
|
result.push(code.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
code = self._findPattern(self.STOP_PATTERN, code.end);
|
code = self._findEnd(code.end);
|
||||||
|
if (code === null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
decodedCodes.push(code);
|
decodedCodes.push(code);
|
||||||
|
|
||||||
// Checksum
|
// Checksum
|
||||||
|
|||||||
@@ -2,8 +2,33 @@
|
|||||||
/* global define, vec2 */
|
/* global define, vec2 */
|
||||||
|
|
||||||
|
|
||||||
define(["code_128_reader", "ean_reader", "input_stream", "image_wrapper", "barcode_locator", "barcode_decoder", "frame_grabber", "html_utils", "config", "events", "camera_access", "image_debug"],
|
define([
|
||||||
function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, BarcodeDecoder, FrameGrabber, HtmlUtils, _config, Events, CameraAccess, ImageDebug) {
|
"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(Code128Reader,
|
||||||
|
EANReader,
|
||||||
|
InputStream,
|
||||||
|
ImageWrapper,
|
||||||
|
BarcodeLocator,
|
||||||
|
BarcodeDecoder,
|
||||||
|
FrameGrabber,
|
||||||
|
HtmlUtils,
|
||||||
|
_config,
|
||||||
|
Events,
|
||||||
|
CameraAccess,
|
||||||
|
ImageDebug,
|
||||||
|
CVUtils) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var _inputStream,
|
var _inputStream,
|
||||||
@@ -85,17 +110,23 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
|||||||
function checkImageConstraints() {
|
function checkImageConstraints() {
|
||||||
var patchSize,
|
var patchSize,
|
||||||
width = _inputStream.getWidth(),
|
width = _inputStream.getWidth(),
|
||||||
height = _inputStream.getHeight();
|
height = _inputStream.getHeight(),
|
||||||
|
halfSample = _config.locator.halfSample,
|
||||||
|
size = {
|
||||||
|
x: Math.floor(width * (halfSample ? 0.5 : 1)),
|
||||||
|
y: Math.floor(height * (halfSample ? 0.5 : 1))
|
||||||
|
};
|
||||||
|
|
||||||
if (_config.locate) {
|
if (_config.locate) {
|
||||||
patchSize = _config.locator.patchSize * ( _config.locator.halfSample ? 0.5 : 1);
|
patchSize = CVUtils.calculatePatchSize(_config.locator.patchSize, size);
|
||||||
if ((width % patchSize) === 0 && (height % patchSize) === 0) {
|
console.log("Patch-Size: " + JSON.stringify(patchSize));
|
||||||
|
if ((width % patchSize.x) === 0 && (height % patchSize.y) === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error("Image dimensions do not comply with the current settings: Width (" +
|
throw new Error("Image dimensions do not comply with the current settings: Width (" +
|
||||||
width + " )and height (" + height +
|
width + " )and height (" + height +
|
||||||
") must a multiple of " + patchSize);
|
") must a multiple of " + patchSize.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canRecord(cb) {
|
function canRecord(cb) {
|
||||||
@@ -394,17 +425,18 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
|||||||
},
|
},
|
||||||
canvas : _canvasContainer,
|
canvas : _canvasContainer,
|
||||||
decodeSingle : function(config, resultCallback) {
|
decodeSingle : function(config, resultCallback) {
|
||||||
config.inputStream = {
|
config = HtmlUtils.mergeObjects({
|
||||||
|
inputStream: {
|
||||||
type : "ImageStream",
|
type : "ImageStream",
|
||||||
src : config.src,
|
|
||||||
sequence : false,
|
sequence : false,
|
||||||
size: 800
|
size: 800,
|
||||||
};
|
src: config.src
|
||||||
config.numOfWorkers = 0;
|
},
|
||||||
config.locator = {
|
numOfWorkers: 1,
|
||||||
halfSample: false,
|
locator: {
|
||||||
patchSize: 40
|
halfSample: false
|
||||||
};
|
}
|
||||||
|
}, config);
|
||||||
this.init(config, function() {
|
this.init(config, function() {
|
||||||
Events.once("detected", function(result) {
|
Events.once("detected", function(result) {
|
||||||
_stopped = true;
|
_stopped = true;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 710 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 674 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 797 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 736 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 774 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 748 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 741 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 562 KiB After Width: | Height: | Size: 115 KiB |