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

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

@ -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));
},
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 = [
{

@ -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;
class ImageSource extends Source {
constructor() {
super("IMAGE");
this._$image = null;
this._src = null;
this.tags = null;
this.colorChannels = 3;
}
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();
}
});
}
_applyInput(input) {
if (typeof input === 'string') {
// data or url, or queryString
$image = new Image();
src = input;
this._$image = new Image();
this._src = input;
} else if (input instanceof HTMLImageElement) {
$image = input;
this._$image = input;
} else if (input instanceof File) {
$image = new Image();
src = URL.createObjectURL(input);
this._$image = new Image();
this._src = URL.createObjectURL(input);
} else {
return Promise.reject("fromImage needs a src, HTMLImageElement or File");
throw new Error("fromImage needs a src, HTMLImageElement or File");
}
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;
}
} else {
return resolve();
return this;
}
})
.then(() => findTagsInObjectURL(src, ['orientation']))
.then((tags) => {
let width = $image.naturalWidth;
let height = $image.naturalHeight;
if (tags && tags.orientation) {
switch (tags.orientation) {
_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;
const calculatedWidth = imageAR > 1 ? desiredWidth : Math.floor((imageAR) * desiredWidth);
const calculatedHeight = imageAR > 1 ? Math.floor((1 / imageAR) * desiredWidth) : desiredWidth;
return Object.assign(generateSourceInterface(), {
type: "IMAGE",
colorChannels,
tags,
getDimensions() {
return {
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() {},
};
}
};

@ -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) {

@ -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();
});

Loading…
Cancel
Save