mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-12 21:21:42 +08:00
Orientation works on iPhone and Android
This commit is contained in:
@@ -21,8 +21,7 @@
|
|||||||
@import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600");
|
@import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600");
|
||||||
/* line 1, ../sass/_viewport.scss */
|
/* line 1, ../sass/_viewport.scss */
|
||||||
#interactive.viewport {
|
#interactive.viewport {
|
||||||
width: 640px;
|
max-width: 100%;
|
||||||
height: 480px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<meta name="description" content=""/>
|
<meta name="description" content=""/>
|
||||||
<meta name="author" content="Christoph Oberhofer"/>
|
<meta name="author" content="Christoph Oberhofer"/>
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width; initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"/>
|
||||||
<link rel="stylesheet" type="text/css" href="css/styles.css"/>
|
<link rel="stylesheet" type="text/css" href="css/styles.css"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const READERS = {
|
|||||||
i2of5_reader: I2of5Reader
|
i2of5_reader: I2of5Reader
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
create: function(config, inputImageWrapper) {
|
create: function(config) {
|
||||||
var _canvas = {
|
var _canvas = {
|
||||||
ctx: {
|
ctx: {
|
||||||
frequency: null,
|
frequency: null,
|
||||||
@@ -136,7 +136,7 @@ export default {
|
|||||||
* @param {Array} line
|
* @param {Array} line
|
||||||
* @param {Number} angle
|
* @param {Number} angle
|
||||||
*/
|
*/
|
||||||
function getExtendedLine(line, angle, ext) {
|
function getExtendedLine(inputImageWrapper, line, angle, ext) {
|
||||||
function extendLine(amount) {
|
function extendLine(amount) {
|
||||||
var extension = {
|
var extension = {
|
||||||
y: amount * Math.sin(angle),
|
y: amount * Math.sin(angle),
|
||||||
@@ -169,7 +169,7 @@ export default {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryDecode(line) {
|
function tryDecode(inputImageWrapper, line) {
|
||||||
var result = null,
|
var result = null,
|
||||||
i,
|
i,
|
||||||
barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]);
|
barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]);
|
||||||
@@ -204,7 +204,7 @@ export default {
|
|||||||
* @param {Array} line
|
* @param {Array} line
|
||||||
* @param {Number} lineAngle
|
* @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)),
|
var sideLength = Math.sqrt(Math.pow(box[1][0] - box[0][0], 2) + Math.pow((box[1][1] - box[0][1]), 2)),
|
||||||
i,
|
i,
|
||||||
slices = 16,
|
slices = 16,
|
||||||
@@ -226,7 +226,7 @@ export default {
|
|||||||
line[1].y += extension.x;
|
line[1].y += extension.x;
|
||||||
line[1].x -= extension.y;
|
line[1].x -= extension.y;
|
||||||
|
|
||||||
result = tryDecode(line);
|
result = tryDecode(inputImageWrapper, line);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ export default {
|
|||||||
* @param {Object} box The area to search in
|
* @param {Object} box The area to search in
|
||||||
* @returns {Object} the result {codeResult, line, angle, pattern, threshold}
|
* @returns {Object} the result {codeResult, line, angle, pattern, threshold}
|
||||||
*/
|
*/
|
||||||
function decodeFromBoundingBox(box) {
|
function decodeFromBoundingBox(inputImageWrapper, box) {
|
||||||
var line,
|
var line,
|
||||||
lineAngle,
|
lineAngle,
|
||||||
ctx = _canvas.ctx.overlay,
|
ctx = _canvas.ctx.overlay,
|
||||||
@@ -259,14 +259,14 @@ export default {
|
|||||||
line = getLine(box);
|
line = getLine(box);
|
||||||
lineLength = getLineLength(line);
|
lineLength = getLineLength(line);
|
||||||
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
|
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){
|
if (line === null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = tryDecode(line);
|
result = tryDecode(inputImageWrapper, line);
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
result = tryDecodeBruteForce(box, line, lineAngle);
|
result = tryDecodeBruteForce(inputImageWrapper, box, line, lineAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
@@ -287,17 +287,14 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
decodeFromBoundingBox: function(box) {
|
decodeFromBoundingBoxes: function(inputImageWrapper, boxes) {
|
||||||
return decodeFromBoundingBox(box);
|
|
||||||
},
|
|
||||||
decodeFromBoundingBoxes: function(boxes) {
|
|
||||||
var i, result,
|
var i, result,
|
||||||
barcodes = [],
|
barcodes = [],
|
||||||
multiple = config.multiple;
|
multiple = config.multiple;
|
||||||
|
|
||||||
for ( i = 0; i < boxes.length; i++) {
|
for ( i = 0; i < boxes.length; i++) {
|
||||||
const box = boxes[i];
|
const box = boxes[i];
|
||||||
result = decodeFromBoundingBox(box) || {};
|
result = decodeFromBoundingBox(inputImageWrapper, box) || {};
|
||||||
result.box = box;
|
result.box = box;
|
||||||
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
|
|||||||
@@ -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');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
import {sleep, getViewport} from '../common/utils';
|
import {sleep, getViewport} from '../common/utils';
|
||||||
import {aquire} from '../common/buffers';
|
import {aquire} from '../common/buffers';
|
||||||
|
|
||||||
|
const TO_RADIANS = Math.PI / 180;
|
||||||
|
|
||||||
function adjustCanvasSize(input, canvas) {
|
function adjustCanvasSize(input, canvas) {
|
||||||
if (input instanceof HTMLVideoElement) {
|
if (input instanceof HTMLVideoElement) {
|
||||||
if (canvas.height !== input.videoHeight || canvas.width !== input.videoWidth) {
|
if (canvas.height !== input.videoHeight || canvas.width !== input.videoWidth) {
|
||||||
@@ -45,9 +47,8 @@ function drawImage(
|
|||||||
canvasSize,
|
canvasSize,
|
||||||
ctx,
|
ctx,
|
||||||
source,
|
source,
|
||||||
type,
|
|
||||||
drawable,
|
drawable,
|
||||||
...drawImageArgs,
|
...drawImageArgs
|
||||||
) {
|
) {
|
||||||
let drawAngle = 0;
|
let drawAngle = 0;
|
||||||
if (source.type === 'IMAGE') {
|
if (source.type === 'IMAGE') {
|
||||||
@@ -63,10 +64,11 @@ function drawImage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [,,,,,, dWidth, dHeight] = drawImageArgs;
|
||||||
if (drawAngle !== 0) {
|
if (drawAngle !== 0) {
|
||||||
ctx.translate(canvasSize.width / 2, canvasSize.height / 2);
|
ctx.translate(canvasSize.width / 2, canvasSize.height / 2);
|
||||||
ctx.rotate(drawAngle);
|
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.rotate(-drawAngle);
|
||||||
ctx.translate(-canvasSize.width / 2, -canvasSize.height / 2);
|
ctx.translate(-canvasSize.width / 2, -canvasSize.height / 2);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-74
@@ -3,6 +3,8 @@ import {determineOrientation, PORTRAIT, LANDSCAPE, SQUARE} from '../common/devic
|
|||||||
import CameraAccess from './camera_access';
|
import CameraAccess from './camera_access';
|
||||||
import {getViewport} from '../common/utils';
|
import {getViewport} from '../common/utils';
|
||||||
|
|
||||||
|
export * from './ImageSource';
|
||||||
|
|
||||||
const ConstraintPresets = [
|
const ConstraintPresets = [
|
||||||
{
|
{
|
||||||
width: 720,
|
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');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
+6
-6
@@ -14,10 +14,10 @@ const vec2 = {
|
|||||||
clone: require('gl-vec2/clone')
|
clone: require('gl-vec2/clone')
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDecoder = memoize((decoderConfig, _inputImageWrapper) => {
|
const getDecoder = memoize(decoderConfig => {
|
||||||
return BarcodeDecoder.create(decoderConfig, _inputImageWrapper);
|
return BarcodeDecoder.create(decoderConfig);
|
||||||
}, (decoderConfig, _inputImageWrapper) => {
|
}, decoderConfig => {
|
||||||
return JSON.stringify(Object.assign({}, decoderConfig, {width: _inputImageWrapper.size.x, height: _inputImageWrapper.size.y}));
|
return JSON.stringify(decoderConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
const _checkImageConstraints = memoize((opts) => {
|
const _checkImageConstraints = memoize((opts) => {
|
||||||
@@ -177,8 +177,8 @@ function createScanner(pixelCapturer) {
|
|||||||
|
|
||||||
boxes = getBoundingBoxes();
|
boxes = getBoundingBoxes();
|
||||||
if (boxes) {
|
if (boxes) {
|
||||||
result = getDecoder(_config.decoder, _inputImageWrapper)
|
result = getDecoder(_config.decoder)
|
||||||
.decodeFromBoundingBoxes(boxes);
|
.decodeFromBoundingBoxes(_inputImageWrapper, boxes);
|
||||||
result = result || {};
|
result = result || {};
|
||||||
result.boxes = boxes;
|
result.boxes = boxes;
|
||||||
publishResult(result, _inputImageWrapper.data);
|
publishResult(result, _inputImageWrapper.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user