@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.
@@ -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
- _isStarted = false;
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._isStarted) {
289
+ if (this._state !== Camera.State.STOPPED) {
175
290
  throw new Error('Camera is already started');
176
291
  }
177
292
 
178
- this._isStarted = true;
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.emit('start', {
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 (!this._isStarted) {
207
- throw new Error('Camera is not started yet');
332
+ if (this._state === Camera.State.STOPPED) {
333
+ throw new Error('Camera is already stopped');
208
334
  }
209
335
 
210
- this.emit('stop');
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
- this._isStarted = false;
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 isStarted() {
264
- return this._isStarted;
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('start', () => this._tryStart());
391
- this._camera.on('stop', () => this._stop());
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 || !this._camera.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":";;;;;AAIA,MAAM,aAAa,SAAS,YAAY,CAAC;AACzC;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,QAAQ,GAAG;AAC1B,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AAC7B,YAAY,IAAI,CAAC,SAAS,GAAG,IAAI,aAAa,EAAE,CAAC;AACjD,SAAS;AACT,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC;AAC9B,KAAK;AACL;AACA;AACA,IAAI,KAAK,GAAG,EAAE;AACd;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAC5B,QAAQ,MAAM,GAAG,GAAG;AACpB,YAAY,MAAM;AAClB,YAAY,SAAS;AACrB,SAAS,CAAC;AACV,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAChC,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,MAAM,EAAE;AACpB,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO,KAAK,MAAM,CAAC,CAAC;AACpF,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACzC,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,IAAI,IAAI,GAAG;AACf,QAAQ,OAAO,IAAI,CAAC,KAAK,CAAC;AAC1B,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,CAAC,SAAS,EAAE;AACpC,QAAQ,KAAK,MAAM;AACnB,YAAY,MAAM,EAAE,SAAS,EAAE,UAAU;AACzC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE;AACzB,YAAY,IAAI,SAAS,KAAK,UAAU,EAAE;AAC1C,gBAAgB,OAAO,MAAM,CAAC;AAC9B,aAAa;AACb,SAAS;AACT,QAAQ,OAAO,IAAI,CAAC;AACpB,KAAK;AACL,CAAC;AACD;AACA,sBAAe,aAAa,CAAC,QAAQ;;AChErC;AACA;AACA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE;AAC/C,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC;AAC9F,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE;AACpF;AACA,IAAI,MAAM,WAAW,GAAG,YAAY,CAAC,UAAU,CAAC;AAChD,IAAI,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,CAAC;AAClD;AACA,IAAI,MAAM,cAAc,GAAG,cAAc,CAAC,WAAW,CAAC;AACtD,IAAI,MAAM,eAAe,GAAG,cAAc,CAAC,YAAY,CAAC;AACxD;AACA,IAAI,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;AACpD,IAAI,MAAM,YAAY,GAAG,cAAc,GAAG,eAAe,CAAC;AAC1D;AACA,IAAI,IAAI,IAAI,GAAG,mBAAmB,CAAC;AACnC,IAAI,IAAI,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AAC9C;AACA,IAAI,IAAI,YAAY,GAAG,YAAY,EAAE;AACrC,QAAQ,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AAC9C,KAAK,MAAM;AACX,QAAQ,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC;AAClD,KAAK;AACL;AACA,IAAI,OAAO;AACX,QAAQ,QAAQ,EAAE,IAAI;AACtB,QAAQ,UAAU,EAAE,IAAI;AACxB,KAAK,CAAC;AACN,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,GAAG,WAAW,EAAE,OAAO,GAAG,IAAI,EAAE;AAC3E,IAAI,OAAO,MAAM;AACjB,SAAS,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC;AACjC,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,IAAI,GAAG,UAAU,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,yCAAyC,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE;AACrF;AACA,IAAI,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AACjF;AACA,IAAI,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC;AACxD,IAAI,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC;AAC1D,IAAI,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;AACzB,IAAI,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC;AAC1B;AACA,IAAI,OAAO;AACX,QAAQ,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAClD,QAAQ,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpC,KAAK,CAAC;AACN,CAAC;AACD;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAC,WAAW,EAAE;AAChD,IAAI,MAAM,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC7C,IAAI,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;AAClF,IAAI,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;AAChC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;AAC/C;AACA,QAAQ,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AACxF,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AAC9B,QAAQ,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;AAClC,QAAQ,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;AAClC,KAAK;AACL,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACpC,CAAC;AACD;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI,EAAE;AACzE;AACA,IAAI,IAAI,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC;AACrC,IAAI,IAAI,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC;AACvC;AACA,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE;AAC5B,QAAQ,IAAI,QAAQ,GAAG,QAAQ,EAAE;AACjC,YAAY,SAAS,IAAI,QAAQ,GAAG,QAAQ,CAAC;AAC7C,YAAY,QAAQ,GAAG,QAAQ,CAAC;AAChC,SAAS;AACT;AACA,QAAQ,IAAI,SAAS,GAAG,SAAS,EAAE;AACnC,YAAY,QAAQ,IAAI,SAAS,GAAG,SAAS,CAAC;AAC9C,YAAY,SAAS,GAAG,SAAS,CAAC;AAClC,SAAS;AACT,KAAK,MAAM;AACX,QAAQ,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;AACnE,QAAQ,IAAI,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE;AACpD,YAAY,IAAI,WAAW,CAAC,KAAK,GAAG,QAAQ,EAAE;AAC9C,gBAAgB,QAAQ,GAAG,QAAQ,CAAC;AACpC,gBAAgB,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AACnD,aAAa;AACb,SAAS,MAAM,IAAI,WAAW,CAAC,MAAM,GAAG,QAAQ,EAAE;AAClD,YAAY,SAAS,GAAG,QAAQ,CAAC;AACjC,YAAY,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAC9C,SAAS;AACT,KAAK;AACL;AACA;AACA,IAAI,IAAI,QAAQ,KAAK,WAAW,CAAC,KAAK;AACtC,WAAW,SAAS,KAAK,WAAW,CAAC,MAAM,EAAE;AAC7C,QAAQ,OAAO,WAAW,CAAC;AAC3B,KAAK;AACL;AACA,IAAI,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AACvD,IAAI,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAClD;AACA,IAAI,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC;AAC/B,IAAI,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC;AACjC,IAAI,UAAU,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;AAC/E;AACA,IAAI,OAAO,SAAS,CAAC;AACrB;;;;;;;;;;;;ACvIA;AACA;AACA;AACA;AACA;AACA,MAAM,MAAM,SAAS,YAAY,CAAC;AAClC;AACA,IAAI,OAAO,KAAK,GAAG;AACnB,QAAQ,OAAO,EAAE,SAAS;AAC1B,QAAQ,QAAQ,EAAE,UAAU;AAC5B,QAAQ,OAAO,EAAE,SAAS;AAC1B,QAAQ,QAAQ,EAAE,UAAU;AAC5B,KAAK;AACL;AACA,IAAI,OAAO,eAAe,GAAG;AAC7B,QAAQ,KAAK,EAAE,IAAI;AACnB,QAAQ,MAAM,EAAE,GAAG;AACnB,QAAQ,oBAAoB,EAAE,KAAK;AACnC,KAAK;AACL;AACA,IAAI,OAAO,6BAA6B,GAAG,EAAE;AAC7C;AACA,IAAI,cAAc;AAClB,IAAI,YAAY;AAChB;AACA,IAAI,GAAG,GAAG,IAAI;AACd;AACA,IAAI,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO;AACjC;AACA,IAAI,oBAAoB,GAAG,MAAM,CAAC,6BAA6B;AAC/D,IAAI,qBAAqB;AACzB;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK,EAAE,CAAC;AAChB;AACA,QAAQ,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;AACrE;AACA,QAAQA,eAAa,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC5C;AACA,QAAQ,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;AACxC;AACA,QAAQ,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;AAClE,QAAQ,IAAI,CAAC,qBAAqB,GAAG;AACrC,YAAY,KAAK,EAAE,KAAK;AACxB,YAAY,KAAK,EAAE;AACnB,gBAAgB,UAAU,EAAE,aAAa;AACzC,gBAAgB,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;AAC/C,gBAAgB,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;AACjD,gBAAgB,UAAU,EAAE,MAAM;AAClC,aAAa;AACb,SAAS,CAAC;AACV;AACA,QAAQ,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;AACtD;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;AAC5D,QAAQ,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAC7D,QAAQ,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAC1D,QAAQ,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAC1D,QAAQ,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAC3D,KAAK;AACL;AACA,IAAI,MAAM,KAAK,CAAC,qBAAqB,GAAG,IAAI,EAAE;AAC9C;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AAClD,YAAY,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACzD,SAAS;AACT;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE;AACnD,YAAY,MAAM,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AACxE,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC5C,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9B;AACA,QAAQ,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;AACzC;AACA,QAAQ,IAAI,qBAAqB,EAAE;AACnC,YAAY,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK;AAC1D,gBAAgB,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;AACzE,SAAS;AACT;AACA,QAAQ,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAC7F;AACA;AACA,QAAQ,IAAI,CAAC,YAAY,CAAC,gBAAgB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;AAC5E,QAAQ,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,YAAY,CAAC,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;AAClG;AACA,QAAQ,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;AAChE,QAAQ,MAAM,UAAU,CAAC;AACzB;AACA,QAAQ,IAAI,CAAC,cAAc,EAAE,CAAC;AAC9B,QAAQ,IAAI,CAAC,WAAW,EAAE,CAAC;AAC3B;AACA,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE;AACxC,YAAY,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAC/E,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AAC7B,YAAY,YAAY,EAAE,IAAI,CAAC,YAAY;AAC3C,YAAY,MAAM;AAClB,SAAS,CAAC,CAAC;AACX,KAAK;AACL;AACA,IAAI,MAAM,IAAI,GAAG;AACjB;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AAClD,YAAY,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACzD,SAAS;AACT;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE;AACnD,YAAY,MAAM,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;AACxE,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC5C,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACpC;AACA,QAAQ,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;AACvD;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;AACpC,SAAS,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE;AACrC;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7E,SAAS;AACT,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;AAChC,QAAQ,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,IAAI,CAAC;AAC3C;AACA,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE;AACxC,YAAY,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,0BAA0B,CAAC,CAAC;AAClF,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACnC,KAAK;AACL;AACA,IAAI,OAAO,GAAG;AACd,QAAQ,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAC3D,QAAQA,eAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACpC,KAAK;AACL;AACA,IAAI,aAAa,iBAAiB,CAAC,aAAa,GAAG,KAAK,EAAE;AAC1D;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE;AACrC,YAAY,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;AAClF,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE;AACtD,YAAY,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;AACnG,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE;AAClD,YAAY,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;AAC/F,SAAS;AACT;AACA,QAAQ,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;AACxE,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC,EAAE;AACnE,YAAY,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AAC/C,SAAS;AACT;AACA,QAAQ,IAAI,aAAa,EAAE;AAC3B,YAAY,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;AACrE,gBAAgB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE;AAClE,aAAa,CAAC,CAAC;AACf,YAAY,IAAI,MAAM,CAAC,IAAI,EAAE;AAC7B,gBAAgB,MAAM,CAAC,IAAI,EAAE,CAAC;AAC9B,aAAa,MAAM;AACnB,gBAAgB,MAAM,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACvE,aAAa;AACb,SAAS;AACT,KAAK;AACL;AACA,IAAI,IAAI,KAAK,GAAG;AAChB,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC;AAC3B,KAAK;AACL;AACA,IAAI,IAAI,mBAAmB,GAAG;AAC9B,QAAQ,OAAO,IAAI,CAAC,oBAAoB,CAAC;AACzC,KAAK;AACL;AACA,IAAI,IAAI,mBAAmB,CAAC,mBAAmB,EAAE;AACjD,QAAQ,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;AACxD,QAAQ,IAAI,CAAC,WAAW,EAAE,CAAC;AAC3B,KAAK;AACL;AACA,IAAI,0BAA0B,GAAG,MAAM;AACvC,QAAQ,IAAI,CAAC,cAAc,EAAE,CAAC;AAC9B,QAAQ,IAAI,CAAC,WAAW,EAAE,CAAC;AAC3B,KAAK;AACL;AACA,IAAI,cAAc,GAAG,MAAM;AAC3B;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AAChC,YAAY,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;AACtD,SAAS;AACT;AACA,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;AACzD,QAAQ,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;AAC3D;AACA,QAAQ,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC;AAC/D,QAAQ,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC;AACjE;AACA,QAAQ,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;AACxD,QAAQ,MAAM,YAAY,GAAG,cAAc,GAAG,eAAe,CAAC;AAC9D;AACA,QAAQ,IAAI,YAAY,GAAG,YAAY,EAAE;AACzC;AACA,YAAY,MAAM,QAAQ,GAAG,YAAY,GAAG,eAAe,CAAC;AAC5D,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;AAC5D,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;AACzF;AACA,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;AACpE,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;AACtD;AACA,SAAS,MAAM;AACf;AACA,YAAY,MAAM,SAAS,GAAG,CAAC,IAAI,YAAY,GAAG,cAAc,CAAC,CAAC;AAClE,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;AAC9D,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;AAC1F;AACA,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG,cAAc,GAAG,IAAI,CAAC;AAClE,YAAY,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC;AACvD,SAAS;AACT;AACA,KAAK;AACL;AACA,IAAI,WAAW,GAAG,MAAM;AACxB;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,gBAAgB;AACnC,YAAY,IAAI,CAAC,cAAc;AAC/B,YAAY,IAAI,CAAC,YAAY;AAC7B,YAAY,IAAI,CAAC,oBAAoB;AACrC,SAAS,CAAC;AACV;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,IAAI,YAAY,GAAG;AACvB;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AAClD,YAAY,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;AAC3E,YAAY,OAAO,IAAI,CAAC;AACxB,SAAS;AACT;AACA,QAAQ,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC;AAC7E,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AACxD,QAAQ,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAChD;AACA;AACA,QAAQ,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;AAC7B,QAAQ,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;AAC/B;AACA,QAAQ,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAClE,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACvC,KAAK;AACL;;AC5QA;AAYA;AACA,MAAM,aAAa,SAAS,YAAY,CAAC;AACzC;AACA,IAAI,OAAO,eAAe,GAAG;AAC7B,QAAQ,aAAa,CAAC,OAAO;AAC7B,QAAQ,aAAa,CAAC,WAAW;AACjC,QAAQ,aAAa,CAAC,OAAO;AAC7B,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA,IAAI,aAAa;AACjB;AACA;AACA;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA,IAAI,IAAI;AACR;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA,IAAI,aAAa;AACjB;AACA;AACA;AACA;AACA,IAAI,aAAa;AACjB;AACA;AACA;AACA;AACA,IAAI,UAAU,GAAG,KAAK;AACtB;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE;AACxB,QAAQ,KAAK,EAAE,CAAC;AAChB;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;AAC9B,QAAQ,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC;AACjD;AACA,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,iBAAiB,EAAE,CAAC;AACnD;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AACxD,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAClD;AACA,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;AAC3D,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;AACvD,KAAK;AACL;AACA,IAAI,KAAK,CAAC,YAAY,GAAG,GAAG,EAAE,OAAO,GAAG,aAAa,CAAC,eAAe,EAAE;AACvE,QAAQ,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;AAC1C;AACA,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE;AAC7B,YAAY,OAAO;AACnB,SAAS;AACT,QAAQ,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;AAC/B;AACA,QAAQ,MAAM,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;AAChC,QAAQ,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;AAC5D,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC;AACA,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;AACzB,KAAK;AACL;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;AAChC,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;AACrB,KAAK;AACL;AACA,IAAI,SAAS,GAAG;AAChB;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;AAC7E,YAAY,OAAO;AACnB,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;AACpD,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC;AACtD,QAAQ,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;AACzC,QAAQ,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;AAC3C,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;AACtE;AACA,QAAQ,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;AACpF,KAAK;AACL;AACA,IAAI,KAAK,GAAG;AACZ,QAAQ,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAC1C,KAAK;AACL;AACA,IAAI,QAAQ,GAAG;AACf;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AAC3C,YAAY,OAAO;AACnB,SAAS;AACT;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AACjF,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AAC5E;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC1D;AACA,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACjH,SAAS;AACT;AACA,QAAQ,MAAM,YAAY,GAAG,IAAI,YAAY;AAC7C,YAAY,IAAI,eAAe;AAC/B,gBAAgB,IAAI,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC;AACnF,aAAa;AACb,SAAS,CAAC;AACV;AACA,QAAQ,IAAI;AACZ,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;AAC1E,YAAY,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAChD,SAAS,CAAC,OAAO,CAAC,EAAE;AACpB;AACA,SAAS;AACT,KAAK;AACL;;;;"}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/camera"
12
12
  },
13
13
  "name": "@wemap/camera",
14
- "version": "6.0.0",
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": "a377d6fd98b48ce0e083ece1c695642947c456cc"
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
- _isStarted = false;
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._isStarted) {
75
+ if (this._state !== Camera.State.STOPPED) {
67
76
  throw new Error('Camera is already started');
68
77
  }
69
78
 
70
- this._isStarted = true;
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.emit('start', {
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 (!this._isStarted) {
99
- throw new Error('Camera is not started yet');
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.emit('stop');
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
- this._isStarted = false;
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 isStarted() {
156
- return this._isStarted;
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;
@@ -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
+
@@ -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('start', () => this._tryStart());
78
- this._camera.on('stop', () => this._stop());
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 || !this._camera.isStarted) {
103
+ if (!this._isStarted || this._camera.state !== Camera.State.STARTED) {
104
104
  return;
105
105
  }
106
106