diff --git a/example/css/styles.css b/example/css/styles.css index 1239c5b..6e5a419 100644 --- a/example/css/styles.css +++ b/example/css/styles.css @@ -21,8 +21,7 @@ @import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); /* line 1, ../sass/_viewport.scss */ #interactive.viewport { - width: 640px; - height: 480px; + max-width: 100%; } .input-field { diff --git a/example/file_input.html b/example/file_input.html index 06ca78b..f75d1da 100644 --- a/example/file_input.html +++ b/example/file_input.html @@ -8,7 +8,7 @@ - + diff --git a/src/decoder/barcode_decoder.js b/src/decoder/barcode_decoder.js index cbd9eab..6bff4e7 100644 --- a/src/decoder/barcode_decoder.js +++ b/src/decoder/barcode_decoder.js @@ -26,7 +26,7 @@ const READERS = { i2of5_reader: I2of5Reader }; export default { - create: function(config, inputImageWrapper) { + create: function(config) { var _canvas = { ctx: { frequency: null, @@ -136,7 +136,7 @@ export default { * @param {Array} line * @param {Number} angle */ - function getExtendedLine(line, angle, ext) { + function getExtendedLine(inputImageWrapper, line, angle, ext) { function extendLine(amount) { var extension = { y: amount * Math.sin(angle), @@ -169,7 +169,7 @@ export default { }]; } - function tryDecode(line) { + function tryDecode(inputImageWrapper, line) { var result = null, i, barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]); @@ -204,7 +204,7 @@ export default { * @param {Array} line * @param {Number} lineAngle */ - function tryDecodeBruteForce(box, line, lineAngle) { + function tryDecodeBruteForce(inputImageWrapper, box, line, lineAngle) { var sideLength = Math.sqrt(Math.pow(box[1][0] - box[0][0], 2) + Math.pow((box[1][1] - box[0][1]), 2)), i, slices = 16, @@ -226,7 +226,7 @@ export default { line[1].y += extension.x; line[1].x -= extension.y; - result = tryDecode(line); + result = tryDecode(inputImageWrapper, line); } return result; } @@ -243,7 +243,7 @@ export default { * @param {Object} box The area to search in * @returns {Object} the result {codeResult, line, angle, pattern, threshold} */ - function decodeFromBoundingBox(box) { + function decodeFromBoundingBox(inputImageWrapper, box) { var line, lineAngle, ctx = _canvas.ctx.overlay, @@ -259,14 +259,14 @@ export default { 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, Math.floor(lineLength * 0.1)); + line = getExtendedLine(inputImageWrapper, line, lineAngle, Math.floor(lineLength * 0.1)); if (line === null){ return null; } - result = tryDecode(line); + result = tryDecode(inputImageWrapper, line); if (result === null) { - result = tryDecodeBruteForce(box, line, lineAngle); + result = tryDecodeBruteForce(inputImageWrapper, box, line, lineAngle); } if (result === null) { @@ -287,17 +287,14 @@ export default { } return { - decodeFromBoundingBox: function(box) { - return decodeFromBoundingBox(box); - }, - decodeFromBoundingBoxes: function(boxes) { + decodeFromBoundingBoxes: function(inputImageWrapper, boxes) { var i, result, barcodes = [], multiple = config.multiple; for ( i = 0; i < boxes.length; i++) { const box = boxes[i]; - result = decodeFromBoundingBox(box) || {}; + result = decodeFromBoundingBox(inputImageWrapper, box) || {}; result.box = box; if (multiple) { diff --git a/src/input/ImageSource.js b/src/input/ImageSource.js new file mode 100644 index 0000000..76b0346 --- /dev/null +++ b/src/input/ImageSource.js @@ -0,0 +1,84 @@ +import {findTagsInObjectURL} from './exif_helper'; + +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"); + } + 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(); + } + }) + .then(() => findTagsInObjectURL(src, ['orientation'])) + .then((tags) => { + let width = $image.naturalWidth; + let height = $image.naturalHeight; + if (tags && tags.orientation) { + switch (tags.orientation) { + case 6: + case 8: + width = $image.naturalHeight; + height = $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 { + type: "IMAGE", + colorChannels, + tags, + getDimensions() { + return { + 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() { + return constraints; + }, + applyConstraints: function() { + console.log('ImageSource.applyConstraints not implemented'); + }, + }; + }); +} diff --git a/src/input/PixelCapture.js b/src/input/PixelCapture.js index d201bb7..570f298 100644 --- a/src/input/PixelCapture.js +++ b/src/input/PixelCapture.js @@ -6,6 +6,8 @@ import { import {sleep, getViewport} from '../common/utils'; import {aquire} from '../common/buffers'; +const TO_RADIANS = Math.PI / 180; + function adjustCanvasSize(input, canvas) { if (input instanceof HTMLVideoElement) { if (canvas.height !== input.videoHeight || canvas.width !== input.videoWidth) { @@ -45,9 +47,8 @@ function drawImage( canvasSize, ctx, source, - type, drawable, - ...drawImageArgs, + ...drawImageArgs ) { let drawAngle = 0; if (source.type === 'IMAGE') { @@ -63,10 +64,11 @@ function drawImage( } } + const [,,,,,, dWidth, dHeight] = drawImageArgs; if (drawAngle !== 0) { ctx.translate(canvasSize.width / 2, canvasSize.height / 2); ctx.rotate(drawAngle); - ctx.drawImage(drawable, -canvasSize.height / 2, -canvasSize.width / 2, canvasSize.height, canvasSize.width); + ctx.drawImage(drawable, -dHeight / 2, -dWidth / 2, dHeight, dWidth); ctx.rotate(-drawAngle); ctx.translate(-canvasSize.width / 2, -canvasSize.height / 2); } else { diff --git a/src/input/Source.js b/src/input/Source.js index aaef1e0..ba47887 100644 --- a/src/input/Source.js +++ b/src/input/Source.js @@ -3,6 +3,8 @@ import {determineOrientation, PORTRAIT, LANDSCAPE, SQUARE} from '../common/devic import CameraAccess from './camera_access'; import {getViewport} from '../common/utils'; +export * from './ImageSource'; + const ConstraintPresets = [ { width: 720, @@ -244,77 +246,3 @@ export function fromCanvas(input) { } }); } - -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"); - } - 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(); - } - }) - .then(() => { - const width = $image.naturalWidth; - const height = $image.naturalHeight; - 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 { - type: "IMAGE", - colorChannels, - getDimensions() { - return { - 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() { - return constraints; - }, - applyConstraints: function() { - console.log('ImageSource.applyConstraints not implemented'); - }, - }; - }); -} diff --git a/src/scanner.js b/src/scanner.js index adc1571..2d5174a 100644 --- a/src/scanner.js +++ b/src/scanner.js @@ -14,10 +14,10 @@ const vec2 = { clone: require('gl-vec2/clone') }; -const getDecoder = memoize((decoderConfig, _inputImageWrapper) => { - return BarcodeDecoder.create(decoderConfig, _inputImageWrapper); -}, (decoderConfig, _inputImageWrapper) => { - return JSON.stringify(Object.assign({}, decoderConfig, {width: _inputImageWrapper.size.x, height: _inputImageWrapper.size.y})); +const getDecoder = memoize(decoderConfig => { + return BarcodeDecoder.create(decoderConfig); +}, decoderConfig => { + return JSON.stringify(decoderConfig); }); const _checkImageConstraints = memoize((opts) => { @@ -177,8 +177,8 @@ function createScanner(pixelCapturer) { boxes = getBoundingBoxes(); if (boxes) { - result = getDecoder(_config.decoder, _inputImageWrapper) - .decodeFromBoundingBoxes(boxes); + result = getDecoder(_config.decoder) + .decodeFromBoundingBoxes(_inputImageWrapper, boxes); result = result || {}; result.boxes = boxes; publishResult(result, _inputImageWrapper.data);