@wemap/camera 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wemap-camera.es.js +176 -16
- package/dist/wemap-camera.es.js.map +1 -1
- package/package.json +3 -2
- package/src/Camera.js +66 -12
- package/src/CameraUtils.js +103 -0
- package/src/QrCodeScanner.js +3 -3
package/dist/wemap-camera.es.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BarcodeFormat, MultiFormatReader, DecodeHintType, BinaryBitmap, HybridBinarizer, RGBLuminanceSource } from '@zxing/library';
|
|
2
2
|
export { BarcodeFormat } from '@zxing/library';
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
|
+
import Logger from '@wemap/logger';
|
|
4
5
|
|
|
5
6
|
class SharedCameras extends EventEmitter {
|
|
6
7
|
|
|
@@ -105,10 +106,116 @@ function calcDisplayedFov(videoContainer, videoElement, hardwareVerticalFov) {
|
|
|
105
106
|
};
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* @param {HTMLCanvasElement} canvas
|
|
111
|
+
* @param {string} type
|
|
112
|
+
* @param {any} quality
|
|
113
|
+
* @returns {string}
|
|
114
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
|
|
115
|
+
*/
|
|
116
|
+
function canvasToBase64(canvas, type = 'image/png', quality = null) {
|
|
117
|
+
return canvas
|
|
118
|
+
.toDataURL(type, quality)
|
|
119
|
+
.substring(('data:' + type + ';base64,').length);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Creates a pinhole camera from dimensions and a field of view
|
|
124
|
+
* Distortions are not considered
|
|
125
|
+
*
|
|
126
|
+
* @param {number} width the camera width
|
|
127
|
+
* @param {number} height the camera height
|
|
128
|
+
* @param {number} fovOfWidth the field of view along the width axis in radians
|
|
129
|
+
* @returns {object} the calibration matrix
|
|
130
|
+
*/
|
|
131
|
+
function createCameraCalibrationFromWidthHeightFov(width, height, fovOfWidth) {
|
|
132
|
+
|
|
133
|
+
const fovOfHeight = 2 * Math.atan(height * Math.tan(fovOfWidth / 2) / width);
|
|
134
|
+
|
|
135
|
+
const fx = width / (2 * Math.tan(0.5 * fovOfWidth));
|
|
136
|
+
const fy = height / (2 * Math.tan(0.5 * fovOfHeight));
|
|
137
|
+
const cx = width / 2;
|
|
138
|
+
const cy = height / 2;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
intrinsic: [fx, 0, cx, 0, fy, cy, 0, 0, 1],
|
|
142
|
+
distortions: [0, 0, 0, 0, 0]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {HTMLCanvasElement} imageCanvas
|
|
148
|
+
*/
|
|
149
|
+
function convertToGrayscale(imageCanvas) {
|
|
150
|
+
const ctx = imageCanvas.getContext('2d');
|
|
151
|
+
const imgData = ctx.getImageData(0, 0, imageCanvas.width, imageCanvas.height);
|
|
152
|
+
const pixels = imgData.data;
|
|
153
|
+
for (let i = 0; i < pixels.length; i += 4) {
|
|
154
|
+
|
|
155
|
+
const lightness = parseInt((pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3, 10);
|
|
156
|
+
pixels[i] = lightness;
|
|
157
|
+
pixels[i + 1] = lightness;
|
|
158
|
+
pixels[i + 2] = lightness;
|
|
159
|
+
}
|
|
160
|
+
ctx.putImageData(imgData, 0, 0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Reduce image size and keep aspect ratio
|
|
165
|
+
* @param {HTMLCanvasElement} imageCanvas
|
|
166
|
+
*/
|
|
167
|
+
function reduceImageSize(imageCanvas, maxWidth, maxHeight = null) {
|
|
168
|
+
|
|
169
|
+
let newWidth = imageCanvas.width;
|
|
170
|
+
let newHeight = imageCanvas.height;
|
|
171
|
+
|
|
172
|
+
if (maxHeight !== null) {
|
|
173
|
+
if (newWidth > maxWidth) {
|
|
174
|
+
newHeight *= maxWidth / newWidth;
|
|
175
|
+
newWidth = maxWidth;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (newHeight > maxHeight) {
|
|
179
|
+
newWidth *= maxHeight / newHeight;
|
|
180
|
+
newHeight = maxHeight;
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
const aspectRatio = imageCanvas.width / imageCanvas.height;
|
|
184
|
+
if (imageCanvas.width > imageCanvas.height) {
|
|
185
|
+
if (imageCanvas.width > maxWidth) {
|
|
186
|
+
newWidth = maxWidth;
|
|
187
|
+
newHeight = maxWidth / aspectRatio;
|
|
188
|
+
}
|
|
189
|
+
} else if (imageCanvas.height > maxWidth) {
|
|
190
|
+
newHeight = maxWidth;
|
|
191
|
+
newWidth = maxWidth * aspectRatio;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
if (newWidth === imageCanvas.width
|
|
197
|
+
&& newHeight === imageCanvas.height) {
|
|
198
|
+
return imageCanvas;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const newCanvas = document.createElement('canvas');
|
|
202
|
+
const newContext = newCanvas.getContext('2d');
|
|
203
|
+
|
|
204
|
+
newCanvas.width = newWidth;
|
|
205
|
+
newCanvas.height = newHeight;
|
|
206
|
+
newContext.drawImage(imageCanvas, 0, 0, newCanvas.width, newCanvas.height);
|
|
207
|
+
|
|
208
|
+
return newCanvas;
|
|
209
|
+
}
|
|
210
|
+
|
|
108
211
|
var CameraUtils = /*#__PURE__*/Object.freeze({
|
|
109
212
|
__proto__: null,
|
|
110
213
|
convertFov: convertFov,
|
|
111
|
-
calcDisplayedFov: calcDisplayedFov
|
|
214
|
+
calcDisplayedFov: calcDisplayedFov,
|
|
215
|
+
canvasToBase64: canvasToBase64,
|
|
216
|
+
createCameraCalibrationFromWidthHeightFov: createCameraCalibrationFromWidthHeightFov,
|
|
217
|
+
convertToGrayscale: convertToGrayscale,
|
|
218
|
+
reduceImageSize: reduceImageSize
|
|
112
219
|
});
|
|
113
220
|
|
|
114
221
|
// Helped from https://github.com/jeromeetienne/AR.js/blob/master/three.js/src/threex/threex-artoolkitsource.js
|
|
@@ -118,6 +225,13 @@ var CameraUtils = /*#__PURE__*/Object.freeze({
|
|
|
118
225
|
// camera preview is extended then cropped.
|
|
119
226
|
class Camera extends EventEmitter {
|
|
120
227
|
|
|
228
|
+
static State = {
|
|
229
|
+
STOPPED: 'stopped',
|
|
230
|
+
STARTING: 'starting',
|
|
231
|
+
STARTED: 'started',
|
|
232
|
+
STOPPING: 'stopping'
|
|
233
|
+
}
|
|
234
|
+
|
|
121
235
|
static DEFAULT_OPTIONS = {
|
|
122
236
|
width: 1024,
|
|
123
237
|
height: 768,
|
|
@@ -131,7 +245,7 @@ class Camera extends EventEmitter {
|
|
|
131
245
|
|
|
132
246
|
fov = null;
|
|
133
247
|
|
|
134
|
-
|
|
248
|
+
_state = Camera.State.STOPPED;
|
|
135
249
|
|
|
136
250
|
_hardwareVerticalFov = Camera.GENERIC_HARDWARE_VERTICAL_FOV;
|
|
137
251
|
_resizeOnWindowChange;
|
|
@@ -155,7 +269,8 @@ class Camera extends EventEmitter {
|
|
|
155
269
|
video: {
|
|
156
270
|
facingMode: 'environment',
|
|
157
271
|
width: { ideal: options.width },
|
|
158
|
-
height: { ideal: options.height }
|
|
272
|
+
height: { ideal: options.height },
|
|
273
|
+
resizeMode: 'none'
|
|
159
274
|
}
|
|
160
275
|
};
|
|
161
276
|
|
|
@@ -169,16 +284,26 @@ class Camera extends EventEmitter {
|
|
|
169
284
|
this.videoContainer.appendChild(this.videoElement);
|
|
170
285
|
}
|
|
171
286
|
|
|
172
|
-
async start() {
|
|
287
|
+
async start(videoMediaConstraints = null) {
|
|
173
288
|
|
|
174
|
-
if (this.
|
|
289
|
+
if (this._state !== Camera.State.STOPPED) {
|
|
175
290
|
throw new Error('Camera is already started');
|
|
176
291
|
}
|
|
177
292
|
|
|
178
|
-
this.
|
|
293
|
+
if (this._state === Camera.State.STOPPING) {
|
|
294
|
+
await new Promise(resolve => this.once('stopped', resolve));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this._state = Camera.State.STARTING;
|
|
298
|
+
this.emit('starting');
|
|
179
299
|
|
|
180
300
|
await Camera.checkAvailability();
|
|
181
301
|
|
|
302
|
+
if (videoMediaConstraints) {
|
|
303
|
+
Object.assign(this._userMediaConstraints.video,
|
|
304
|
+
this._userMediaConstraints.video, videoMediaConstraints);
|
|
305
|
+
}
|
|
306
|
+
|
|
182
307
|
const stream = await navigator.mediaDevices.getUserMedia(this._userMediaConstraints);
|
|
183
308
|
|
|
184
309
|
// Listeners have to be set before srcObject assigment or they can be never called
|
|
@@ -195,7 +320,8 @@ class Camera extends EventEmitter {
|
|
|
195
320
|
window.addEventListener('resize', this.notifyContainerSizeChanged);
|
|
196
321
|
}
|
|
197
322
|
|
|
198
|
-
this.
|
|
323
|
+
this._state = Camera.State.STARTED;
|
|
324
|
+
this.emit('started', {
|
|
199
325
|
videoElement: this.videoElement,
|
|
200
326
|
stream
|
|
201
327
|
});
|
|
@@ -203,11 +329,16 @@ class Camera extends EventEmitter {
|
|
|
203
329
|
|
|
204
330
|
async stop() {
|
|
205
331
|
|
|
206
|
-
if (
|
|
207
|
-
throw new Error('Camera is
|
|
332
|
+
if (this._state === Camera.State.STOPPED) {
|
|
333
|
+
throw new Error('Camera is already stopped');
|
|
208
334
|
}
|
|
209
335
|
|
|
210
|
-
this.
|
|
336
|
+
if (this._state === Camera.State.STARTING) {
|
|
337
|
+
await new Promise(resolve => this.once('started', resolve));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
this._state = Camera.State.STOPPING;
|
|
341
|
+
this.emit('stopping', this);
|
|
211
342
|
|
|
212
343
|
if (this.videoStream && this.videoStream.stop) {
|
|
213
344
|
// compatibility with old JS API
|
|
@@ -222,10 +353,13 @@ class Camera extends EventEmitter {
|
|
|
222
353
|
if (this._resizeOnWindowChange) {
|
|
223
354
|
window.removeEventListener('resize', this.notifyContainerSizeChanged);
|
|
224
355
|
}
|
|
225
|
-
|
|
356
|
+
|
|
357
|
+
this._state = Camera.State.STOPPED;
|
|
358
|
+
this.emit('stopped', this);
|
|
226
359
|
}
|
|
227
360
|
|
|
228
361
|
release() {
|
|
362
|
+
this.videoContainer.removeChild(this.videoElement);
|
|
229
363
|
SharedCameras$1._remove(this);
|
|
230
364
|
}
|
|
231
365
|
|
|
@@ -260,8 +394,12 @@ class Camera extends EventEmitter {
|
|
|
260
394
|
}
|
|
261
395
|
}
|
|
262
396
|
|
|
263
|
-
get
|
|
264
|
-
return this.
|
|
397
|
+
get state() {
|
|
398
|
+
return this._state;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
get hardwareVerticalFov() {
|
|
402
|
+
return this._hardwareVerticalFov;
|
|
265
403
|
}
|
|
266
404
|
|
|
267
405
|
set hardwareVerticalFov(hardwareVerticalFov) {
|
|
@@ -320,6 +458,28 @@ class Camera extends EventEmitter {
|
|
|
320
458
|
|
|
321
459
|
this.emit('fov.changed', this.fov);
|
|
322
460
|
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* @returns {Promise<HTMLCanvasElement>}
|
|
464
|
+
*/
|
|
465
|
+
get currentImage() {
|
|
466
|
+
|
|
467
|
+
if (this._state !== Camera.State.STARTED) {
|
|
468
|
+
Logger.warn('Trying to access image but video is not started');
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const { videoWidth: width, videoHeight: height } = this.videoElement;
|
|
473
|
+
const canvas = document.createElement('canvas');
|
|
474
|
+
const context = canvas.getContext('2d');
|
|
475
|
+
// context.filter = 'grayscale(100%)';
|
|
476
|
+
|
|
477
|
+
canvas.width = width;
|
|
478
|
+
canvas.height = height;
|
|
479
|
+
|
|
480
|
+
context.drawImage(this.videoElement, 0, 0, width, height);
|
|
481
|
+
return Promise.resolve(canvas);
|
|
482
|
+
}
|
|
323
483
|
}
|
|
324
484
|
|
|
325
485
|
/* eslint-disable max-statements */
|
|
@@ -387,8 +547,8 @@ class QrCodeScanner extends EventEmitter {
|
|
|
387
547
|
this._canvas = document.createElement('canvas');
|
|
388
548
|
this._ctx = this._canvas.getContext('2d');
|
|
389
549
|
|
|
390
|
-
this._camera.on('
|
|
391
|
-
this._camera.on('
|
|
550
|
+
this._camera.on('started', () => this._tryStart());
|
|
551
|
+
this._camera.on('stopped', () => this._stop());
|
|
392
552
|
}
|
|
393
553
|
|
|
394
554
|
start(intervalTime = 500, formats = QrCodeScanner.DEFAULT_FORMATS) {
|
|
@@ -413,7 +573,7 @@ class QrCodeScanner extends EventEmitter {
|
|
|
413
573
|
|
|
414
574
|
_tryStart() {
|
|
415
575
|
|
|
416
|
-
if (!this._isStarted ||
|
|
576
|
+
if (!this._isStarted || this._camera.state !== Camera.State.STARTED) {
|
|
417
577
|
return;
|
|
418
578
|
}
|
|
419
579
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wemap-camera.es.js","sources":["../src/SharedCameras.js","../src/CameraUtils.js","../src/Camera.js","../src/QrCodeScanner.js"],"sourcesContent":["import EventEmitter from 'events';\n\nimport Camera from './Camera.js';\n\nclass SharedCameras extends EventEmitter {\n\n /**\n * Singleton pattern.\n * @returns {SharedCameras}\n */\n static get instance() {\n if (!this._instance) {\n this._instance = new SharedCameras();\n }\n return this._instance;\n }\n\n /** @type {{container: Node, camera: Camera}[]} */\n _list = [];\n\n /**\n * @param {Camera} camera\n * @param {Node}\n */\n _add(camera, container) {\n const obj = {\n camera,\n container\n };\n this._list.push(obj);\n this.emit('added', obj);\n }\n\n /**\n * @param {Camera} camera\n */\n _remove(camera) {\n this._list = this._list.filter(({ camera: _camera }) => _camera !== camera);\n this.emit('removed', { camera });\n }\n\n /**\n * @returns {{container: Node, camera: Camera}[]}\n */\n get list() {\n return this._list;\n }\n\n /**\n * @param {Node} container\n * @returns {?Camera}\n */\n getCameraByContainer(container) {\n for (const {\n camera, container: _container\n } of this._list) {\n if (container === _container) {\n return camera;\n }\n }\n return null;\n }\n}\n\nexport default SharedCameras.instance;\n","/**\n * @param {number} angle\n * @param {number} aspectRatio\n * @returns {number}\n */\nexport function convertFov(angle, aspectRatio) {\n return 2 * Math.atan(Math.tan((angle / 180 * Math.PI) / 2) * aspectRatio) * 180 / Math.PI;\n}\n\n/**\n * @param {HTMLDivElement} videoContainer\n * @param {HTMLVideoElement} videoElement\n * @param {number} hardwareVerticalFov\n * @returns {object}\n */\nexport function calcDisplayedFov(videoContainer, videoElement, hardwareVerticalFov) {\n\n const sourceWidth = videoElement.videoWidth;\n const sourceHeight = videoElement.videoHeight;\n\n const containerWidth = videoContainer.offsetWidth;\n const containerHeight = videoContainer.offsetHeight;\n\n const sourceAspect = sourceWidth / sourceHeight;\n const screenAspect = containerWidth / containerHeight;\n\n let fovV = hardwareVerticalFov;\n let fovH = convertFov(fovV, sourceAspect);\n\n if (screenAspect < sourceAspect) {\n fovH = convertFov(fovV, screenAspect);\n } else {\n fovV = convertFov(fovH, 1 / screenAspect);\n }\n\n return {\n vertical: fovV,\n horizontal: fovH\n };\n}\n","import EventEmitter from 'events';\n\nimport SharedCameras from './SharedCameras.js';\nimport { calcDisplayedFov } from './CameraUtils.js';\n\n// Helped from https://github.com/jeromeetienne/AR.js/blob/master/three.js/src/threex/threex-artoolkitsource.js\n\n// Camera preview will fill component bounds without transformations.\n// If the component aspect ratio is different from camera aspect ratio,\n// camera preview is extended then cropped.\nclass Camera extends EventEmitter {\n\n static DEFAULT_OPTIONS = {\n width: 1024,\n height: 768,\n resizeOnWindowChange: false\n };\n\n static GENERIC_HARDWARE_VERTICAL_FOV = 60;\n\n videoContainer;\n videoElement;\n\n fov = null;\n\n _isStarted = false;\n\n _hardwareVerticalFov = Camera.GENERIC_HARDWARE_VERTICAL_FOV;\n _resizeOnWindowChange;\n\n /**\n * @param {Node} container\n * @param {{width: number, height: number, resizeOnWindowChange: boolean}} options\n */\n constructor(container, options = {}) {\n super();\n\n options = Object.assign({}, Camera.DEFAULT_OPTIONS, options);\n\n SharedCameras._add(this, container);\n\n this.videoContainer = container;\n\n this._resizeOnWindowChange = options.resizeOnWindowChange;\n this._userMediaConstraints = {\n audio: false,\n video: {\n facingMode: 'environment',\n width: { ideal: options.width },\n height: { ideal: options.height }\n }\n };\n\n this.videoContainer.style.overflow = 'hidden';\n\n this.videoElement = document.createElement('video');\n this.videoElement.setAttribute('id', 'wemap-camera');\n this.videoElement.setAttribute('preload', 'none');\n this.videoElement.setAttribute('muted', '');\n this.videoElement.setAttribute('playsinline', '');\n this.videoContainer.appendChild(this.videoElement);\n }\n\n async start() {\n\n if (this._isStarted) {\n throw new Error('Camera is already started');\n }\n\n this._isStarted = true;\n\n await Camera.checkAvailability();\n\n const stream = await navigator.mediaDevices.getUserMedia(this._userMediaConstraints);\n\n // Listeners have to be set before srcObject assigment or they can be never called\n this.videoElement.oncanplaythrough = () => this.videoElement.play();\n const metadataPr = new Promise(resolve => (this.videoElement.onloadedmetadata = resolve));\n\n this.videoElement.srcObject = this.videoStream = stream;\n await metadataPr;\n\n this._resizeElement();\n this._computeFov();\n\n if (this._resizeOnWindowChange) {\n window.addEventListener('resize', this.notifyContainerSizeChanged);\n }\n\n this.emit('start', {\n videoElement: this.videoElement,\n stream\n });\n }\n\n async stop() {\n\n if (!this._isStarted) {\n throw new Error('Camera is not started yet');\n }\n\n this.emit('stop');\n\n if (this.videoStream && this.videoStream.stop) {\n // compatibility with old JS API\n this.videoStream.stop();\n } else if (this.videoStream) {\n // new JS API\n this.videoStream.getVideoTracks().forEach(track => track.stop());\n }\n this.videoStream = null;\n this.videoElement.srcObject = null;\n\n if (this._resizeOnWindowChange) {\n window.removeEventListener('resize', this.notifyContainerSizeChanged);\n }\n this._isStarted = false;\n }\n\n release() {\n SharedCameras._remove(this);\n }\n\n static async checkAvailability(testUserMedia = false) {\n\n if (!navigator.mediaDevices) {\n throw new Error('navigator.mediaDevices not present in your browser');\n }\n\n if (!navigator.mediaDevices.enumerateDevices) {\n throw new Error('navigator.mediaDevices.enumerateDevices not present in your browser');\n }\n\n if (!navigator.mediaDevices.getUserMedia) {\n throw new Error('navigator.mediaDevices.getUserMedia not present in your browser');\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n if (!devices.find(device => device.kind === 'videoinput')) {\n throw new Error('No camera found');\n }\n\n if (testUserMedia) {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: false, video: { facingMode: 'environment' }\n });\n if (stream.stop) {\n stream.stop();\n } else {\n stream.getVideoTracks().forEach(track => track.stop());\n }\n }\n }\n\n get isStarted() {\n return this._isStarted;\n }\n\n set hardwareVerticalFov(hardwareVerticalFov) {\n this._hardwareVerticalFov = hardwareVerticalFov;\n this._computeFov();\n }\n\n notifyContainerSizeChanged = () => {\n this._resizeElement();\n this._computeFov();\n }\n\n _resizeElement = () => {\n\n if (!this.videoElement) {\n throw new Error('No video element found');\n }\n\n const sourceWidth = this.videoElement.videoWidth;\n const sourceHeight = this.videoElement.videoHeight;\n\n const containerWidth = this.videoContainer.offsetWidth;\n const containerHeight = this.videoContainer.offsetHeight;\n\n const sourceAspect = sourceWidth / sourceHeight;\n const screenAspect = containerWidth / containerHeight;\n\n if (screenAspect < sourceAspect) {\n\n const newWidth = sourceAspect * containerHeight;\n this.videoElement.style.width = newWidth + 'px';\n this.videoElement.style.marginLeft = -(newWidth - containerWidth) / 2 + 'px';\n\n this.videoElement.style.height = containerHeight + 'px';\n this.videoElement.style.marginTop = '0px';\n\n } else {\n\n const newHeight = 1 / (sourceAspect / containerWidth);\n this.videoElement.style.height = newHeight + 'px';\n this.videoElement.style.marginTop = -(newHeight - containerHeight) / 2 + 'px';\n\n this.videoElement.style.width = containerWidth + 'px';\n this.videoElement.style.marginLeft = '0px';\n }\n\n }\n\n _computeFov = () => {\n\n this.fov = calcDisplayedFov(\n this.videoContainer,\n this.videoElement,\n this._hardwareVerticalFov\n );\n\n this.emit('fov.changed', this.fov);\n }\n}\n\nexport default Camera;\n","/* eslint-disable max-statements */\nimport EventEmitter from 'events';\nimport {\n MultiFormatReader,\n BarcodeFormat,\n DecodeHintType,\n RGBLuminanceSource,\n BinaryBitmap,\n HybridBinarizer\n} from '@zxing/library';\n\nimport Camera from './Camera.js';\n\nclass QrCodeScanner extends EventEmitter {\n\n static DEFAULT_FORMATS = [\n BarcodeFormat.QR_CODE,\n BarcodeFormat.DATA_MATRIX,\n BarcodeFormat.CODABAR\n ];\n\n /**\n * @type {Camera}\n */\n _camera;\n\n /**\n * @type {HTMLVideoElement}\n */\n _videoElement;\n\n /**\n * @type {HTMLCanvasElement}\n */\n _canvas;\n\n /**\n * @type {CanvasRenderingContext2D}\n */\n _ctx;\n\n /**\n * @type {MultiFormatReader}\n */\n _codeReader;\n\n /**\n * @type {number}\n */\n _intervalTime;\n\n /**\n * @type {number}\n */\n _intervalTick;\n\n /**\n * @type {boolean}\n */\n _isStarted = false;\n\n\n /**\n * @param {Camera} camera\n */\n constructor(camera) {\n super();\n\n this._camera = camera;\n this._videoElement = camera.videoElement;\n\n this._codeReader = new MultiFormatReader();\n\n this._canvas = document.createElement('canvas');\n this._ctx = this._canvas.getContext('2d');\n\n this._camera.on('start', () => this._tryStart());\n this._camera.on('stop', () => this._stop());\n }\n\n start(intervalTime = 500, formats = QrCodeScanner.DEFAULT_FORMATS) {\n this._intervalTime = intervalTime;\n\n if (this._isStarted) {\n return;\n }\n this._isStarted = true;\n\n const hints = new Map();\n hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);\n this._codeReader.setHints(hints);\n\n this._tryStart();\n }\n\n stop() {\n this._isStarted = false;\n this._stop();\n }\n\n _tryStart() {\n\n if (!this._isStarted || !this._camera.isStarted) {\n return;\n }\n\n this._width = this._videoElement.videoWidth;\n this._height = this._videoElement.videoHeight;\n this._canvas.width = this._width;\n this._canvas.height = this._height;\n this._luminances = new Uint8Array(this._width * this._height);\n\n this._intervalTick = setInterval(() => this._onFrame(), this._intervalTime);\n }\n\n _stop() {\n clearInterval(this._intervalTick);\n }\n\n _onFrame() {\n\n if (!this._width || !this._height) {\n return;\n }\n\n this._ctx.drawImage(this._videoElement, 0, 0, this._width, this._height);\n const img = this._ctx.getImageData(0, 0, this._width, this._height);\n\n for (let i = 0; i < this._luminances.length; i++) {\n // eslint-disable-next-line no-bitwise\n this._luminances[i] = ((img.data[i * 4] + img.data[i * 4 + 1] * 2 + img.data[i * 4 + 2]) / 4) & 0xFF;\n }\n\n const binaryBitmap = new BinaryBitmap(\n new HybridBinarizer(\n new RGBLuminanceSource(this._luminances, this._width, this._height)\n )\n );\n\n try {\n const result = this._codeReader.decodeWithState(binaryBitmap);\n this.emit('scan', result.getText());\n } catch (e) {\n // do nothing\n }\n }\n}\n\nexport default QrCodeScanner;\n"],"names":["SharedCameras"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wemap-camera.es.js","sources":["../src/SharedCameras.js","../src/CameraUtils.js","../src/Camera.js","../src/QrCodeScanner.js"],"sourcesContent":["import EventEmitter from 'events';\n\nimport Camera from './Camera.js';\n\nclass SharedCameras extends EventEmitter {\n\n /**\n * Singleton pattern.\n * @returns {SharedCameras}\n */\n static get instance() {\n if (!this._instance) {\n this._instance = new SharedCameras();\n }\n return this._instance;\n }\n\n /** @type {{container: Node, camera: Camera}[]} */\n _list = [];\n\n /**\n * @param {Camera} camera\n * @param {Node}\n */\n _add(camera, container) {\n const obj = {\n camera,\n container\n };\n this._list.push(obj);\n this.emit('added', obj);\n }\n\n /**\n * @param {Camera} camera\n */\n _remove(camera) {\n this._list = this._list.filter(({ camera: _camera }) => _camera !== camera);\n this.emit('removed', { camera });\n }\n\n /**\n * @returns {{container: Node, camera: Camera}[]}\n */\n get list() {\n return this._list;\n }\n\n /**\n * @param {Node} container\n * @returns {?Camera}\n */\n getCameraByContainer(container) {\n for (const {\n camera, container: _container\n } of this._list) {\n if (container === _container) {\n return camera;\n }\n }\n return null;\n }\n}\n\nexport default SharedCameras.instance;\n","/**\n * @param {number} angle\n * @param {number} aspectRatio\n * @returns {number}\n */\nexport function convertFov(angle, aspectRatio) {\n return 2 * Math.atan(Math.tan((angle / 180 * Math.PI) / 2) * aspectRatio) * 180 / Math.PI;\n}\n\n/**\n * @param {HTMLDivElement} videoContainer\n * @param {HTMLVideoElement} videoElement\n * @param {number} hardwareVerticalFov\n * @returns {object}\n */\nexport function calcDisplayedFov(videoContainer, videoElement, hardwareVerticalFov) {\n\n const sourceWidth = videoElement.videoWidth;\n const sourceHeight = videoElement.videoHeight;\n\n const containerWidth = videoContainer.offsetWidth;\n const containerHeight = videoContainer.offsetHeight;\n\n const sourceAspect = sourceWidth / sourceHeight;\n const screenAspect = containerWidth / containerHeight;\n\n let fovV = hardwareVerticalFov;\n let fovH = convertFov(fovV, sourceAspect);\n\n if (screenAspect < sourceAspect) {\n fovH = convertFov(fovV, screenAspect);\n } else {\n fovV = convertFov(fovH, 1 / screenAspect);\n }\n\n return {\n vertical: fovV,\n horizontal: fovH\n };\n}\n\n/**\n * @param {HTMLCanvasElement} canvas\n * @param {string} type\n * @param {any} quality\n * @returns {string}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL\n */\nexport function canvasToBase64(canvas, type = 'image/png', quality = null) {\n return canvas\n .toDataURL(type, quality)\n .substring(('data:' + type + ';base64,').length);\n}\n\n/**\n * Creates a pinhole camera from dimensions and a field of view\n * Distortions are not considered\n *\n * @param {number} width the camera width\n * @param {number} height the camera height\n * @param {number} fovOfWidth the field of view along the width axis in radians\n * @returns {object} the calibration matrix\n */\nexport function createCameraCalibrationFromWidthHeightFov(width, height, fovOfWidth) {\n\n const fovOfHeight = 2 * Math.atan(height * Math.tan(fovOfWidth / 2) / width);\n\n const fx = width / (2 * Math.tan(0.5 * fovOfWidth));\n const fy = height / (2 * Math.tan(0.5 * fovOfHeight));\n const cx = width / 2;\n const cy = height / 2;\n\n return {\n intrinsic: [fx, 0, cx, 0, fy, cy, 0, 0, 1],\n distortions: [0, 0, 0, 0, 0]\n };\n}\n\n/**\n * @param {HTMLCanvasElement} imageCanvas\n */\nexport function convertToGrayscale(imageCanvas) {\n const ctx = imageCanvas.getContext('2d');\n const imgData = ctx.getImageData(0, 0, imageCanvas.width, imageCanvas.height);\n const pixels = imgData.data;\n for (let i = 0; i < pixels.length; i += 4) {\n\n const lightness = parseInt((pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3, 10);\n pixels[i] = lightness;\n pixels[i + 1] = lightness;\n pixels[i + 2] = lightness;\n }\n ctx.putImageData(imgData, 0, 0);\n}\n\n/**\n * Reduce image size and keep aspect ratio\n * @param {HTMLCanvasElement} imageCanvas\n */\nexport function reduceImageSize(imageCanvas, maxWidth, maxHeight = null) {\n\n let newWidth = imageCanvas.width;\n let newHeight = imageCanvas.height;\n\n if (maxHeight !== null) {\n if (newWidth > maxWidth) {\n newHeight *= maxWidth / newWidth;\n newWidth = maxWidth;\n }\n\n if (newHeight > maxHeight) {\n newWidth *= maxHeight / newHeight;\n newHeight = maxHeight;\n }\n } else {\n const aspectRatio = imageCanvas.width / imageCanvas.height;\n if (imageCanvas.width > imageCanvas.height) {\n if (imageCanvas.width > maxWidth) {\n newWidth = maxWidth;\n newHeight = maxWidth / aspectRatio;\n }\n } else if (imageCanvas.height > maxWidth) {\n newHeight = maxWidth;\n newWidth = maxWidth * aspectRatio;\n }\n }\n\n\n if (newWidth === imageCanvas.width\n && newHeight === imageCanvas.height) {\n return imageCanvas;\n }\n\n const newCanvas = document.createElement('canvas');\n const newContext = newCanvas.getContext('2d');\n\n newCanvas.width = newWidth;\n newCanvas.height = newHeight;\n newContext.drawImage(imageCanvas, 0, 0, newCanvas.width, newCanvas.height);\n\n return newCanvas;\n}\n\n","import EventEmitter from 'events';\n\nimport Logger from '@wemap/logger';\nimport SharedCameras from './SharedCameras.js';\nimport { calcDisplayedFov } from './CameraUtils.js';\n\n// Helped from https://github.com/jeromeetienne/AR.js/blob/master/three.js/src/threex/threex-artoolkitsource.js\n\n// Camera preview will fill component bounds without transformations.\n// If the component aspect ratio is different from camera aspect ratio,\n// camera preview is extended then cropped.\nclass Camera extends EventEmitter {\n\n static State = {\n STOPPED: 'stopped',\n STARTING: 'starting',\n STARTED: 'started',\n STOPPING: 'stopping'\n }\n\n static DEFAULT_OPTIONS = {\n width: 1024,\n height: 768,\n resizeOnWindowChange: false\n };\n\n static GENERIC_HARDWARE_VERTICAL_FOV = 60;\n\n videoContainer;\n videoElement;\n\n fov = null;\n\n _state = Camera.State.STOPPED;\n\n _hardwareVerticalFov = Camera.GENERIC_HARDWARE_VERTICAL_FOV;\n _resizeOnWindowChange;\n\n /**\n * @param {Node} container\n * @param {{width: number, height: number, resizeOnWindowChange: boolean}} options\n */\n constructor(container, options = {}) {\n super();\n\n options = Object.assign({}, Camera.DEFAULT_OPTIONS, options);\n\n SharedCameras._add(this, container);\n\n this.videoContainer = container;\n\n this._resizeOnWindowChange = options.resizeOnWindowChange;\n this._userMediaConstraints = {\n audio: false,\n video: {\n facingMode: 'environment',\n width: { ideal: options.width },\n height: { ideal: options.height },\n resizeMode: 'none'\n }\n };\n\n this.videoContainer.style.overflow = 'hidden';\n\n this.videoElement = document.createElement('video');\n this.videoElement.setAttribute('id', 'wemap-camera');\n this.videoElement.setAttribute('preload', 'none');\n this.videoElement.setAttribute('muted', '');\n this.videoElement.setAttribute('playsinline', '');\n this.videoContainer.appendChild(this.videoElement);\n }\n\n async start(videoMediaConstraints = null) {\n\n if (this._state !== Camera.State.STOPPED) {\n throw new Error('Camera is already started');\n }\n\n if (this._state === Camera.State.STOPPING) {\n await new Promise(resolve => this.once('stopped', resolve));\n }\n\n this._state = Camera.State.STARTING;\n this.emit('starting');\n\n await Camera.checkAvailability();\n\n if (videoMediaConstraints) {\n Object.assign(this._userMediaConstraints.video,\n this._userMediaConstraints.video, videoMediaConstraints);\n }\n\n const stream = await navigator.mediaDevices.getUserMedia(this._userMediaConstraints);\n\n // Listeners have to be set before srcObject assigment or they can be never called\n this.videoElement.oncanplaythrough = () => this.videoElement.play();\n const metadataPr = new Promise(resolve => (this.videoElement.onloadedmetadata = resolve));\n\n this.videoElement.srcObject = this.videoStream = stream;\n await metadataPr;\n\n this._resizeElement();\n this._computeFov();\n\n if (this._resizeOnWindowChange) {\n window.addEventListener('resize', this.notifyContainerSizeChanged);\n }\n\n this._state = Camera.State.STARTED;\n this.emit('started', {\n videoElement: this.videoElement,\n stream\n });\n }\n\n async stop() {\n\n if (this._state === Camera.State.STOPPED) {\n throw new Error('Camera is already stopped');\n }\n\n if (this._state === Camera.State.STARTING) {\n await new Promise(resolve => this.once('started', resolve));\n }\n\n this._state = Camera.State.STOPPING;\n this.emit('stopping', this);\n\n if (this.videoStream && this.videoStream.stop) {\n // compatibility with old JS API\n this.videoStream.stop();\n } else if (this.videoStream) {\n // new JS API\n this.videoStream.getVideoTracks().forEach(track => track.stop());\n }\n this.videoStream = null;\n this.videoElement.srcObject = null;\n\n if (this._resizeOnWindowChange) {\n window.removeEventListener('resize', this.notifyContainerSizeChanged);\n }\n\n this._state = Camera.State.STOPPED;\n this.emit('stopped', this);\n }\n\n release() {\n this.videoContainer.removeChild(this.videoElement);\n SharedCameras._remove(this);\n }\n\n static async checkAvailability(testUserMedia = false) {\n\n if (!navigator.mediaDevices) {\n throw new Error('navigator.mediaDevices not present in your browser');\n }\n\n if (!navigator.mediaDevices.enumerateDevices) {\n throw new Error('navigator.mediaDevices.enumerateDevices not present in your browser');\n }\n\n if (!navigator.mediaDevices.getUserMedia) {\n throw new Error('navigator.mediaDevices.getUserMedia not present in your browser');\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n if (!devices.find(device => device.kind === 'videoinput')) {\n throw new Error('No camera found');\n }\n\n if (testUserMedia) {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: false, video: { facingMode: 'environment' }\n });\n if (stream.stop) {\n stream.stop();\n } else {\n stream.getVideoTracks().forEach(track => track.stop());\n }\n }\n }\n\n get state() {\n return this._state;\n }\n\n get hardwareVerticalFov() {\n return this._hardwareVerticalFov;\n }\n\n set hardwareVerticalFov(hardwareVerticalFov) {\n this._hardwareVerticalFov = hardwareVerticalFov;\n this._computeFov();\n }\n\n notifyContainerSizeChanged = () => {\n this._resizeElement();\n this._computeFov();\n }\n\n _resizeElement = () => {\n\n if (!this.videoElement) {\n throw new Error('No video element found');\n }\n\n const sourceWidth = this.videoElement.videoWidth;\n const sourceHeight = this.videoElement.videoHeight;\n\n const containerWidth = this.videoContainer.offsetWidth;\n const containerHeight = this.videoContainer.offsetHeight;\n\n const sourceAspect = sourceWidth / sourceHeight;\n const screenAspect = containerWidth / containerHeight;\n\n if (screenAspect < sourceAspect) {\n\n const newWidth = sourceAspect * containerHeight;\n this.videoElement.style.width = newWidth + 'px';\n this.videoElement.style.marginLeft = -(newWidth - containerWidth) / 2 + 'px';\n\n this.videoElement.style.height = containerHeight + 'px';\n this.videoElement.style.marginTop = '0px';\n\n } else {\n\n const newHeight = 1 / (sourceAspect / containerWidth);\n this.videoElement.style.height = newHeight + 'px';\n this.videoElement.style.marginTop = -(newHeight - containerHeight) / 2 + 'px';\n\n this.videoElement.style.width = containerWidth + 'px';\n this.videoElement.style.marginLeft = '0px';\n }\n\n }\n\n _computeFov = () => {\n\n this.fov = calcDisplayedFov(\n this.videoContainer,\n this.videoElement,\n this._hardwareVerticalFov\n );\n\n this.emit('fov.changed', this.fov);\n }\n\n /**\n * @returns {Promise<HTMLCanvasElement>}\n */\n get currentImage() {\n\n if (this._state !== Camera.State.STARTED) {\n Logger.warn('Trying to access image but video is not started');\n return null;\n }\n\n const { videoWidth: width, videoHeight: height } = this.videoElement;\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n // context.filter = 'grayscale(100%)';\n\n canvas.width = width;\n canvas.height = height;\n\n context.drawImage(this.videoElement, 0, 0, width, height);\n return Promise.resolve(canvas);\n }\n}\n\nexport default Camera;\n","/* eslint-disable max-statements */\nimport EventEmitter from 'events';\nimport {\n MultiFormatReader,\n BarcodeFormat,\n DecodeHintType,\n RGBLuminanceSource,\n BinaryBitmap,\n HybridBinarizer\n} from '@zxing/library';\n\nimport Camera from './Camera.js';\n\nclass QrCodeScanner extends EventEmitter {\n\n static DEFAULT_FORMATS = [\n BarcodeFormat.QR_CODE,\n BarcodeFormat.DATA_MATRIX,\n BarcodeFormat.CODABAR\n ];\n\n /**\n * @type {Camera}\n */\n _camera;\n\n /**\n * @type {HTMLVideoElement}\n */\n _videoElement;\n\n /**\n * @type {HTMLCanvasElement}\n */\n _canvas;\n\n /**\n * @type {CanvasRenderingContext2D}\n */\n _ctx;\n\n /**\n * @type {MultiFormatReader}\n */\n _codeReader;\n\n /**\n * @type {number}\n */\n _intervalTime;\n\n /**\n * @type {number}\n */\n _intervalTick;\n\n /**\n * @type {boolean}\n */\n _isStarted = false;\n\n\n /**\n * @param {Camera} camera\n */\n constructor(camera) {\n super();\n\n this._camera = camera;\n this._videoElement = camera.videoElement;\n\n this._codeReader = new MultiFormatReader();\n\n this._canvas = document.createElement('canvas');\n this._ctx = this._canvas.getContext('2d');\n\n this._camera.on('started', () => this._tryStart());\n this._camera.on('stopped', () => this._stop());\n }\n\n start(intervalTime = 500, formats = QrCodeScanner.DEFAULT_FORMATS) {\n this._intervalTime = intervalTime;\n\n if (this._isStarted) {\n return;\n }\n this._isStarted = true;\n\n const hints = new Map();\n hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);\n this._codeReader.setHints(hints);\n\n this._tryStart();\n }\n\n stop() {\n this._isStarted = false;\n this._stop();\n }\n\n _tryStart() {\n\n if (!this._isStarted || this._camera.state !== Camera.State.STARTED) {\n return;\n }\n\n this._width = this._videoElement.videoWidth;\n this._height = this._videoElement.videoHeight;\n this._canvas.width = this._width;\n this._canvas.height = this._height;\n this._luminances = new Uint8Array(this._width * this._height);\n\n this._intervalTick = setInterval(() => this._onFrame(), this._intervalTime);\n }\n\n _stop() {\n clearInterval(this._intervalTick);\n }\n\n _onFrame() {\n\n if (!this._width || !this._height) {\n return;\n }\n\n this._ctx.drawImage(this._videoElement, 0, 0, this._width, this._height);\n const img = this._ctx.getImageData(0, 0, this._width, this._height);\n\n for (let i = 0; i < this._luminances.length; i++) {\n // eslint-disable-next-line no-bitwise\n this._luminances[i] = ((img.data[i * 4] + img.data[i * 4 + 1] * 2 + img.data[i * 4 + 2]) / 4) & 0xFF;\n }\n\n const binaryBitmap = new BinaryBitmap(\n new HybridBinarizer(\n new RGBLuminanceSource(this._luminances, this._width, this._height)\n )\n );\n\n try {\n const result = this._codeReader.decodeWithState(binaryBitmap);\n this.emit('scan', result.getText());\n } catch (e) {\n // do nothing\n }\n }\n}\n\nexport default QrCodeScanner;\n"],"names":["SharedCameras"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/camera"
|
|
12
12
|
},
|
|
13
13
|
"name": "@wemap/camera",
|
|
14
|
-
"version": "
|
|
14
|
+
"version": "7.0.0",
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/wemap/wemap-modules-js/issues"
|
|
17
17
|
},
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
],
|
|
24
24
|
"license": "ISC",
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@wemap/logger": "^7.0.0",
|
|
26
27
|
"@zxing/library": "^0.18.4",
|
|
27
28
|
"events": "^3.3.0"
|
|
28
29
|
},
|
|
29
30
|
"type": "module",
|
|
30
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "cfd70d1f998599c53689c1b1996a517247f04dce"
|
|
31
32
|
}
|
package/src/Camera.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
|
|
3
|
+
import Logger from '@wemap/logger';
|
|
3
4
|
import SharedCameras from './SharedCameras.js';
|
|
4
5
|
import { calcDisplayedFov } from './CameraUtils.js';
|
|
5
6
|
|
|
@@ -10,6 +11,13 @@ import { calcDisplayedFov } from './CameraUtils.js';
|
|
|
10
11
|
// camera preview is extended then cropped.
|
|
11
12
|
class Camera extends EventEmitter {
|
|
12
13
|
|
|
14
|
+
static State = {
|
|
15
|
+
STOPPED: 'stopped',
|
|
16
|
+
STARTING: 'starting',
|
|
17
|
+
STARTED: 'started',
|
|
18
|
+
STOPPING: 'stopping'
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
static DEFAULT_OPTIONS = {
|
|
14
22
|
width: 1024,
|
|
15
23
|
height: 768,
|
|
@@ -23,7 +31,7 @@ class Camera extends EventEmitter {
|
|
|
23
31
|
|
|
24
32
|
fov = null;
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
_state = Camera.State.STOPPED;
|
|
27
35
|
|
|
28
36
|
_hardwareVerticalFov = Camera.GENERIC_HARDWARE_VERTICAL_FOV;
|
|
29
37
|
_resizeOnWindowChange;
|
|
@@ -47,7 +55,8 @@ class Camera extends EventEmitter {
|
|
|
47
55
|
video: {
|
|
48
56
|
facingMode: 'environment',
|
|
49
57
|
width: { ideal: options.width },
|
|
50
|
-
height: { ideal: options.height }
|
|
58
|
+
height: { ideal: options.height },
|
|
59
|
+
resizeMode: 'none'
|
|
51
60
|
}
|
|
52
61
|
};
|
|
53
62
|
|
|
@@ -61,16 +70,26 @@ class Camera extends EventEmitter {
|
|
|
61
70
|
this.videoContainer.appendChild(this.videoElement);
|
|
62
71
|
}
|
|
63
72
|
|
|
64
|
-
async start() {
|
|
73
|
+
async start(videoMediaConstraints = null) {
|
|
65
74
|
|
|
66
|
-
if (this.
|
|
75
|
+
if (this._state !== Camera.State.STOPPED) {
|
|
67
76
|
throw new Error('Camera is already started');
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
this.
|
|
79
|
+
if (this._state === Camera.State.STOPPING) {
|
|
80
|
+
await new Promise(resolve => this.once('stopped', resolve));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._state = Camera.State.STARTING;
|
|
84
|
+
this.emit('starting');
|
|
71
85
|
|
|
72
86
|
await Camera.checkAvailability();
|
|
73
87
|
|
|
88
|
+
if (videoMediaConstraints) {
|
|
89
|
+
Object.assign(this._userMediaConstraints.video,
|
|
90
|
+
this._userMediaConstraints.video, videoMediaConstraints);
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
const stream = await navigator.mediaDevices.getUserMedia(this._userMediaConstraints);
|
|
75
94
|
|
|
76
95
|
// Listeners have to be set before srcObject assigment or they can be never called
|
|
@@ -87,7 +106,8 @@ class Camera extends EventEmitter {
|
|
|
87
106
|
window.addEventListener('resize', this.notifyContainerSizeChanged);
|
|
88
107
|
}
|
|
89
108
|
|
|
90
|
-
this.
|
|
109
|
+
this._state = Camera.State.STARTED;
|
|
110
|
+
this.emit('started', {
|
|
91
111
|
videoElement: this.videoElement,
|
|
92
112
|
stream
|
|
93
113
|
});
|
|
@@ -95,11 +115,16 @@ class Camera extends EventEmitter {
|
|
|
95
115
|
|
|
96
116
|
async stop() {
|
|
97
117
|
|
|
98
|
-
if (
|
|
99
|
-
throw new Error('Camera is
|
|
118
|
+
if (this._state === Camera.State.STOPPED) {
|
|
119
|
+
throw new Error('Camera is already stopped');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this._state === Camera.State.STARTING) {
|
|
123
|
+
await new Promise(resolve => this.once('started', resolve));
|
|
100
124
|
}
|
|
101
125
|
|
|
102
|
-
this.
|
|
126
|
+
this._state = Camera.State.STOPPING;
|
|
127
|
+
this.emit('stopping', this);
|
|
103
128
|
|
|
104
129
|
if (this.videoStream && this.videoStream.stop) {
|
|
105
130
|
// compatibility with old JS API
|
|
@@ -114,10 +139,13 @@ class Camera extends EventEmitter {
|
|
|
114
139
|
if (this._resizeOnWindowChange) {
|
|
115
140
|
window.removeEventListener('resize', this.notifyContainerSizeChanged);
|
|
116
141
|
}
|
|
117
|
-
|
|
142
|
+
|
|
143
|
+
this._state = Camera.State.STOPPED;
|
|
144
|
+
this.emit('stopped', this);
|
|
118
145
|
}
|
|
119
146
|
|
|
120
147
|
release() {
|
|
148
|
+
this.videoContainer.removeChild(this.videoElement);
|
|
121
149
|
SharedCameras._remove(this);
|
|
122
150
|
}
|
|
123
151
|
|
|
@@ -152,8 +180,12 @@ class Camera extends EventEmitter {
|
|
|
152
180
|
}
|
|
153
181
|
}
|
|
154
182
|
|
|
155
|
-
get
|
|
156
|
-
return this.
|
|
183
|
+
get state() {
|
|
184
|
+
return this._state;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get hardwareVerticalFov() {
|
|
188
|
+
return this._hardwareVerticalFov;
|
|
157
189
|
}
|
|
158
190
|
|
|
159
191
|
set hardwareVerticalFov(hardwareVerticalFov) {
|
|
@@ -212,6 +244,28 @@ class Camera extends EventEmitter {
|
|
|
212
244
|
|
|
213
245
|
this.emit('fov.changed', this.fov);
|
|
214
246
|
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @returns {Promise<HTMLCanvasElement>}
|
|
250
|
+
*/
|
|
251
|
+
get currentImage() {
|
|
252
|
+
|
|
253
|
+
if (this._state !== Camera.State.STARTED) {
|
|
254
|
+
Logger.warn('Trying to access image but video is not started');
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const { videoWidth: width, videoHeight: height } = this.videoElement;
|
|
259
|
+
const canvas = document.createElement('canvas');
|
|
260
|
+
const context = canvas.getContext('2d');
|
|
261
|
+
// context.filter = 'grayscale(100%)';
|
|
262
|
+
|
|
263
|
+
canvas.width = width;
|
|
264
|
+
canvas.height = height;
|
|
265
|
+
|
|
266
|
+
context.drawImage(this.videoElement, 0, 0, width, height);
|
|
267
|
+
return Promise.resolve(canvas);
|
|
268
|
+
}
|
|
215
269
|
}
|
|
216
270
|
|
|
217
271
|
export default Camera;
|
package/src/CameraUtils.js
CHANGED
|
@@ -38,3 +38,106 @@ export function calcDisplayedFov(videoContainer, videoElement, hardwareVerticalF
|
|
|
38
38
|
horizontal: fovH
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {HTMLCanvasElement} canvas
|
|
44
|
+
* @param {string} type
|
|
45
|
+
* @param {any} quality
|
|
46
|
+
* @returns {string}
|
|
47
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
|
|
48
|
+
*/
|
|
49
|
+
export function canvasToBase64(canvas, type = 'image/png', quality = null) {
|
|
50
|
+
return canvas
|
|
51
|
+
.toDataURL(type, quality)
|
|
52
|
+
.substring(('data:' + type + ';base64,').length);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a pinhole camera from dimensions and a field of view
|
|
57
|
+
* Distortions are not considered
|
|
58
|
+
*
|
|
59
|
+
* @param {number} width the camera width
|
|
60
|
+
* @param {number} height the camera height
|
|
61
|
+
* @param {number} fovOfWidth the field of view along the width axis in radians
|
|
62
|
+
* @returns {object} the calibration matrix
|
|
63
|
+
*/
|
|
64
|
+
export function createCameraCalibrationFromWidthHeightFov(width, height, fovOfWidth) {
|
|
65
|
+
|
|
66
|
+
const fovOfHeight = 2 * Math.atan(height * Math.tan(fovOfWidth / 2) / width);
|
|
67
|
+
|
|
68
|
+
const fx = width / (2 * Math.tan(0.5 * fovOfWidth));
|
|
69
|
+
const fy = height / (2 * Math.tan(0.5 * fovOfHeight));
|
|
70
|
+
const cx = width / 2;
|
|
71
|
+
const cy = height / 2;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
intrinsic: [fx, 0, cx, 0, fy, cy, 0, 0, 1],
|
|
75
|
+
distortions: [0, 0, 0, 0, 0]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {HTMLCanvasElement} imageCanvas
|
|
81
|
+
*/
|
|
82
|
+
export function convertToGrayscale(imageCanvas) {
|
|
83
|
+
const ctx = imageCanvas.getContext('2d');
|
|
84
|
+
const imgData = ctx.getImageData(0, 0, imageCanvas.width, imageCanvas.height);
|
|
85
|
+
const pixels = imgData.data;
|
|
86
|
+
for (let i = 0; i < pixels.length; i += 4) {
|
|
87
|
+
|
|
88
|
+
const lightness = parseInt((pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3, 10);
|
|
89
|
+
pixels[i] = lightness;
|
|
90
|
+
pixels[i + 1] = lightness;
|
|
91
|
+
pixels[i + 2] = lightness;
|
|
92
|
+
}
|
|
93
|
+
ctx.putImageData(imgData, 0, 0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Reduce image size and keep aspect ratio
|
|
98
|
+
* @param {HTMLCanvasElement} imageCanvas
|
|
99
|
+
*/
|
|
100
|
+
export function reduceImageSize(imageCanvas, maxWidth, maxHeight = null) {
|
|
101
|
+
|
|
102
|
+
let newWidth = imageCanvas.width;
|
|
103
|
+
let newHeight = imageCanvas.height;
|
|
104
|
+
|
|
105
|
+
if (maxHeight !== null) {
|
|
106
|
+
if (newWidth > maxWidth) {
|
|
107
|
+
newHeight *= maxWidth / newWidth;
|
|
108
|
+
newWidth = maxWidth;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (newHeight > maxHeight) {
|
|
112
|
+
newWidth *= maxHeight / newHeight;
|
|
113
|
+
newHeight = maxHeight;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
const aspectRatio = imageCanvas.width / imageCanvas.height;
|
|
117
|
+
if (imageCanvas.width > imageCanvas.height) {
|
|
118
|
+
if (imageCanvas.width > maxWidth) {
|
|
119
|
+
newWidth = maxWidth;
|
|
120
|
+
newHeight = maxWidth / aspectRatio;
|
|
121
|
+
}
|
|
122
|
+
} else if (imageCanvas.height > maxWidth) {
|
|
123
|
+
newHeight = maxWidth;
|
|
124
|
+
newWidth = maxWidth * aspectRatio;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if (newWidth === imageCanvas.width
|
|
130
|
+
&& newHeight === imageCanvas.height) {
|
|
131
|
+
return imageCanvas;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const newCanvas = document.createElement('canvas');
|
|
135
|
+
const newContext = newCanvas.getContext('2d');
|
|
136
|
+
|
|
137
|
+
newCanvas.width = newWidth;
|
|
138
|
+
newCanvas.height = newHeight;
|
|
139
|
+
newContext.drawImage(imageCanvas, 0, 0, newCanvas.width, newCanvas.height);
|
|
140
|
+
|
|
141
|
+
return newCanvas;
|
|
142
|
+
}
|
|
143
|
+
|
package/src/QrCodeScanner.js
CHANGED
|
@@ -74,8 +74,8 @@ class QrCodeScanner extends EventEmitter {
|
|
|
74
74
|
this._canvas = document.createElement('canvas');
|
|
75
75
|
this._ctx = this._canvas.getContext('2d');
|
|
76
76
|
|
|
77
|
-
this._camera.on('
|
|
78
|
-
this._camera.on('
|
|
77
|
+
this._camera.on('started', () => this._tryStart());
|
|
78
|
+
this._camera.on('stopped', () => this._stop());
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
start(intervalTime = 500, formats = QrCodeScanner.DEFAULT_FORMATS) {
|
|
@@ -100,7 +100,7 @@ class QrCodeScanner extends EventEmitter {
|
|
|
100
100
|
|
|
101
101
|
_tryStart() {
|
|
102
102
|
|
|
103
|
-
if (!this._isStarted ||
|
|
103
|
+
if (!this._isStarted || this._camera.state !== Camera.State.STARTED) {
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|