From afcaa580b14a0d04433e9ee9c91a6fb9478b7ead Mon Sep 17 00:00:00 2001 From: Christoph Oberhofer Date: Sun, 26 Mar 2017 23:22:10 +0200 Subject: [PATCH] Added orientation-dependent constraints; extended constrain-matching; --- example/live_w_locator.js | 17 ++++- src/common/device.js | 1 + src/input/Source.js | 152 ++++++++++++++++++++++++++++++++++---- src/quagga.js | 6 ++ 4 files changed, 156 insertions(+), 20 deletions(-) diff --git a/example/live_w_locator.js b/example/live_w_locator.js index 4e63d13..413e017 100644 --- a/example/live_w_locator.js +++ b/example/live_w_locator.js @@ -146,11 +146,20 @@ $(function() { inputStream: { type : "LiveStream", constraints: { - width: {ideal: 480}, - height: {ideal: 480}, - zoom: {exact: 2}, + width: {ideal: 800}, + height: {ideal: 800}, facingMode: "environment", - aspectRatio: 1, + landscape: { + width: {ideal: 640}, + height: {ideal: 480}, + zoom: 1.5, + }, + portrait: { + width: {ideal: 640}, + height: {ideal: 640}, + zoom: 1.5, + aspectRatio: 1, + } } }, locator: { diff --git a/src/common/device.js b/src/common/device.js index 2b4435f..0c3fa86 100644 --- a/src/common/device.js +++ b/src/common/device.js @@ -1,5 +1,6 @@ export const PORTRAIT = "portrait"; export const LANDSCAPE = "landscape"; +export const SQUARE = "square"; const matchingScreens = { [PORTRAIT]: /portrait/i, diff --git a/src/input/Source.js b/src/input/Source.js index 474c843..f0c022c 100644 --- a/src/input/Source.js +++ b/src/input/Source.js @@ -1,8 +1,81 @@ import {clone} from 'lodash'; -import {determineOrientation, PORTRAIT} from '../common/device'; +import {determineOrientation, PORTRAIT, LANDSCAPE, SQUARE} from '../common/device'; import CameraAccess from './camera_access'; import {getViewport} from '../common/utils'; +const ConstraintPresets = [ + { + width: 720, + height: 1280, + }, { + width: 540, + height: 960, + }, { + width: 600, + height: 800, + }, { + width: 480, + height: 640, + }, { + width: 1280, + height: 720, + }, { + width: 960, + height: 540, + }, { + width: 800, + height: 600, + }, { + width: 640, + height: 480, + }, { + width: 1280, + height: 1280, + }, { + width: 1080, + height: 1080, + }, { + width: 960, + height: 960, + }, { + width: 800, + height: 800, + }, { + width: 640, + height: 640, + }, +].map((preset) => Object.assign({}, preset, {aspectRatio: preset.width / preset.height})); + +function getFilter(aspectRatio) { + if (aspectRatio === 1) { + return pre => pre.aspectRatio === aspectRatio; + } else if (aspectRatio > 1) { + return pre => pre.aspectRatio > 1; + } + return pre => pre.aspectRatio < 1; +} + +function resolveMinWidthToAdvanced({aspectRatio, minPixels}) { + return [...ConstraintPresets] + .filter(getFilter(aspectRatio)) + .map((pre) => { + return { + error: Math.abs((pre.width * pre.height) - minPixels), + pre, + }; + }) + .sort(({error: errorA}, {error: errorB}) => { + if (errorB > errorA) { + return -1; + } + if (errorB < errorA) { + return 1; + } + return 0; + }) + .map(({pre}) => pre); +} + function getOrCreateVideo(source, target) { const $viewport = getViewport(target); if ($viewport) { @@ -16,21 +89,70 @@ function getOrCreateVideo(source, target) { return document.createElement("video"); } -export function fromCamera(constraints) { - var orientation = determineOrientation(); - var videoConstraints = clone(constraints); - if (orientation === PORTRAIT) { - videoConstraints = Object.assign({}, videoConstraints, { - width: videoConstraints.height, - height: videoConstraints.width, - }); +function constraintToNumber(constraint) { + if (!constraint) { + return null; + } + if (typeof constraint === 'number') { + return constraint; + } + const {ideal, exact, min, max} = constraint; + if (typeof exact !== 'undefined') { + return exact; + } + if (typeof ideal !== 'undefined') { + return ideal; + } + if (typeof min !== 'undefined') { + return min; + } + if (typeof max !== 'undefined') { + return max; + } + + return null; +} + +function adjustWithZoom(videoConstraints) { + const constraints = clone(videoConstraints); + const orientation = determineOrientation(); + + let zoom = constraintToNumber(constraints.zoom) || 1, + width = constraintToNumber(constraints.width), + height = constraintToNumber(constraints.height), + aspectRatio = constraintToNumber(constraints.aspectRatio) || (width / height); + + if (constraints[orientation]) { + zoom = constraintToNumber(constraints[orientation].zoom) || zoom; + width = constraintToNumber(constraints[orientation].width) || width; + height = constraintToNumber(constraints[orientation].height) || height; + aspectRatio = constraintToNumber(constraints[orientation].aspectRatio) || (width / height); } - if (videoConstraints.zoom && videoConstraints.zoom.exact > 1) { - videoConstraints.width.ideal = Math.floor(videoConstraints.width.ideal * videoConstraints.zoom.exact); - videoConstraints.height.ideal = Math.floor(videoConstraints.height.ideal * videoConstraints.zoom.exact); - delete videoConstraints.zoom; + if (zoom > 1) { + width = Math.floor(width * zoom); + height = Math.floor(height * zoom); } + + delete constraints.zoom; + delete constraints.orientation; + delete constraints.landscape; + delete constraints.portrait; + + const advanced = resolveMinWidthToAdvanced({minPixels: (width * height), aspectRatio}); + return { + zoom, + video: Object.assign({}, constraints, { + width: {ideal: advanced[0].width}, + height: {ideal: advanced[0].height}, + aspectRatio: {exact: advanced[0].aspectRatio || aspectRatio}, + advanced, + }), + }; +} + +export function fromCamera(constraints) { + var {video: videoConstraints, zoom} = adjustWithZoom(constraints); console.log(videoConstraints); const video = getOrCreateVideo(); @@ -46,9 +168,7 @@ export function fromCamera(constraints) { width: video.videoWidth, height: video.videoHeight, }; - - if (constraints.zoom && constraints.zoom.exact > 1) { - const zoom = constraints.zoom.exact; + if (zoom > 1) { viewport.width = Math.floor(video.videoWidth / zoom); viewport.height = Math.floor(video.videoHeight / zoom); viewport.x = Math.floor((video.videoWidth - viewport.width) / 2); diff --git a/src/quagga.js b/src/quagga.js index 6892610..2dcf05c 100644 --- a/src/quagga.js +++ b/src/quagga.js @@ -8,6 +8,7 @@ import {merge} from 'lodash'; import CameraAccess from './input/camera_access'; import * as PixelCapture from './input/PixelCapture'; import * as Source from './input/Source'; +import {PORTRAIT, LANDSCAPE, SQUARE} from './common/device'; function fromConfig(pixelCapturer, config) { const scanner = createScanner(pixelCapturer); @@ -162,6 +163,11 @@ function createApi() { ResultCollector, _worker: { createScanner + }, + Orientation: { + PORTRAIT, + LANDSCAPE, + SQUARE, } }; }