Implemented applyConfig for ImageSource; Refactored ImageSource to fit into a class

feature/image-source
Christoph Oberhofer 8 years ago
parent b799a154b0
commit d279971c46

@ -53,34 +53,47 @@ $(function() {
$(".controls .reader-config-group").off("change", "input, select"); $(".controls .reader-config-group").off("change", "input, select");
$(".controls button").off("click"); $(".controls button").off("click");
}, },
detect: function() {
var scanner = this.scanner;
scanner.detect()
.then(function(result) {
console.log(result);
addToResults(scanner, result);
return result;
})
.catch(function(result) {
console.log('Not found', result);
return result;
})
.then(function(result) {
drawResult(scanner, result);
this.attachListeners();
}.bind(this));
},
decode: function(file) { decode: function(file) {
this.detachListeners(); this.detachListeners();
var size = this.state.inputStream.size; var size = this.state.inputStream.size;
console.log("decode..."); console.log("decode...");
Quagga.fromImage(file, { if (!this.scanner) {
constraints: {width: size, height: size}, Quagga.fromImage({
locator: this.state.locator, constraints: {src: file, width: size, height: size},
decoder: this.state.decoder, locator: this.state.locator,
}) decoder: this.state.decoder,
.then(function(scanner) {
scanner.detect()
.then(function(result) {
console.log(result);
addToResults(scanner, result);
return result;
}) })
.catch(function(result) { .then(function(scanner) {
console.log('Not found', result); this.scanner = scanner;
return result; this.detect();
})
.then(function(result) {
drawResult(scanner, result);
this.attachListeners();
}.bind(this)); }.bind(this));
}.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.fromSource();
// Quagga.fromPixelCapture(); // Quagga.fromPixelCapture();
}, },

@ -101,7 +101,8 @@ $(function() {
console.log(JSON.stringify(this.state)); console.log(JSON.stringify(this.state));
this.scanner.applyConfig({ this.scanner
.applyConfig({
constraints: this.state.inputStream.constraints, constraints: this.state.inputStream.constraints,
locator: this.state.locator, locator: this.state.locator,
decoder: this.state.decoder, decoder: this.state.decoder,

@ -3,7 +3,7 @@ import {determineOrientation} from '../common/device';
import CameraAccess from './camera_access'; import CameraAccess from './camera_access';
import {getViewport} from '../common/utils'; import {getViewport} from '../common/utils';
import {generateSourceInterface} from './SourceInterface'; import {generateSourceInterface} from './SourceInterface';
import {Scope} from './input/SourceScope'; import {Scope} from './SourceScope';
const ConstraintPresets = [ const ConstraintPresets = [
{ {

@ -1,82 +1,102 @@
import {findTagsInObjectURL} from './exif_helper'; import {findTagsInObjectURL} from './exif_helper';
import {generateSourceInterface} from './SourceInterface'; import {Source} from './SourceInterface';
export function fromImage(input, constraints = {width: 800, height: 800, channels: 3}) { class ImageSource extends Source {
var $image = null; constructor() {
var src = null; super("IMAGE");
if (typeof input === 'string') { this._$image = null;
// data or url, or queryString this._src = null;
$image = new Image(); this.tags = null;
src = input; this.colorChannels = 3;
} 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");
} }
return new Promise(function(resolve, reject) {
if (src || !$image.complete) { applyConstraints(newConstraints) {
console.log('Adding eventlistener'); this.constraints = newConstraints;
$image.addEventListener('load', function() { this.colorChannels = this.constraints.channels || this.colorChannels;
resolve(); return this._applyInput(this.constraints.src)
}, false); ._loadResource()
$image.addEventListener('error', function(e) { .then(() => findTagsInObjectURL(this._src, ['orientation']))
reject(e); .then((tags) => {this.tags = tags;})
}, false); .then(this._determineDimensions.bind(this))
if (src) { .then(() => this);
console.log(`Setting src = ${src}`); }
$image.src = src;
_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();
} }
});
}
_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 { } else {
return resolve(); throw new Error("fromImage needs a src, HTMLImageElement or File");
} }
}) return this;
.then(() => findTagsInObjectURL(src, ['orientation'])) }
.then((tags) => {
let width = $image.naturalWidth; _determineDimensions() {
let height = $image.naturalHeight; let width = this._$image.naturalWidth;
if (tags && tags.orientation) { let height = this._$image.naturalHeight;
switch (tags.orientation) { let desiredWidth = this.constraints.width;
if (this.tags && this.tags.orientation) {
switch (this.tags.orientation) {
case 6: case 6:
case 8: case 8:
width = $image.naturalHeight; width = this._$image.naturalHeight;
height = $image.naturalWidth; height = this._$image.naturalWidth;
} }
} }
const imageAR = width / height; const imageAR = width / height;
const calculatedWidth = imageAR > 1 ? constraints.width : Math.floor((imageAR) * constraints.width); const calculatedWidth = imageAR > 1 ? desiredWidth : Math.floor((imageAR) * desiredWidth);
const calculatedHeight = imageAR > 1 ? Math.floor((1 / imageAR) * constraints.width) : constraints.width; const calculatedHeight = imageAR > 1 ? Math.floor((1 / imageAR) * desiredWidth) : desiredWidth;
const colorChannels = constraints.channels || 3;
return Object.assign(generateSourceInterface(), { this._dimensions = {
type: "IMAGE", viewport: {
colorChannels, width, // AR
tags, height, // AR
getDimensions() { x: 0, // AR
return { y: 0, // AR
viewport: {
width: $image.naturalWidth, // AR
height: $image.naturalHeight, // AR
x: 0, // AR
y: 0, // AR
},
canvas: {
width: calculatedWidth, // AR
height: calculatedHeight, // AR
},
};
},
getDrawable: function() {
return $image;
},
getLabel: function() {
return $image.src;
}, },
getConstraints: function() { canvas: {
return constraints; width: calculatedWidth, // AR
height: calculatedHeight, // AR
}, },
}); };
}); }
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 { return {
grabFrameData: function grabFrameData({clipping} = {}) { grabFrameData: function grabFrameData({clipping} = {}) {
const frame = source.getDrawable();
const {viewport, canvas: canvasSize} = source.getDimensions(); const {viewport, canvas: canvasSize} = source.getDimensions();
const sx = viewport.x; const sx = viewport.x;
const sy = viewport.y; const sy = viewport.y;
@ -121,12 +122,12 @@ export function fromSource(source, {target = "#interactive.viewport"} = {}) {
return sleep(100).then(grabFrameData); return sleep(100).then(grabFrameData);
} }
if (!(drawable instanceof HTMLCanvasElement)) { if (!(frame instanceof HTMLCanvasElement)) {
drawImage( drawImage(
canvasSize, canvasSize,
ctx, ctx,
source, source,
drawable, frame,
sx, sx,
sy, sy,
sWidth, sWidth,

@ -1,24 +1,22 @@
const viewport = { class Source {
x: 0, constructor(type) {
y: 0, this.type = type;
width: 0, }
height: 0, getDimensions() {}
}; getConstraints() {}
getDrawable() {}
applyConstraints() {}
getLabel() {}
stop() {}
getScope() {}
}
const canvas = { export {Source};
height: 0,
width: 0,
};
export function generateSourceInterface() { export function generateSourceInterface() {
return { return {
type: "INTERFACE", type: "INTERFACE",
getDimensions() { getDimensions() {},
return {
viewport,
canvas,
};
},
getConstraints() {}, getConstraints() {},
getDrawable() {}, getDrawable() {},
applyConstraints() {}, applyConstraints() {},
@ -26,4 +24,4 @@ export function generateSourceInterface() {
stop() {}, stop() {},
getScope() {}, getScope() {},
}; };
} };

@ -43,17 +43,11 @@ function fromConfig(pixelCapturer, config) {
scanner.start(); scanner.start();
return Promise.resolve(true); return Promise.resolve(true);
} }
pendingStart = new Promise((resolve, reject) => { pendingStart = scanner.init(currentConfig)
scanner.init(currentConfig, (error) => { .then(() => {
if (error) { initialized = true;
console.log(error); scanner.start();
reject(error); pendingStart = null;
}
initialized = true;
scanner.start();
resolve();
pendingStart = null;
});
}); });
return pendingStart; return pendingStart;
}, },
@ -88,14 +82,14 @@ function fromConfig(pixelCapturer, config) {
}) })
}; };
} else { } else {
return new Promise((resolve, reject) => { let pendingDecodeSingle = Promise.resolve();
scanner.decodeSingle(currentConfig, (result) => { if (!initialized) {
if (result && result.codeResult && result.codeResult.code) { pendingDecodeSingle = pendingDecodeSingle
return resolve(result); .then(scanner.init.bind(scanner, currentConfig))
} .then(() => {initialized = true;});
return reject(result); }
}); return pendingDecodeSingle
}); .then(scanner.decodeSingle.bind(scanner));
} }
}, },
registerResultCollector(resultCollector) { registerResultCollector(resultCollector) {
@ -106,6 +100,7 @@ function fromConfig(pixelCapturer, config) {
}, },
applyConfig(newConfig) { applyConfig(newConfig) {
const normalizedConfig = merge({}, Config, currentConfig, newConfig); const normalizedConfig = merge({}, Config, currentConfig, newConfig);
const wasRunning = scanner.isRunning();
let promise = Promise.resolve(); let promise = Promise.resolve();
if (hasConfigChanged(currentConfig, normalizedConfig, "constraints")) { if (hasConfigChanged(currentConfig, normalizedConfig, "constraints")) {
console.log("constraints changed!", currentConfig.constraints, normalizedConfig.constraints); console.log("constraints changed!", currentConfig.constraints, normalizedConfig.constraints);
@ -117,6 +112,9 @@ function fromConfig(pixelCapturer, config) {
if (hasConfigChanged(currentConfig, normalizedConfig)) { if (hasConfigChanged(currentConfig, normalizedConfig)) {
console.log("config changed!"); console.log("config changed!");
promise = promise.then(() => scanner.applyConfig(normalizedConfig)); promise = promise.then(() => scanner.applyConfig(normalizedConfig));
if (wasRunning) {
promise = promise.then(scanner.start.bind(scanner));
}
} }
currentConfig = normalizedConfig; currentConfig = normalizedConfig;
return promise; return promise;
@ -134,10 +132,13 @@ function fromSource(config, source) {
function createApi() { function createApi() {
return { return {
fromImage(image, options) { fromImage(options) {
const config = merge({}, Config, options); const config = merge({}, Config, options);
return Source return Source
.fromImage(image, config.constraints) .fromImage(config.constraints, {
target: config.target,
scope: Source.Scope.INTERNAL,
})
.then(fromSource.bind(null, config)); .then(fromSource.bind(null, config));
}, },
fromCamera(options) { fromCamera(options) {

@ -346,7 +346,7 @@ function createScanner(pixelCapturer) {
x: e.data.size.x, x: e.data.size.x,
y: e.data.size.y y: e.data.size.y
}, new Uint8Array(e.data.imageData)); }, new Uint8Array(e.data.imageData));
scanner.init(config, ready, imageWrapper); scanner.init(config, imageWrapper).then(ready);
scanner.subscribe("processed", onProcessed); scanner.subscribe("processed", onProcessed);
} else if (e.data.cmd === 'process') { } else if (e.data.cmd === 'process') {
imageWrapper.data = new Uint8Array(e.data.imageData); imageWrapper.data = new Uint8Array(e.data.imageData);
@ -417,15 +417,17 @@ function createScanner(pixelCapturer) {
} }
return { return {
init: function(config, cb, imageWrapper) { init: function(config, imageWrapper) {
_stopped = true;
_config = merge({}, Config, config); _config = merge({}, Config, config);
if (imageWrapper) { if (imageWrapper) {
_onUIThread = false; _onUIThread = false;
initBuffers(imageWrapper); initBuffers(imageWrapper);
return cb(); return Promise.resolve();
} else { } else {
return setup(_config).then(cb); adjustWorkerPool(0);
return setup(_config);
} }
}, },
start: function() { start: function() {
@ -443,10 +445,7 @@ function createScanner(pixelCapturer) {
} }
}, },
applyConfig(newConfig) { applyConfig(newConfig) {
_stopped = true; return this.init(newConfig);
adjustWorkerPool(0);
_config = merge({}, Config, _config, newConfig);
return setup(_config).then(start);
}, },
pause: function() { pause: function() {
_stopped = true; _stopped = true;
@ -462,11 +461,14 @@ function createScanner(pixelCapturer) {
_resultCollector = resultCollector; _resultCollector = resultCollector;
} }
}, },
decodeSingle: function(config, resultCallback) { decodeSingle() {
this.init(config, () => { return new Promise((resolve, reject) => {
_events.once("processed", (result) => { _events.once("processed", (result) => {
this.stop(); this.stop();
resultCallback.call(null, result); if (result && result.codeResult && result.codeResult.code) {
return resolve(result);
}
return reject(result);
}, true); }, true);
start(); start();
}); });

Loading…
Cancel
Save