Updated version to 0.6.0

gh-pages
Christoph Oberhofer 10 years ago
parent 902dc369d7
commit 380c4b6ff8

@ -7,12 +7,15 @@ 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>, <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>
<p>This example let's you select an image from your local filesystem.
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>This also works great on a wide range of mobile-phones where the
camera access through <code>getUserMedia</code> is still very
limited. </p>
<p>If the default configuration does not suit your use-case, you can
adjust various parameters of the localization and decoding process.</p>
<div class="controls">
<fieldset class="input-group">
<input type="file" accept="image/*;capture=camera"/>
@ -25,6 +28,9 @@ showInMenu: false
<option value="code_128" selected="selected">Code 128</option>
<option value="code_39">Code 39</option>
<option value="ean">EAN</option>
<option value="ean_8">EAN-8</option>
<option value="upc">UPC</option>
<option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option>
</select>
</label>

@ -1240,23 +1240,50 @@ define(
throw BarcodeReader.PatternNotFoundException;
};
EANReader.prototype._decode = function() {
var startInfo,
self = this,
code = null,
result = [],
i,
codeFrequency = 0x0,
decodedCodes = [];
EANReader.prototype._findStart = function() {
var self = this,
leadingWhitespaceStart,
offset = self._nextSet(self._row),
startInfo;
try {
startInfo = self._findPattern(self.START_PATTERN);
code = {
code : startInfo.code,
start : startInfo.start,
end : startInfo.end
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;
}
};
decodedCodes.push(code);
EANReader.prototype._verifyTrailingWhitespace = function(endInfo) {
var self = this,
trailingWhitespaceEnd;
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._findEnd = function(offset, isWhite) {
var self = this,
endInfo = self._findPattern(self.STOP_PATTERN, offset, isWhite, false);
return self._verifyTrailingWhitespace(endInfo);
};
EANReader.prototype._decodePayload = function(code, result, decodedCodes) {
var i,
self = this,
codeFrequency = 0x0;
for ( i = 0; i < 6; i++) {
code = self._decodeCode(code.end);
if (code.code >= self.CODE_G_START) {
@ -1276,7 +1303,7 @@ define(
}
}
code = self._findPattern(self.MIDDLE_PATTERN, code.end, true);
code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
if (code === null) {
return null;
}
@ -1288,7 +1315,30 @@ define(
result.push(code.code);
}
code = self._findPattern(self.STOP_PATTERN, code.end);
return code;
};
EANReader.prototype._decode = function() {
var startInfo,
self = this,
code = null,
result = [],
decodedCodes = [];
try {
startInfo = self._findStart();
code = {
code : startInfo.code,
start : startInfo.start,
end : startInfo.end
};
decodedCodes.push(code);
code = self._decodePayload(code, result, decodedCodes);
code = self._findEnd(code.end, false);
if (!code){
return null;
}
decodedCodes.push(code);
// Checksum
@ -1459,6 +1509,17 @@ define('input_stream',["image_loader"], function(ImageLoader) {
}
};
that.clearEventHandlers = function() {
_eventNames.forEach(function(eventName) {
var handlers = _eventHandlers[eventName];
if (handlers && handlers.length > 0) {
handlers.forEach(function(handler) {
video.removeEventListener(eventName, handler);
});
}
});
};
that.trigger = function(eventName, args) {
var j,
handlers = _eventHandlers[eventName];
@ -6384,23 +6445,23 @@ define('bresenham',[],function() {
extrema = [],
currentDir,
dir,
threshold = (max - min) / 8,
threshold = (max - min) / 12,
rThreshold = -threshold,
i,
j;
// 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({
pos : 0,
val : line[0]
});
for ( i = 0; i < line.length - 1; i++) {
slope = (line[i + 1] - line[i]);
if (slope < rThreshold) {
dir = Slope.DIR.UP;
} else if (slope > threshold) {
if (slope < rThreshold && line[i + 1] < (center*1.5)) {
dir = Slope.DIR.DOWN;
} else if (slope > threshold && line[i + 1] > (center*0.5)) {
dir = Slope.DIR.UP;
} else {
dir = currentDir;
}
@ -6995,14 +7056,221 @@ define(
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_reader', 'code_39_reader', 'codabar_reader'], function(Bresenham, ImageDebug, Code128Reader, EANReader, Code39Reader, CodabarReader) {
define(
'upc_reader',[
"./ean_reader"
],
function(EANReader) {
function UPCReader() {
EANReader.call(this);
}
UPCReader.prototype = Object.create(EANReader.prototype);
UPCReader.prototype.constructor = UPCReader;
UPCReader.prototype._decode = function() {
var result = EANReader.prototype._decode.call(this);
if (result && result.code && result.code.length === 13 && result.code.charAt(0) === "0") {
result.code = result.code.substring(1);
return result;
}
return null;
};
return (UPCReader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(
'ean_8_reader',[
"./ean_reader"
],
function(EANReader) {
function EAN8Reader() {
EANReader.call(this);
}
EAN8Reader.prototype = Object.create(EANReader.prototype);
EAN8Reader.prototype.constructor = EAN8Reader;
EAN8Reader.prototype._decodePayload = function(code, result, decodedCodes) {
var i,
self = this;
for ( i = 0; i < 4; i++) {
code = self._decodeCode(code.end);
result.push(code.code);
decodedCodes.push(code);
}
code = self._findPattern(self.MIDDLE_PATTERN, code.end, true);
if (code === null) {
return null;
}
decodedCodes.push(code);
for ( i = 0; i < 4; i++) {
code = self._decodeCode(code.end, self.CODE_G_START);
decodedCodes.push(code);
result.push(code.code);
}
return code;
};
return (EAN8Reader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(
'upc_e_reader',[
"./ean_reader"
],
function(EANReader) {
function UPCEReader() {
EANReader.call(this);
}
var properties = {
CODE_FREQUENCY : {value: [
[ 56, 52, 50, 49, 44, 38, 35, 42, 41, 37 ],
[7, 11, 13, 14, 19, 25, 28, 21, 22, 26]]},
STOP_PATTERN: { value: [1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7]}
};
UPCEReader.prototype = Object.create(EANReader.prototype, properties);
UPCEReader.prototype.constructor = UPCEReader;
UPCEReader.prototype._decodePayload = function(code, result, decodedCodes) {
var i,
self = this,
codeFrequency = 0x0;
for ( i = 0; i < 6; i++) {
code = self._decodeCode(code.end);
if (code.code >= self.CODE_G_START) {
code.code = code.code - self.CODE_G_START;
codeFrequency |= 1 << (5 - i);
} else {
codeFrequency |= 0 << (5 - i);
}
result.push(code.code);
decodedCodes.push(code);
}
self._determineParity(codeFrequency, result);
return code;
};
UPCEReader.prototype._determineParity = function(codeFrequency, result) {
var self =this,
i,
nrSystem;
for (nrSystem = 0; nrSystem < self.CODE_FREQUENCY.length; nrSystem++){
for ( i = 0; i < self.CODE_FREQUENCY[nrSystem].length; i++) {
if (codeFrequency === self.CODE_FREQUENCY[nrSystem][i]) {
result.unshift(nrSystem);
result.push(i);
return;
}
}
}
};
UPCEReader.prototype._convertToUPCA = function(result) {
var upca = [result[0]],
lastDigit = result[result.length - 2];
if (lastDigit <= 2) {
upca = upca.concat(result.slice(1, 3))
.concat([lastDigit, 0, 0, 0, 0])
.concat(result.slice(3, 6));
} else if (lastDigit === 3) {
upca = upca.concat(result.slice(1, 4))
.concat([0 ,0, 0, 0, 0])
.concat(result.slice(4,6));
} else if (lastDigit === 4) {
upca = upca.concat(result.slice(1, 5))
.concat([0, 0, 0, 0, 0, result[5]]);
} else {
upca = upca.concat(result.slice(1, 6))
.concat([0, 0, 0, 0, lastDigit]);
}
upca.push(result[result.length - 1]);
return upca;
};
UPCEReader.prototype._checksum = function(result) {
return EANReader.prototype._checksum.call(this, this._convertToUPCA(result));
};
UPCEReader.prototype._findEnd = function(offset, isWhite) {
isWhite = true;
return EANReader.prototype._findEnd.call(this, offset, isWhite);
};
UPCEReader.prototype._verifyTrailingWhitespace = function(endInfo) {
var self = this,
trailingWhitespaceEnd;
trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start)/2);
if (trailingWhitespaceEnd < self._row.length) {
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
return endInfo;
}
}
};
return (UPCEReader);
}
);
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define('barcode_decoder',[
"bresenham",
"image_debug",
'code_128_reader',
'ean_reader',
'code_39_reader',
'codabar_reader',
'upc_reader',
'ean_8_reader',
'upc_e_reader'
], function(
Bresenham,
ImageDebug,
Code128Reader,
EANReader,
Code39Reader,
CodabarReader,
UPCReader,
EAN8Reader,
UPCEReader) {
var readers = {
code_128_reader: Code128Reader,
ean_reader: EANReader,
ean_8_reader: EAN8Reader,
code_39_reader: Code39Reader,
codabar_reader: CodabarReader
codabar_reader: CodabarReader,
upc_reader: UPCReader,
upc_e_reader: UPCEReader
};
var BarcodeDecoder = {
create : function(config, inputImageWrapper) {
@ -7090,18 +7358,25 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
* @param {Number} angle
*/
function getExtendedLine(line, angle, ext) {
function extendLine(amount) {
var extension = {
y : ext * Math.sin(angle),
x : ext * Math.cos(angle)
y : amount * Math.sin(angle),
x : amount * Math.cos(angle)
};
line[0].y -= extension.y;
line[0].x -= extension.x;
line[1].y += extension.y;
line[1].x += extension.x;
}
// 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 line;
@ -7181,6 +7456,12 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
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
* valid barcode pattern within the given area.
@ -7191,15 +7472,17 @@ define('barcode_decoder',["bresenham", "image_debug", 'code_128_reader', 'ean_re
var line,
lineAngle,
ctx = _canvas.ctx.overlay,
result;
result,
lineLength;
if (config.drawBoundingBox && ctx) {
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
}
line = getLine(box);
lineLength = getLineLength(line);
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.1));
if(line === null){
return null;
}
@ -7531,7 +7814,8 @@ define('events',[],function() {
define('camera_access',["html_utils"], function(HtmlUtils) {
var streamRef;
var streamRef,
loadedDataHandler;
/**
* Wraps browser-specific getUserMedia
@ -7547,17 +7831,7 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
}, failure);
}
/**
* Tries to attach the camera-stream to a given video-element
* and calls the callback function when the content is ready
* @param {Object} constraints
* @param {Object} video
* @param {Object} callback
*/
function initCamera(constraints, video, callback) {
getUserMedia(constraints, function(src) {
video.src = src;
video.addEventListener('loadeddata', function() {
function loadedData(video, callback) {
var attempts = 10;
function checkVideo() {
@ -7573,9 +7847,24 @@ define('camera_access',["html_utils"], function(HtmlUtils) {
}
attempts--;
}
checkVideo();
}, false);
}
/**
* Tries to attach the camera-stream to a given video-element
* and calls the callback function when the content is ready
* @param {Object} constraints
* @param {Object} video
* @param {Object} callback
*/
function initCamera(constraints, video, callback) {
getUserMedia(constraints, function(src) {
video.src = src;
if (loadedDataHandler) {
video.removeEventListener("loadeddata", loadedDataHandler, false);
}
loadedDataHandler = loadedData.bind(null, video, callback);
video.addEventListener('loadeddata', loadedDataHandler, false);
video.play();
}, function(e) {
console.log(e);
@ -8064,8 +8353,14 @@ function(Code128Reader,
},
stop : function() {
_stopped = true;
_workerPool.forEach(function(workerThread) {
workerThread.worker.terminate();
console.log("Worker terminated!");
});
_workerPool.length = 0;
if (_config.inputStream.type === "LiveStream") {
CameraAccess.release();
_inputStream.clearEventHandlers();
}
},
pause: function() {

File diff suppressed because one or more lines are too long

@ -6,23 +6,64 @@ showInMenu: false
<section id="container" class="container">
<h3>The user's camera</h3>
<p>If your platform supports the <strong>getUserMedia</strong> API call, you can try the real-time locating and decoding features.
Simply allow the page to access your web-cam and point it to a barcode. You can switch between <strong>Code128</strong>
and <strong>EAN</strong> to test different scenarios.
It works best if your camera has built-in auto-focus.
</p>
<p>If your platform supports the <strong>getUserMedia</strong> API call, you
can try the real-time locating and decoding features.
Simply allow the page to access your web-cam and point it to a barcode.</p>
<p>The various options available allow you to adjust the decoding
process to your needs (Type of barcode, resolution, ...)</p>
<div class="controls">
<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 class="input-group">
<button class="stop">Stop</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="ean_8">EAN-8</option>
<option value="upc">UPC</option>
<option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option>
</select>
</label>
<label>
<span>Resolution (long side)</span>
<select name="input-stream_constraints">
<option value="320x240">320px</option>
<option selected="selected" value="640x480">640px</option>
<option value="800x600">800px</option>
<option value="1280x720">1280px</option>
<option value="1600x960">1600px</option>
<option value="1920x1080">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" checked="checked" name="locator_half-sample" />
</label>
<label>
<span>Workers</span>
<select name="numOfWorkers">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option selected="selected" value="4">4</option>
<option value="8">8</option>
</select>
</label>
</fieldset>
<br clear="all" />
</div>
<div id="result_strip">
<ul class="thumbnails"></ul>

@ -1,27 +1,103 @@
$(function() {
var App = {
init : function() {
Quagga.init({
inputStream : {
name : "Live",
type : "LiveStream"
},
decoder : {
readers : ["code_128_reader"]
}
}, function() {
Quagga.init(this.state, function() {
App.attachListeners();
Quagga.start();
});
},
attachListeners : function() {
$(".controls .reader-group").on("change", "input", function(e) {
attachListeners: function() {
var self = this;
$(".controls").on("click", "button.stop", function(e) {
e.preventDefault();
Quagga.setReaders([e.target.value + "_reader"]);
Quagga.stop();
});
$(".controls .reader-config-group").on("change", "input, select", function(e) {
e.preventDefault();
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);
});
},
detachListeners : function() {
$(".controls .reader-group").off("change", "input");
_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").off("click", "button.stop");
$(".controls .reader-config-group").off("change", "input, select");
},
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();
Quagga.stop();
App.init();
},
inputMapper: {
inputStream: {
constraints: function(value){
var values = value.split('x');
return {
width: parseInt(values[0]),
height: parseInt(values[1]),
facing: "environment"
}
}
},
numOfWorkers: function(value) {
return parseInt(value);
},
decoder: {
readers: function(value) {
return [value + "_reader"];
}
}
},
state: {
inputStream: {
type : "LiveStream",
constraints: {
width: 640,
height: 480,
facing: "environment" // or user
}
},
locator: {
patchSize: "medium",
halfSample: true
},
numOfWorkers: 4,
decoder: {
readers : ["code_128_reader"]
},
locate: true
},
lastResult : null
};

@ -7,23 +7,27 @@ showInMenu: false
<section id="container" class="container">
<h3>Working with static images</h3>
<p>This examples uses static image files as input which are loaded from the server on startup.
The locating and decoding process takes place inside the browser.
Hit the <strong>next</strong> button to try a different image. You can also switch between
two different test-sets. Each of those contains 10 images, demonstrating the capabilities of decoding
<strong>Code128</strong> and <strong>EAN</strong> encoded barcodes.
<p>This examples uses static image files as input which are loaded from
the server on startup. The locating and decoding process takes place
inside the browser. Hit the <strong>next</strong> button to try a
different image. You can also switch between different test-sets,
depending on the barcode-type.
</p>
<div class="controls">
<fieldset class="input-group">
<button class="next">Next</button>
<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="reader-config-group">
<span>Barcode-Type</span>
<select name="decoder_readers;input-stream_src">
<option value="code_128" selected="selected">Code 128</option>
<option value="code_39">Code 39</option>
<option value="ean">EAN</option>
<option value="ean_8">EAN-8</option>
<option value="upc">UPC</option>
<option value="upc_e">UPC-E</option>
<option value="codabar">Codabar</option>
</select>
</fieldset>
</div>
<div id="result_strip">

@ -1,16 +1,7 @@
$(function() {
var App = {
init: function() {
Quagga.init({
inputStream: { name: "Test",
type: "ImageStream",
src: site.baseurl + "/test/fixtures/" + App.config.reader + "/",
length: App.config.length
},
decoder : {
readers : [App.config.reader + "_reader"]
}
}, function() {
Quagga.init(this.state, function() {
App.attachListeners();
Quagga.start();
});
@ -20,22 +11,85 @@ $(function() {
length: 10
},
attachListeners: function() {
var self = this;
$(".controls").on("click", "button.next", function(e) {
e.preventDefault();
Quagga.start();
});
$(".controls .reader-group").on("change", "input", function(e) {
$(".controls .reader-config-group").on("change", "input, select", function(e) {
e.preventDefault();
App.detachListeners();
Quagga.stop();
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"),
states = self._convertNameToStates(name);
console.log("Value of "+ states + " changed to " + value);
self.setState(states, value);
});
},
detachListeners: function() {
$(".controls").off("click", "button.next");
$(".controls .reader-group").off("change", "input");
$(".controls .reader-config-group").off("change", "input, select");
},
_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);
},
_convertNameToStates: function(names) {
return names.split(";").map(this._convertNameToState.bind(this));
},
_convertNameToState: function(name) {
return name.replace("_", ".").split("-").reduce(function(result, value) {
return result + value.charAt(0).toUpperCase() + value.substring(1);
});
},
setState: function(paths, value) {
var self = this;
paths.forEach(function(path) {
var mappedValue;
if (typeof self._accessByPath(self.inputMapper, path) === "function") {
mappedValue = self._accessByPath(self.inputMapper, path)(value);
}
self._accessByPath(self.state, path, mappedValue);
});
console.log(JSON.stringify(self.state));
App.detachListeners();
Quagga.stop();
App.init();
},
inputMapper: {
decoder: {
readers: function(value) {
return [value + "_reader"];
}
},
inputStream: {
src: function(value) {
return site.baseurl + "/test/fixtures/" + value + "/"
}
}
},
state: {
inputStream: { name: "Test",
type: "ImageStream",
src: site.baseurl + "/test/fixtures/code_128/",
length: 10
},
decoder : {
readers : ["code_128_reader"]
}
}
};

@ -7,16 +7,17 @@ showInMenu: true
quaggaJS
========
- [Changelog](#changelog) (2015-04-25)
- [Changelog](#changelog) (2015-04-30)
## What is QuaggaJS?
QuaggaJS is a barcode-scanner entirely written in JavaScript supporting real-
time localization and decoding of various types of barcodes such as __EAN__,
__CODE128__, __CODE39__ and __CODABAR__. The library is also capable of using
`getUserMedia` to get direct access to the user's camera stream. Although the
code relies on heavy image-processing even recent smartphones are capable of
locating and decoding barcodes in real-time.
__CODE 128__, __CODE 39__, __EAN 8__, __UPC-A__, __UPC-C__ and __CODABAR__.
The library is also capable of using `getUserMedia` to get direct access to
the user's camera stream. Although the code relies on heavy image-processing
even recent smartphones are capable of locating and decoding barcodes in
real-time.
Try some [examples](http://serratus.github.io/quaggaJS/examples) and check out
the blog post ([How barcode-localization works in QuaggaJS][oberhofer_co_how])
@ -298,6 +299,15 @@ work.
## <a name="changelog">Changelog</a>
### 2015-04-30
- Features
- Added support for [UPC-A and UPC-E][upc_wiki] barcodes
- Added support for [EAN-8][ean_8_wiki] barcodes
- Improvements
- Added extended configuration to the
[live-video example]({{ site.baseurl }}/examples/live_w_locator.html)
- Releasing resources when calling ``Quagga.stop()``
### 2015-04-25
- Improvements
- Added extended configuration to the
@ -353,5 +363,7 @@ introduced to the API.
[karmaUrl]: http://karma-runner.github.io/
[code39_wiki]: http://en.wikipedia.org/wiki/Code_39
[codabar_wiki]: http://en.wikipedia.org/wiki/Codabar
[upc_wiki]: http://en.wikipedia.org/wiki/Universal_Product_Code
[ean_8_wiki]: http://en.wikipedia.org/wiki/EAN-8
[oberhofer_co_how]: http://www.oberhofer.co/how-barcode-localization-works-in-quaggajs/
[github_examples]: http://serratus.github.io/quaggaJS/examples

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Loading…
Cancel
Save