@wemap/camera 3.2.5 → 3.2.6
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/debug/dist/index.html +2 -1
- package/debug/dist/qr-code-scanner.html +115 -0
- package/index.js +6 -1
- package/package.json +4 -3
- package/src/Camera.js +20 -5
- package/src/QrCodeScanner.js +149 -0
- package/src/SharedCameras.js +34 -0
package/debug/dist/index.html
CHANGED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Camera</title>
|
|
8
|
+
|
|
9
|
+
<script src="/js/camera-lib.js"></script>
|
|
10
|
+
|
|
11
|
+
<style type="text/css">
|
|
12
|
+
html,
|
|
13
|
+
body {
|
|
14
|
+
height: 100%;
|
|
15
|
+
margin: 0px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#camera-container {
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#controls {
|
|
24
|
+
position: absolute;
|
|
25
|
+
bottom: 0;
|
|
26
|
+
z-index: 2;
|
|
27
|
+
margin: 5px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#controls>div {
|
|
31
|
+
background: #ffffffaa;
|
|
32
|
+
padding-left: 10px;
|
|
33
|
+
padding-right: 10px;
|
|
34
|
+
min-width: 100px;
|
|
35
|
+
display: inline-block;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#scan-result {
|
|
39
|
+
position: absolute;
|
|
40
|
+
border: 1px solid black;
|
|
41
|
+
background: white;
|
|
42
|
+
top: 0;
|
|
43
|
+
width: 150px;
|
|
44
|
+
left: 50%;
|
|
45
|
+
transform: translate(-50%, 0%);
|
|
46
|
+
z-index: 2;
|
|
47
|
+
text-align: center;
|
|
48
|
+
line-height: 30px;
|
|
49
|
+
vertical-align: middle;
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
52
|
+
</head>
|
|
53
|
+
|
|
54
|
+
<body>
|
|
55
|
+
|
|
56
|
+
<div id="camera-container"></div>
|
|
57
|
+
<div id="scan-result">Waiting</div>
|
|
58
|
+
<div id="controls">
|
|
59
|
+
<div id="camera-handler">
|
|
60
|
+
<div class="title">Camera</div>
|
|
61
|
+
<button id="start-camera">Start</button>
|
|
62
|
+
<button id="stop-camera" disabled>Stop</button>
|
|
63
|
+
</div>
|
|
64
|
+
<div id="qrcode-handler">
|
|
65
|
+
<div class="title">Scanner</div>
|
|
66
|
+
<button id="start-scanner">Start</button>
|
|
67
|
+
<button id="stop-scanner" disabled>Stop</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
<script>
|
|
73
|
+
/* global Camera, QrCodeScanner */
|
|
74
|
+
|
|
75
|
+
const cameraContainer = document.getElementById('camera-container');
|
|
76
|
+
const scanResultContainer = document.getElementById('scan-result');
|
|
77
|
+
const startCameraButton = document.getElementById('start-camera');
|
|
78
|
+
const stopCameraButton = document.getElementById('stop-camera');
|
|
79
|
+
const startScannerButton = document.getElementById('start-scanner');
|
|
80
|
+
const stopScannerButton = document.getElementById('stop-scanner');
|
|
81
|
+
|
|
82
|
+
const camera = new Camera(cameraContainer);
|
|
83
|
+
const qrCodeScanner = new QrCodeScanner(camera);
|
|
84
|
+
qrCodeScanner.on('scan', str => (scanResultContainer.innerHTML = str));
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
startCameraButton.addEventListener('click', () => {
|
|
88
|
+
camera.start();
|
|
89
|
+
startCameraButton.disabled = true;
|
|
90
|
+
stopCameraButton.disabled = false;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
stopCameraButton.addEventListener('click', () => {
|
|
94
|
+
camera.stop();
|
|
95
|
+
startCameraButton.disabled = false;
|
|
96
|
+
stopCameraButton.disabled = true;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
startScannerButton.addEventListener('click', () => {
|
|
101
|
+
qrCodeScanner.start();
|
|
102
|
+
startScannerButton.disabled = true;
|
|
103
|
+
stopScannerButton.disabled = false;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
stopScannerButton.addEventListener('click', () => {
|
|
107
|
+
qrCodeScanner.stop();
|
|
108
|
+
startScannerButton.disabled = false;
|
|
109
|
+
stopScannerButton.disabled = true;
|
|
110
|
+
scanResultContainer.innerHTML = 'Waiting';
|
|
111
|
+
});
|
|
112
|
+
</script>
|
|
113
|
+
</body>
|
|
114
|
+
|
|
115
|
+
</html>
|
package/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { BarcodeFormat } from '@zxing/library';
|
|
1
2
|
import Camera from './src/Camera.js';
|
|
3
|
+
import QrCodeScanner from './src/QrCodeScanner.js';
|
|
4
|
+
import SharedCameras from './src/SharedCameras.js';
|
|
2
5
|
|
|
3
|
-
export {
|
|
6
|
+
export {
|
|
7
|
+
BarcodeFormat, Camera, QrCodeScanner, SharedCameras
|
|
8
|
+
};
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/camera"
|
|
12
12
|
},
|
|
13
13
|
"name": "@wemap/camera",
|
|
14
|
-
"version": "3.2.
|
|
14
|
+
"version": "3.2.6",
|
|
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/navigation-logger": "^3.2.
|
|
26
|
+
"@wemap/navigation-logger": "^3.2.6",
|
|
27
|
+
"@zxing/library": "^0.17.1",
|
|
27
28
|
"events": "^3.1.0"
|
|
28
29
|
},
|
|
29
30
|
"type": "module",
|
|
30
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "0b4bcb307a86aa10d123603698961463baf931fd"
|
|
31
32
|
}
|
package/src/Camera.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
|
|
3
3
|
import CameraLogger from './CameraLogger.js';
|
|
4
|
+
import SharedCameras from './SharedCameras.js';
|
|
4
5
|
|
|
5
6
|
const GENERIC_HARDWARE_VERTICAL_FOV = 60;
|
|
6
7
|
|
|
@@ -31,16 +32,22 @@ class Camera extends EventEmitter {
|
|
|
31
32
|
|
|
32
33
|
fov = null;
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
_isStarted = false;
|
|
35
36
|
|
|
36
37
|
_hardwareVerticalFov = GENERIC_HARDWARE_VERTICAL_FOV;
|
|
37
38
|
_resizeOnWindowChange;
|
|
38
39
|
|
|
39
40
|
_cameraLogger;
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @param {Node} container
|
|
44
|
+
* @param {boolean} resizeOnWindowChange
|
|
45
|
+
*/
|
|
41
46
|
constructor(container, resizeOnWindowChange = false) {
|
|
42
47
|
super();
|
|
43
48
|
|
|
49
|
+
SharedCameras._add(this, container);
|
|
50
|
+
|
|
44
51
|
this.videoContainer = container;
|
|
45
52
|
this._resizeOnWindowChange = resizeOnWindowChange;
|
|
46
53
|
|
|
@@ -58,11 +65,11 @@ class Camera extends EventEmitter {
|
|
|
58
65
|
|
|
59
66
|
async start() {
|
|
60
67
|
|
|
61
|
-
if (this.
|
|
68
|
+
if (this._isStarted) {
|
|
62
69
|
throw new Error('Camera is already started');
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
this.
|
|
72
|
+
this._isStarted = true;
|
|
66
73
|
|
|
67
74
|
await Camera.checkAvailability();
|
|
68
75
|
|
|
@@ -83,14 +90,18 @@ class Camera extends EventEmitter {
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
this._cameraLogger.attachStream(this.videoStream);
|
|
93
|
+
|
|
94
|
+
this.emit('start');
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
async stop() {
|
|
89
98
|
|
|
90
|
-
if (!this.
|
|
99
|
+
if (!this._isStarted) {
|
|
91
100
|
throw new Error('Camera is not started yet');
|
|
92
101
|
}
|
|
93
102
|
|
|
103
|
+
this.emit('stop');
|
|
104
|
+
|
|
94
105
|
this._cameraLogger.detachStream();
|
|
95
106
|
|
|
96
107
|
if (this.videoStream && this.videoStream.stop) {
|
|
@@ -106,7 +117,7 @@ class Camera extends EventEmitter {
|
|
|
106
117
|
if (this._resizeOnWindowChange) {
|
|
107
118
|
window.removeEventListener('resize', this.notifyContainerSizeChanged);
|
|
108
119
|
}
|
|
109
|
-
this.
|
|
120
|
+
this._isStarted = false;
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
static async checkAvailability(testUserMedia = false) {
|
|
@@ -138,6 +149,10 @@ class Camera extends EventEmitter {
|
|
|
138
149
|
}
|
|
139
150
|
}
|
|
140
151
|
|
|
152
|
+
get isStarted() {
|
|
153
|
+
return this._isStarted;
|
|
154
|
+
}
|
|
155
|
+
|
|
141
156
|
set hardwareVerticalFov(hardwareVerticalFov) {
|
|
142
157
|
this._hardwareVerticalFov = hardwareVerticalFov;
|
|
143
158
|
this._computeFov();
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import EventEmitter from 'events';
|
|
3
|
+
import {
|
|
4
|
+
MultiFormatReader,
|
|
5
|
+
BarcodeFormat,
|
|
6
|
+
DecodeHintType,
|
|
7
|
+
RGBLuminanceSource,
|
|
8
|
+
BinaryBitmap,
|
|
9
|
+
HybridBinarizer
|
|
10
|
+
} from '@zxing/library';
|
|
11
|
+
|
|
12
|
+
import Camera from './Camera.js';
|
|
13
|
+
|
|
14
|
+
class QrCodeScanner extends EventEmitter {
|
|
15
|
+
|
|
16
|
+
static DEFAULT_FORMATS = [
|
|
17
|
+
BarcodeFormat.QR_CODE,
|
|
18
|
+
BarcodeFormat.DATA_MATRIX,
|
|
19
|
+
BarcodeFormat.CODABAR
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @type {Camera}
|
|
24
|
+
*/
|
|
25
|
+
_camera;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @type {HTMLVideoElement}
|
|
29
|
+
*/
|
|
30
|
+
_videoElement;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @type {HTMLCanvasElement}
|
|
34
|
+
*/
|
|
35
|
+
_canvas;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @type {CanvasRenderingContext2D}
|
|
39
|
+
*/
|
|
40
|
+
_ctx;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @type {MultiFormatReader}
|
|
44
|
+
*/
|
|
45
|
+
_codeReader;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @type {number}
|
|
49
|
+
*/
|
|
50
|
+
_intervalTime;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @type {number}
|
|
54
|
+
*/
|
|
55
|
+
_intervalTick;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @type {boolean}
|
|
59
|
+
*/
|
|
60
|
+
_isStarted = false;
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {Camera} camera
|
|
65
|
+
*/
|
|
66
|
+
constructor(camera) {
|
|
67
|
+
super();
|
|
68
|
+
|
|
69
|
+
this._camera = camera;
|
|
70
|
+
this._videoElement = camera.videoElement;
|
|
71
|
+
|
|
72
|
+
this._codeReader = new MultiFormatReader();
|
|
73
|
+
|
|
74
|
+
this._canvas = document.createElement('canvas');
|
|
75
|
+
this._ctx = this._canvas.getContext('2d');
|
|
76
|
+
|
|
77
|
+
this._camera.on('start', () => this._tryStart());
|
|
78
|
+
this._camera.on('stop', () => this._stop());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
start(intervalTime = 500, formats = QrCodeScanner.DEFAULT_FORMATS) {
|
|
82
|
+
this._intervalTime = intervalTime;
|
|
83
|
+
|
|
84
|
+
if (this._isStarted) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this._isStarted = true;
|
|
88
|
+
|
|
89
|
+
const hints = new Map();
|
|
90
|
+
hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
|
|
91
|
+
this._codeReader.setHints(hints);
|
|
92
|
+
|
|
93
|
+
this._tryStart();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
stop() {
|
|
97
|
+
this._isStarted = false;
|
|
98
|
+
this._stop();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
_tryStart() {
|
|
102
|
+
|
|
103
|
+
if (!this._isStarted || !this._camera.isStarted) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this._width = this._videoElement.videoWidth;
|
|
108
|
+
this._height = this._videoElement.videoHeight;
|
|
109
|
+
this._canvas.width = this._width;
|
|
110
|
+
this._canvas.height = this._height;
|
|
111
|
+
this._luminances = new Uint8Array(this._width * this._height);
|
|
112
|
+
|
|
113
|
+
this._intervalTick = setInterval(() => this._onFrame(), this._intervalTime);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_stop() {
|
|
117
|
+
clearInterval(this._intervalTick);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
_onFrame() {
|
|
121
|
+
|
|
122
|
+
if (!this._width || !this._height) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this._ctx.drawImage(this._videoElement, 0, 0, this._width, this._height);
|
|
127
|
+
const img = this._ctx.getImageData(0, 0, this._width, this._height);
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < this._luminances.length; i++) {
|
|
130
|
+
// eslint-disable-next-line no-bitwise
|
|
131
|
+
this._luminances[i] = ((img.data[i * 4] + img.data[i * 4 + 1] * 2 + img.data[i * 4 + 2]) / 4) & 0xFF;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const binaryBitmap = new BinaryBitmap(
|
|
135
|
+
new HybridBinarizer(
|
|
136
|
+
new RGBLuminanceSource(this._luminances, this._width, this._height)
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const result = this._codeReader.decodeWithState(binaryBitmap);
|
|
142
|
+
this.emit('scan', result.getText());
|
|
143
|
+
} catch (e) {
|
|
144
|
+
// do nothing
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export default QrCodeScanner;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Camera from './Camera.js';
|
|
2
|
+
|
|
3
|
+
class SharedCameras {
|
|
4
|
+
|
|
5
|
+
static _list = [];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {Camera} camera
|
|
9
|
+
* @param {Node}
|
|
10
|
+
*/
|
|
11
|
+
static _add(camera, container) {
|
|
12
|
+
this._list.push({
|
|
13
|
+
camera,
|
|
14
|
+
container
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static get list() {
|
|
19
|
+
return this._list;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static getCameraByContainer(container) {
|
|
23
|
+
for (const {
|
|
24
|
+
camera, container: _container
|
|
25
|
+
} of this._list) {
|
|
26
|
+
if (container === _container) {
|
|
27
|
+
return camera;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default SharedCameras;
|