mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-12 21:21:42 +08:00
Advanced configuration
This commit is contained in:
+54
-13
@@ -8,21 +8,62 @@ showInMenu: false
|
||||
<section id="container" class="container">
|
||||
<h3>Working with file-input</h3>
|
||||
<p>This example let's you select an image from your local filesystem. QuaggaJS then tries to decode the barcode using
|
||||
the preferred method (<strong>Code128</strong> or <strong>EAN</strong>). There is no server interaction needed as the
|
||||
file is simply accessed through the <a href="http://www.w3.org/TR/file-upload/">File API</a>.</p>
|
||||
the preferred method (<strong>Code128</strong>, <strong>EAN
|
||||
</strong>, <strong>Code 39</strong> or <strong>Codabar</strong>)
|
||||
There is no server interaction needed as the file is simply
|
||||
accessed through the <a href="http://www.w3.org/TR/file-upload/">File API</a>.</p>
|
||||
<p>This also works great on a wide range of mobile-phones where the camera access through <code>getUserMedia</code> is still very limited.</p>
|
||||
<div class="controls">
|
||||
<input type="file" capture/>
|
||||
<fieldset class="reader-group">
|
||||
<label>Code128</label>
|
||||
<input type="radio" name="reader" value="code_128" checked />
|
||||
<label>EAN</label>
|
||||
<input type="radio" name="reader" value="ean" />
|
||||
<label>Code39</label>
|
||||
<input type="radio" name="reader" value="code_39" />
|
||||
<label>Codabar</label>
|
||||
<input type="radio" name="reader" value="codabar" />
|
||||
</fieldset>
|
||||
<fieldset class="input-group">
|
||||
<input type="file" accept="image/*;capture=camera"/>
|
||||
<button>Rerun</button>
|
||||
</fieldset>
|
||||
<fieldset class="reader-config-group">
|
||||
<label>
|
||||
<span>Barcode-Type</span>
|
||||
<select name="decoder_readers">
|
||||
<option value="code_128" selected="selected">Code 128</option>
|
||||
<option value="code_39">Code 39</option>
|
||||
<option value="ean">EAN</option>
|
||||
<option value="codabar">Codabar</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Resolution (long side)</span>
|
||||
<select name="input-stream_size">
|
||||
<option value="320">320px</option>
|
||||
<option value="640">640px</option>
|
||||
<option selected="selected" 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 selected="selected" value="medium">medium</option>
|
||||
<option 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 value="0">0</option>
|
||||
<option value="1" selected="selected">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="4">4</option>
|
||||
<option value="8">8</option>
|
||||
</select>
|
||||
</label>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div id="result_strip">
|
||||
<ul class="thumbnails"></ul>
|
||||
|
||||
+86
-13
@@ -8,31 +8,104 @@ $(function() {
|
||||
length: 10
|
||||
},
|
||||
attachListeners: function() {
|
||||
var self = this;
|
||||
|
||||
$(".controls input[type=file]").on("change", function(e) {
|
||||
if (e.target.files && e.target.files.length) {
|
||||
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();
|
||||
App.detachListeners();
|
||||
App.config.reader = e.target.value;
|
||||
App.init();
|
||||
var $target = $(e.target),
|
||||
value = $target.attr("type") === "checkbox" ? $target.prop("checked") : $target.val(),
|
||||
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() {
|
||||
$(".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) {
|
||||
Quagga.decodeSingle({
|
||||
decoder: {
|
||||
readers : [App.config.reader + '_reader']
|
||||
},
|
||||
locate : true,
|
||||
src : src
|
||||
}, function(result) {});
|
||||
var self = this,
|
||||
config = $.extend({}, self.state, {src: src});
|
||||
|
||||
Quagga.decodeSingle(config, function(result) {});
|
||||
},
|
||||
setState: function(path, value) {
|
||||
var self = this;
|
||||
|
||||
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: 800
|
||||
},
|
||||
locator: {
|
||||
patchSize: "medium",
|
||||
halfSample: false
|
||||
},
|
||||
numOfWorkers: 1,
|
||||
decoder: {
|
||||
readers: ["code_128_reader"]
|
||||
},
|
||||
locate: true,
|
||||
src: null
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+116
-22
@@ -4724,6 +4724,71 @@ define('cv_utils',['cluster', 'glMatrixAddon', "array_helper"], function(Cluster
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -5736,10 +5801,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
|
||||
_currentImageWrapper = _inputImageWrapper;
|
||||
}
|
||||
|
||||
_patchSize = {
|
||||
x : _config.patchSize * ( _config.halfSample ? 0.5 : 1),
|
||||
y : _config.patchSize * ( _config.halfSample ? 0.5 : 1)
|
||||
};
|
||||
_patchSize = CVUtils.calculatePatchSize(_config.patchSize, _currentImageWrapper.size);
|
||||
|
||||
_numPatches.x = _currentImageWrapper.size.x / _patchSize.x | 0;
|
||||
_numPatches.y = _currentImageWrapper.size.y / _patchSize.y | 0;
|
||||
@@ -7355,7 +7417,7 @@ define('config',[],function(){
|
||||
},
|
||||
locator: {
|
||||
halfSample: true,
|
||||
patchSize: 32,
|
||||
patchSize: "medium", // x-small, small, medium, large, x-large
|
||||
showCanvas: false,
|
||||
showPatches: false,
|
||||
showFoundPatches: false,
|
||||
@@ -7597,8 +7659,33 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
|
||||
/* 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"],
|
||||
function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, BarcodeDecoder, FrameGrabber, HtmlUtils, _config, Events, CameraAccess, ImageDebug) {
|
||||
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",
|
||||
"cv_utils"],
|
||||
function(Code128Reader,
|
||||
EANReader,
|
||||
InputStream,
|
||||
ImageWrapper,
|
||||
BarcodeLocator,
|
||||
BarcodeDecoder,
|
||||
FrameGrabber,
|
||||
HtmlUtils,
|
||||
_config,
|
||||
Events,
|
||||
CameraAccess,
|
||||
ImageDebug,
|
||||
CVUtils) {
|
||||
|
||||
|
||||
var _inputStream,
|
||||
@@ -7680,17 +7767,23 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
||||
function checkImageConstraints() {
|
||||
var patchSize,
|
||||
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) {
|
||||
patchSize = _config.locator.patchSize * ( _config.locator.halfSample ? 0.5 : 1);
|
||||
if ((width % patchSize) === 0 && (height % patchSize) === 0) {
|
||||
patchSize = CVUtils.calculatePatchSize(_config.locator.patchSize, size);
|
||||
console.log("Patch-Size: " + JSON.stringify(patchSize));
|
||||
if ((width % patchSize.x) === 0 && (height % patchSize.y) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
throw new Error("Image dimensions do not comply with the current settings: Width (" +
|
||||
width + " )and height (" + height +
|
||||
") must a multiple of " + patchSize);
|
||||
") must a multiple of " + patchSize.x);
|
||||
}
|
||||
|
||||
function canRecord(cb) {
|
||||
@@ -7989,17 +8082,18 @@ function(Code128Reader, EANReader, InputStream, ImageWrapper, BarcodeLocator, Ba
|
||||
},
|
||||
canvas : _canvasContainer,
|
||||
decodeSingle : function(config, resultCallback) {
|
||||
config.inputStream = {
|
||||
type : "ImageStream",
|
||||
src : config.src,
|
||||
sequence : false,
|
||||
size: 800
|
||||
};
|
||||
config.numOfWorkers = 1;
|
||||
config.locator = {
|
||||
halfSample: false,
|
||||
patchSize: 25
|
||||
};
|
||||
config = HtmlUtils.mergeObjects({
|
||||
inputStream: {
|
||||
type : "ImageStream",
|
||||
sequence : false,
|
||||
size: 800,
|
||||
src: config.src
|
||||
},
|
||||
numOfWorkers: 1,
|
||||
locator: {
|
||||
halfSample: false
|
||||
}
|
||||
}, config);
|
||||
this.init(config, function() {
|
||||
Events.once("detected", function(result) {
|
||||
_stopped = true;
|
||||
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user