mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-12 21:21:42 +08:00
Implemented applyConfig for ImageSource; Refactored ImageSource to fit into a class
This commit is contained in:
+26
-13
@@ -53,17 +53,8 @@ $(function() {
|
||||
$(".controls .reader-config-group").off("change", "input, select");
|
||||
$(".controls button").off("click");
|
||||
},
|
||||
decode: function(file) {
|
||||
this.detachListeners();
|
||||
var size = this.state.inputStream.size;
|
||||
console.log("decode...");
|
||||
|
||||
Quagga.fromImage(file, {
|
||||
constraints: {width: size, height: size},
|
||||
locator: this.state.locator,
|
||||
decoder: this.state.decoder,
|
||||
})
|
||||
.then(function(scanner) {
|
||||
detect: function() {
|
||||
var scanner = this.scanner;
|
||||
scanner.detect()
|
||||
.then(function(result) {
|
||||
console.log(result);
|
||||
@@ -78,9 +69,31 @@ $(function() {
|
||||
drawResult(scanner, result);
|
||||
this.attachListeners();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
decode: function(file) {
|
||||
this.detachListeners();
|
||||
var size = this.state.inputStream.size;
|
||||
console.log("decode...");
|
||||
|
||||
if (!this.scanner) {
|
||||
Quagga.fromImage({
|
||||
constraints: {src: file, width: size, height: size},
|
||||
locator: this.state.locator,
|
||||
decoder: this.state.decoder,
|
||||
})
|
||||
.then(function(scanner) {
|
||||
this.scanner = scanner;
|
||||
this.detect();
|
||||
}.bind(this));
|
||||
} else {
|
||||
this.scanner.applyConfig({
|
||||
constraints: {src: file, width: size, height: size},
|
||||
locator: this.state.locator,
|
||||
decoder: this.state.decoder,
|
||||
})
|
||||
.then(this.detect.bind(this));
|
||||
}
|
||||
|
||||
// Quagga.fromCamera(constraints)
|
||||
// Quagga.fromSource();
|
||||
// Quagga.fromPixelCapture();
|
||||
},
|
||||
|
||||
@@ -101,7 +101,8 @@ $(function() {
|
||||
|
||||
console.log(JSON.stringify(this.state));
|
||||
|
||||
this.scanner.applyConfig({
|
||||
this.scanner
|
||||
.applyConfig({
|
||||
constraints: this.state.inputStream.constraints,
|
||||
locator: this.state.locator,
|
||||
decoder: this.state.decoder,
|
||||
|
||||
@@ -3,7 +3,7 @@ import {determineOrientation} from '../common/device';
|
||||
import CameraAccess from './camera_access';
|
||||
import {getViewport} from '../common/utils';
|
||||
import {generateSourceInterface} from './SourceInterface';
|
||||
import {Scope} from './input/SourceScope';
|
||||
import {Scope} from './SourceScope';
|
||||
|
||||
const ConstraintPresets = [
|
||||
{
|
||||
|
||||
+80
-60
@@ -1,64 +1,78 @@
|
||||
import {findTagsInObjectURL} from './exif_helper';
|
||||
import {generateSourceInterface} from './SourceInterface';
|
||||
import {Source} from './SourceInterface';
|
||||
|
||||
export function fromImage(input, constraints = {width: 800, height: 800, channels: 3}) {
|
||||
var $image = null;
|
||||
var src = null;
|
||||
if (typeof input === 'string') {
|
||||
// data or url, or queryString
|
||||
$image = new Image();
|
||||
src = input;
|
||||
} else if (input instanceof HTMLImageElement) {
|
||||
$image = input;
|
||||
} else if (input instanceof File) {
|
||||
$image = new Image();
|
||||
src = URL.createObjectURL(input);
|
||||
} else {
|
||||
return Promise.reject("fromImage needs a src, HTMLImageElement or File");
|
||||
class ImageSource extends Source {
|
||||
constructor() {
|
||||
super("IMAGE");
|
||||
this._$image = null;
|
||||
this._src = null;
|
||||
this.tags = null;
|
||||
this.colorChannels = 3;
|
||||
}
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (src || !$image.complete) {
|
||||
console.log('Adding eventlistener');
|
||||
$image.addEventListener('load', function() {
|
||||
resolve();
|
||||
}, false);
|
||||
$image.addEventListener('error', function(e) {
|
||||
reject(e);
|
||||
}, false);
|
||||
if (src) {
|
||||
console.log(`Setting src = ${src}`);
|
||||
$image.src = src;
|
||||
|
||||
applyConstraints(newConstraints) {
|
||||
this.constraints = newConstraints;
|
||||
this.colorChannels = this.constraints.channels || this.colorChannels;
|
||||
return this._applyInput(this.constraints.src)
|
||||
._loadResource()
|
||||
.then(() => findTagsInObjectURL(this._src, ['orientation']))
|
||||
.then((tags) => {this.tags = tags;})
|
||||
.then(this._determineDimensions.bind(this))
|
||||
.then(() => this);
|
||||
}
|
||||
|
||||
_loadResource() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this._src || !this._$image.complete) {
|
||||
this._$image.addEventListener('load', resolve, false);
|
||||
this._$image.addEventListener('error', reject, false);
|
||||
if (this._src) {
|
||||
console.log(`Setting src = ${this._src}`);
|
||||
this._$image.src = this._src;
|
||||
}
|
||||
} else {
|
||||
return resolve();
|
||||
}
|
||||
})
|
||||
.then(() => findTagsInObjectURL(src, ['orientation']))
|
||||
.then((tags) => {
|
||||
let width = $image.naturalWidth;
|
||||
let height = $image.naturalHeight;
|
||||
if (tags && tags.orientation) {
|
||||
switch (tags.orientation) {
|
||||
});
|
||||
}
|
||||
|
||||
_applyInput(input) {
|
||||
if (typeof input === 'string') {
|
||||
// data or url, or queryString
|
||||
this._$image = new Image();
|
||||
this._src = input;
|
||||
} else if (input instanceof HTMLImageElement) {
|
||||
this._$image = input;
|
||||
} else if (input instanceof File) {
|
||||
this._$image = new Image();
|
||||
this._src = URL.createObjectURL(input);
|
||||
} else {
|
||||
throw new Error("fromImage needs a src, HTMLImageElement or File");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
_determineDimensions() {
|
||||
let width = this._$image.naturalWidth;
|
||||
let height = this._$image.naturalHeight;
|
||||
let desiredWidth = this.constraints.width;
|
||||
if (this.tags && this.tags.orientation) {
|
||||
switch (this.tags.orientation) {
|
||||
case 6:
|
||||
case 8:
|
||||
width = $image.naturalHeight;
|
||||
height = $image.naturalWidth;
|
||||
width = this._$image.naturalHeight;
|
||||
height = this._$image.naturalWidth;
|
||||
}
|
||||
}
|
||||
const imageAR = width / height;
|
||||
const calculatedWidth = imageAR > 1 ? constraints.width : Math.floor((imageAR) * constraints.width);
|
||||
const calculatedHeight = imageAR > 1 ? Math.floor((1 / imageAR) * constraints.width) : constraints.width;
|
||||
const colorChannels = constraints.channels || 3;
|
||||
|
||||
return Object.assign(generateSourceInterface(), {
|
||||
type: "IMAGE",
|
||||
colorChannels,
|
||||
tags,
|
||||
getDimensions() {
|
||||
return {
|
||||
const imageAR = width / height;
|
||||
const calculatedWidth = imageAR > 1 ? desiredWidth : Math.floor((imageAR) * desiredWidth);
|
||||
const calculatedHeight = imageAR > 1 ? Math.floor((1 / imageAR) * desiredWidth) : desiredWidth;
|
||||
|
||||
this._dimensions = {
|
||||
viewport: {
|
||||
width: $image.naturalWidth, // AR
|
||||
height: $image.naturalHeight, // AR
|
||||
width, // AR
|
||||
height, // AR
|
||||
x: 0, // AR
|
||||
y: 0, // AR
|
||||
},
|
||||
@@ -67,16 +81,22 @@ export function fromImage(input, constraints = {width: 800, height: 800, channel
|
||||
height: calculatedHeight, // AR
|
||||
},
|
||||
};
|
||||
},
|
||||
getDrawable: function() {
|
||||
return $image;
|
||||
},
|
||||
getLabel: function() {
|
||||
return $image.src;
|
||||
},
|
||||
getConstraints: function() {
|
||||
return constraints;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return this._dimensions;
|
||||
}
|
||||
|
||||
getDrawable() {
|
||||
return this._$image;
|
||||
}
|
||||
|
||||
getLabel() {
|
||||
return this._$image.src;
|
||||
}
|
||||
}
|
||||
|
||||
export function fromImage(constraints = {width: 800, height: 800, channels: 3}) {
|
||||
const imageSource = new ImageSource();
|
||||
return imageSource.applyConstraints(constraints);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ export function fromSource(source, {target = "#interactive.viewport"} = {}) {
|
||||
|
||||
return {
|
||||
grabFrameData: function grabFrameData({clipping} = {}) {
|
||||
const frame = source.getDrawable();
|
||||
const {viewport, canvas: canvasSize} = source.getDimensions();
|
||||
const sx = viewport.x;
|
||||
const sy = viewport.y;
|
||||
@@ -121,12 +122,12 @@ export function fromSource(source, {target = "#interactive.viewport"} = {}) {
|
||||
return sleep(100).then(grabFrameData);
|
||||
}
|
||||
|
||||
if (!(drawable instanceof HTMLCanvasElement)) {
|
||||
if (!(frame instanceof HTMLCanvasElement)) {
|
||||
drawImage(
|
||||
canvasSize,
|
||||
ctx,
|
||||
source,
|
||||
drawable,
|
||||
frame,
|
||||
sx,
|
||||
sy,
|
||||
sWidth,
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
const viewport = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
class Source {
|
||||
constructor(type) {
|
||||
this.type = type;
|
||||
}
|
||||
getDimensions() {}
|
||||
getConstraints() {}
|
||||
getDrawable() {}
|
||||
applyConstraints() {}
|
||||
getLabel() {}
|
||||
stop() {}
|
||||
getScope() {}
|
||||
}
|
||||
|
||||
const canvas = {
|
||||
height: 0,
|
||||
width: 0,
|
||||
};
|
||||
export {Source};
|
||||
|
||||
export function generateSourceInterface() {
|
||||
return {
|
||||
type: "INTERFACE",
|
||||
getDimensions() {
|
||||
return {
|
||||
viewport,
|
||||
canvas,
|
||||
};
|
||||
},
|
||||
getDimensions() {},
|
||||
getConstraints() {},
|
||||
getDrawable() {},
|
||||
applyConstraints() {},
|
||||
@@ -26,4 +24,4 @@ export function generateSourceInterface() {
|
||||
stop() {},
|
||||
getScope() {},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
+18
-17
@@ -43,18 +43,12 @@ function fromConfig(pixelCapturer, config) {
|
||||
scanner.start();
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
pendingStart = new Promise((resolve, reject) => {
|
||||
scanner.init(currentConfig, (error) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
reject(error);
|
||||
}
|
||||
pendingStart = scanner.init(currentConfig)
|
||||
.then(() => {
|
||||
initialized = true;
|
||||
scanner.start();
|
||||
resolve();
|
||||
pendingStart = null;
|
||||
});
|
||||
});
|
||||
return pendingStart;
|
||||
},
|
||||
stop() {
|
||||
@@ -88,14 +82,14 @@ function fromConfig(pixelCapturer, config) {
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
scanner.decodeSingle(currentConfig, (result) => {
|
||||
if (result && result.codeResult && result.codeResult.code) {
|
||||
return resolve(result);
|
||||
let pendingDecodeSingle = Promise.resolve();
|
||||
if (!initialized) {
|
||||
pendingDecodeSingle = pendingDecodeSingle
|
||||
.then(scanner.init.bind(scanner, currentConfig))
|
||||
.then(() => {initialized = true;});
|
||||
}
|
||||
return reject(result);
|
||||
});
|
||||
});
|
||||
return pendingDecodeSingle
|
||||
.then(scanner.decodeSingle.bind(scanner));
|
||||
}
|
||||
},
|
||||
registerResultCollector(resultCollector) {
|
||||
@@ -106,6 +100,7 @@ function fromConfig(pixelCapturer, config) {
|
||||
},
|
||||
applyConfig(newConfig) {
|
||||
const normalizedConfig = merge({}, Config, currentConfig, newConfig);
|
||||
const wasRunning = scanner.isRunning();
|
||||
let promise = Promise.resolve();
|
||||
if (hasConfigChanged(currentConfig, normalizedConfig, "constraints")) {
|
||||
console.log("constraints changed!", currentConfig.constraints, normalizedConfig.constraints);
|
||||
@@ -117,6 +112,9 @@ function fromConfig(pixelCapturer, config) {
|
||||
if (hasConfigChanged(currentConfig, normalizedConfig)) {
|
||||
console.log("config changed!");
|
||||
promise = promise.then(() => scanner.applyConfig(normalizedConfig));
|
||||
if (wasRunning) {
|
||||
promise = promise.then(scanner.start.bind(scanner));
|
||||
}
|
||||
}
|
||||
currentConfig = normalizedConfig;
|
||||
return promise;
|
||||
@@ -134,10 +132,13 @@ function fromSource(config, source) {
|
||||
|
||||
function createApi() {
|
||||
return {
|
||||
fromImage(image, options) {
|
||||
fromImage(options) {
|
||||
const config = merge({}, Config, options);
|
||||
return Source
|
||||
.fromImage(image, config.constraints)
|
||||
.fromImage(config.constraints, {
|
||||
target: config.target,
|
||||
scope: Source.Scope.INTERNAL,
|
||||
})
|
||||
.then(fromSource.bind(null, config));
|
||||
},
|
||||
fromCamera(options) {
|
||||
|
||||
+13
-11
@@ -346,7 +346,7 @@ function createScanner(pixelCapturer) {
|
||||
x: e.data.size.x,
|
||||
y: e.data.size.y
|
||||
}, new Uint8Array(e.data.imageData));
|
||||
scanner.init(config, ready, imageWrapper);
|
||||
scanner.init(config, imageWrapper).then(ready);
|
||||
scanner.subscribe("processed", onProcessed);
|
||||
} else if (e.data.cmd === 'process') {
|
||||
imageWrapper.data = new Uint8Array(e.data.imageData);
|
||||
@@ -417,15 +417,17 @@ function createScanner(pixelCapturer) {
|
||||
}
|
||||
|
||||
return {
|
||||
init: function(config, cb, imageWrapper) {
|
||||
init: function(config, imageWrapper) {
|
||||
_stopped = true;
|
||||
_config = merge({}, Config, config);
|
||||
|
||||
if (imageWrapper) {
|
||||
_onUIThread = false;
|
||||
initBuffers(imageWrapper);
|
||||
return cb();
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return setup(_config).then(cb);
|
||||
adjustWorkerPool(0);
|
||||
return setup(_config);
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
@@ -443,10 +445,7 @@ function createScanner(pixelCapturer) {
|
||||
}
|
||||
},
|
||||
applyConfig(newConfig) {
|
||||
_stopped = true;
|
||||
adjustWorkerPool(0);
|
||||
_config = merge({}, Config, _config, newConfig);
|
||||
return setup(_config).then(start);
|
||||
return this.init(newConfig);
|
||||
},
|
||||
pause: function() {
|
||||
_stopped = true;
|
||||
@@ -462,11 +461,14 @@ function createScanner(pixelCapturer) {
|
||||
_resultCollector = resultCollector;
|
||||
}
|
||||
},
|
||||
decodeSingle: function(config, resultCallback) {
|
||||
this.init(config, () => {
|
||||
decodeSingle() {
|
||||
return new Promise((resolve, reject) => {
|
||||
_events.once("processed", (result) => {
|
||||
this.stop();
|
||||
resultCallback.call(null, result);
|
||||
if (result && result.codeResult && result.codeResult.code) {
|
||||
return resolve(result);
|
||||
}
|
||||
return reject(result);
|
||||
}, true);
|
||||
start();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user