@capgo/camera-preview 7.3.12 → 7.4.0-beta.10
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/CapgoCameraPreview.podspec +16 -13
- package/README.md +467 -73
- package/android/.gradle/8.14.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.2/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.14.2/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/8.14.2/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +11 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/src/main/AndroidManifest.xml +5 -3
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +472 -541
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +1648 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +82 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraDevice.java +54 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraLens.java +70 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraSessionConfiguration.java +79 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/LensInfo.java +34 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/ZoomFactors.java +34 -0
- package/dist/docs.json +934 -154
- package/dist/esm/definitions.d.ts +445 -83
- package/dist/esm/definitions.js +10 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +73 -3
- package/dist/esm/web.js +492 -68
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +498 -68
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +498 -68
- package/dist/plugin.js.map +1 -1
- package/ios/{Plugin → Sources/CapgoCameraPreview}/CameraController.swift +601 -59
- package/ios/Sources/CapgoCameraPreview/GridOverlayView.swift +65 -0
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +1369 -0
- package/ios/Tests/CameraPreviewPluginTests/CameraPreviewPluginTests.swift +15 -0
- package/package.json +1 -1
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +0 -1279
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +0 -29
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +0 -39
- package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +0 -461
- package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +0 -24
- package/ios/Plugin/Info.plist +0 -24
- package/ios/Plugin/Plugin.h +0 -10
- package/ios/Plugin/Plugin.m +0 -18
- package/ios/Plugin/Plugin.swift +0 -511
- package/ios/Plugin.xcodeproj/project.pbxproj +0 -593
- package/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/Plugin.xcworkspace/contents.xcworkspacedata +0 -10
- package/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/PluginTests/Info.plist +0 -22
- package/ios/PluginTests/PluginTests.swift +0 -83
- package/ios/Podfile +0 -13
- package/ios/Podfile.lock +0 -23
package/dist/plugin.js
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
var capacitorCapacitorCameraView = (function (exports, core) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
exports.DeviceType = void 0;
|
|
5
|
+
(function (DeviceType) {
|
|
6
|
+
DeviceType["ULTRA_WIDE"] = "ultraWide";
|
|
7
|
+
DeviceType["WIDE_ANGLE"] = "wideAngle";
|
|
8
|
+
DeviceType["TELEPHOTO"] = "telephoto";
|
|
9
|
+
DeviceType["TRUE_DEPTH"] = "trueDepth";
|
|
10
|
+
DeviceType["DUAL"] = "dual";
|
|
11
|
+
DeviceType["DUAL_WIDE"] = "dualWide";
|
|
12
|
+
DeviceType["TRIPLE"] = "triple";
|
|
13
|
+
})(exports.DeviceType || (exports.DeviceType = {}));
|
|
14
|
+
|
|
4
15
|
const CameraPreview = core.registerPlugin("CameraPreview", {
|
|
5
16
|
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CameraPreviewWeb()),
|
|
6
17
|
});
|
|
7
18
|
|
|
19
|
+
const DEFAULT_VIDEO_ID = "capgo_video";
|
|
8
20
|
class CameraPreviewWeb extends core.WebPlugin {
|
|
9
21
|
constructor() {
|
|
10
22
|
super();
|
|
@@ -13,80 +25,101 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
13
25
|
* used in capture
|
|
14
26
|
*/
|
|
15
27
|
this.isBackCamera = false;
|
|
28
|
+
this.currentDeviceId = null;
|
|
29
|
+
this.videoElement = null;
|
|
30
|
+
this.isStarted = false;
|
|
16
31
|
}
|
|
17
32
|
async getSupportedPictureSizes() {
|
|
18
33
|
throw new Error("getSupportedPictureSizes not supported under the web platform");
|
|
19
34
|
}
|
|
20
35
|
async start(options) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
stream.getTracks().forEach((track) => track.stop());
|
|
30
|
-
})
|
|
31
|
-
.catch((error) => {
|
|
32
|
-
Promise.reject(error);
|
|
33
|
-
});
|
|
34
|
-
const video = document.getElementById("video");
|
|
36
|
+
if (options.aspectRatio && (options.width || options.height)) {
|
|
37
|
+
throw new Error("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start.");
|
|
38
|
+
}
|
|
39
|
+
if (this.isStarted) {
|
|
40
|
+
throw new Error("camera already started");
|
|
41
|
+
}
|
|
42
|
+
this.isBackCamera = true;
|
|
43
|
+
this.isStarted = false;
|
|
35
44
|
const parent = document.getElementById((options === null || options === void 0 ? void 0 : options.parent) || "");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
45
|
+
const gridMode = (options === null || options === void 0 ? void 0 : options.gridMode) || "none";
|
|
46
|
+
if (options.position) {
|
|
47
|
+
this.isBackCamera = options.position === "rear";
|
|
48
|
+
}
|
|
49
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
50
|
+
if (video) {
|
|
51
|
+
video.remove();
|
|
52
|
+
}
|
|
53
|
+
const container = options.parent ? document.getElementById(options.parent) : document.body;
|
|
54
|
+
if (!container) {
|
|
55
|
+
throw new Error("container not found");
|
|
56
|
+
}
|
|
57
|
+
this.videoElement = document.createElement("video");
|
|
58
|
+
this.videoElement.id = DEFAULT_VIDEO_ID;
|
|
59
|
+
this.videoElement.className = options.className || "";
|
|
60
|
+
this.videoElement.playsInline = true;
|
|
61
|
+
this.videoElement.muted = true;
|
|
62
|
+
this.videoElement.autoplay = true;
|
|
63
|
+
container.appendChild(this.videoElement);
|
|
64
|
+
if (options.toBack) {
|
|
65
|
+
this.videoElement.style.zIndex = "-1";
|
|
66
|
+
}
|
|
67
|
+
if (options.width) {
|
|
68
|
+
this.videoElement.width = options.width;
|
|
69
|
+
}
|
|
70
|
+
if (options.height) {
|
|
71
|
+
this.videoElement.height = options.height;
|
|
72
|
+
}
|
|
73
|
+
if (options.x) {
|
|
74
|
+
this.videoElement.style.left = `${options.x}px`;
|
|
75
|
+
}
|
|
76
|
+
// Create and add grid overlay if needed
|
|
77
|
+
if (gridMode !== "none") {
|
|
78
|
+
const gridOverlay = this.createGridOverlay(gridMode);
|
|
79
|
+
gridOverlay.id = "camera-grid-overlay";
|
|
80
|
+
parent === null || parent === void 0 ? void 0 : parent.appendChild(gridOverlay);
|
|
81
|
+
}
|
|
82
|
+
if (options.y) {
|
|
83
|
+
this.videoElement.style.top = `${options.y}px`;
|
|
84
|
+
}
|
|
85
|
+
if (options.aspectRatio) {
|
|
86
|
+
const [widthRatio, heightRatio] = options.aspectRatio.split(':').map(Number);
|
|
87
|
+
const ratio = widthRatio / heightRatio;
|
|
88
|
+
if (options.width) {
|
|
89
|
+
this.videoElement.height = options.width / ratio;
|
|
90
|
+
}
|
|
91
|
+
else if (options.height) {
|
|
92
|
+
this.videoElement.width = options.height * ratio;
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
else {
|
|
88
|
-
|
|
96
|
+
this.videoElement.style.objectFit = 'cover';
|
|
97
|
+
}
|
|
98
|
+
const constraints = {
|
|
99
|
+
video: {
|
|
100
|
+
width: { ideal: this.videoElement.width || 640 },
|
|
101
|
+
height: { ideal: this.videoElement.height || window.innerHeight },
|
|
102
|
+
facingMode: this.isBackCamera ? "environment" : "user",
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
106
|
+
if (!stream) {
|
|
107
|
+
throw new Error("could not acquire stream");
|
|
108
|
+
}
|
|
109
|
+
if (!this.videoElement) {
|
|
110
|
+
throw new Error("video element not found");
|
|
111
|
+
}
|
|
112
|
+
this.videoElement.srcObject = stream;
|
|
113
|
+
if (!this.isBackCamera) {
|
|
114
|
+
this.videoElement.style.transform = "scaleX(-1)";
|
|
89
115
|
}
|
|
116
|
+
this.isStarted = true;
|
|
117
|
+
return {
|
|
118
|
+
width: this.videoElement.width,
|
|
119
|
+
height: this.videoElement.height,
|
|
120
|
+
x: this.videoElement.getBoundingClientRect().x,
|
|
121
|
+
y: this.videoElement.getBoundingClientRect().y,
|
|
122
|
+
};
|
|
90
123
|
}
|
|
91
124
|
stopStream(stream) {
|
|
92
125
|
if (stream) {
|
|
@@ -96,16 +129,20 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
96
129
|
}
|
|
97
130
|
}
|
|
98
131
|
async stop() {
|
|
99
|
-
const video = document.getElementById(
|
|
132
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
100
133
|
if (video) {
|
|
101
134
|
video.pause();
|
|
102
135
|
this.stopStream(video.srcObject);
|
|
103
136
|
video.remove();
|
|
137
|
+
this.isStarted = false;
|
|
104
138
|
}
|
|
139
|
+
// Remove grid overlay if it exists
|
|
140
|
+
const gridOverlay = document.getElementById("camera-grid-overlay");
|
|
141
|
+
gridOverlay === null || gridOverlay === void 0 ? void 0 : gridOverlay.remove();
|
|
105
142
|
}
|
|
106
143
|
async capture(options) {
|
|
107
144
|
return new Promise((resolve, reject) => {
|
|
108
|
-
const video = document.getElementById(
|
|
145
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
109
146
|
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
110
147
|
reject(new Error("camera is not running"));
|
|
111
148
|
return;
|
|
@@ -123,6 +160,8 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
123
160
|
context === null || context === void 0 ? void 0 : context.scale(-1, 1);
|
|
124
161
|
}
|
|
125
162
|
context === null || context === void 0 ? void 0 : context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
|
|
163
|
+
if (options.saveToGallery) ;
|
|
164
|
+
if (options.withExifLocation) ;
|
|
126
165
|
if ((options.format || "jpeg") === "jpeg") {
|
|
127
166
|
base64EncodedImage = canvas
|
|
128
167
|
.toDataURL("image/jpeg", (options.quality || 85) / 100.0)
|
|
@@ -136,6 +175,7 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
136
175
|
}
|
|
137
176
|
resolve({
|
|
138
177
|
value: base64EncodedImage,
|
|
178
|
+
exif: {},
|
|
139
179
|
});
|
|
140
180
|
});
|
|
141
181
|
}
|
|
@@ -159,13 +199,403 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
159
199
|
throw new Error(`setFlashMode not supported under the web platform${_options}`);
|
|
160
200
|
}
|
|
161
201
|
async flip() {
|
|
162
|
-
|
|
202
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
203
|
+
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
204
|
+
throw new Error("camera is not running");
|
|
205
|
+
}
|
|
206
|
+
// Stop current stream
|
|
207
|
+
this.stopStream(video.srcObject);
|
|
208
|
+
// Toggle camera position
|
|
209
|
+
this.isBackCamera = !this.isBackCamera;
|
|
210
|
+
// Get new constraints
|
|
211
|
+
const constraints = {
|
|
212
|
+
video: {
|
|
213
|
+
facingMode: this.isBackCamera ? "environment" : "user",
|
|
214
|
+
width: { ideal: video.videoWidth || 640 },
|
|
215
|
+
height: { ideal: video.videoHeight || 480 },
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
try {
|
|
219
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
220
|
+
video.srcObject = stream;
|
|
221
|
+
// Update current device ID from the new stream
|
|
222
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
223
|
+
if (videoTrack) {
|
|
224
|
+
this.currentDeviceId = videoTrack.getSettings().deviceId || null;
|
|
225
|
+
}
|
|
226
|
+
// Update video transform based on camera
|
|
227
|
+
if (this.isBackCamera) {
|
|
228
|
+
video.style.transform = "none";
|
|
229
|
+
video.style.webkitTransform = "none";
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
video.style.transform = "scaleX(-1)";
|
|
233
|
+
video.style.webkitTransform = "scaleX(-1)";
|
|
234
|
+
}
|
|
235
|
+
await video.play();
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
throw new Error(`Failed to flip camera: ${error}`);
|
|
239
|
+
}
|
|
163
240
|
}
|
|
164
241
|
async setOpacity(_options) {
|
|
165
|
-
const video = document.getElementById(
|
|
242
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
166
243
|
if (!!video && !!_options.opacity)
|
|
167
244
|
video.style.setProperty("opacity", _options.opacity.toString());
|
|
168
245
|
}
|
|
246
|
+
async isRunning() {
|
|
247
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
248
|
+
return { isRunning: !!video && !!video.srcObject };
|
|
249
|
+
}
|
|
250
|
+
async getAvailableDevices() {
|
|
251
|
+
var _a;
|
|
252
|
+
if (!((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.enumerateDevices)) {
|
|
253
|
+
throw new Error("getAvailableDevices not supported under the web platform");
|
|
254
|
+
}
|
|
255
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
256
|
+
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
|
257
|
+
// Group devices by position (front/back)
|
|
258
|
+
const frontDevices = [];
|
|
259
|
+
const backDevices = [];
|
|
260
|
+
videoDevices.forEach((device, index) => {
|
|
261
|
+
const label = device.label || `Camera ${index + 1}`;
|
|
262
|
+
const labelLower = label.toLowerCase();
|
|
263
|
+
// Determine device type based on label
|
|
264
|
+
let deviceType = exports.DeviceType.WIDE_ANGLE;
|
|
265
|
+
let baseZoomRatio = 1.0;
|
|
266
|
+
if (labelLower.includes('ultra') || labelLower.includes('0.5')) {
|
|
267
|
+
deviceType = exports.DeviceType.ULTRA_WIDE;
|
|
268
|
+
baseZoomRatio = 0.5;
|
|
269
|
+
}
|
|
270
|
+
else if (labelLower.includes('telephoto') || labelLower.includes('tele') || labelLower.includes('2x') || labelLower.includes('3x')) {
|
|
271
|
+
deviceType = exports.DeviceType.TELEPHOTO;
|
|
272
|
+
baseZoomRatio = 2.0;
|
|
273
|
+
}
|
|
274
|
+
else if (labelLower.includes('depth') || labelLower.includes('truedepth')) {
|
|
275
|
+
deviceType = exports.DeviceType.TRUE_DEPTH;
|
|
276
|
+
baseZoomRatio = 1.0;
|
|
277
|
+
}
|
|
278
|
+
const lensInfo = {
|
|
279
|
+
deviceId: device.deviceId,
|
|
280
|
+
label,
|
|
281
|
+
deviceType,
|
|
282
|
+
focalLength: 4.25,
|
|
283
|
+
baseZoomRatio,
|
|
284
|
+
minZoom: 1.0,
|
|
285
|
+
maxZoom: 1.0
|
|
286
|
+
};
|
|
287
|
+
// Determine position and add to appropriate array
|
|
288
|
+
if (labelLower.includes('back') || labelLower.includes('rear')) {
|
|
289
|
+
backDevices.push(lensInfo);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
frontDevices.push(lensInfo);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
const result = [];
|
|
296
|
+
if (frontDevices.length > 0) {
|
|
297
|
+
result.push({
|
|
298
|
+
deviceId: frontDevices[0].deviceId,
|
|
299
|
+
label: "Front Camera",
|
|
300
|
+
position: "front",
|
|
301
|
+
lenses: frontDevices,
|
|
302
|
+
isLogical: false,
|
|
303
|
+
minZoom: Math.min(...frontDevices.map(d => d.minZoom)),
|
|
304
|
+
maxZoom: Math.max(...frontDevices.map(d => d.maxZoom))
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (backDevices.length > 0) {
|
|
308
|
+
result.push({
|
|
309
|
+
deviceId: backDevices[0].deviceId,
|
|
310
|
+
label: "Back Camera",
|
|
311
|
+
position: "rear",
|
|
312
|
+
lenses: backDevices,
|
|
313
|
+
isLogical: false,
|
|
314
|
+
minZoom: Math.min(...backDevices.map(d => d.minZoom)),
|
|
315
|
+
maxZoom: Math.max(...backDevices.map(d => d.maxZoom))
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return { devices: result };
|
|
319
|
+
}
|
|
320
|
+
async getZoom() {
|
|
321
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
322
|
+
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
323
|
+
throw new Error("camera is not running");
|
|
324
|
+
}
|
|
325
|
+
const stream = video.srcObject;
|
|
326
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
327
|
+
if (!videoTrack) {
|
|
328
|
+
throw new Error("no video track found");
|
|
329
|
+
}
|
|
330
|
+
const capabilities = videoTrack.getCapabilities();
|
|
331
|
+
const settings = videoTrack.getSettings();
|
|
332
|
+
if (!capabilities.zoom) {
|
|
333
|
+
throw new Error("zoom not supported by this device");
|
|
334
|
+
}
|
|
335
|
+
// Get current device info to determine lens type
|
|
336
|
+
let deviceType = exports.DeviceType.WIDE_ANGLE;
|
|
337
|
+
let baseZoomRatio = 1.0;
|
|
338
|
+
if (this.currentDeviceId) {
|
|
339
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
340
|
+
const device = devices.find(d => d.deviceId === this.currentDeviceId);
|
|
341
|
+
if (device) {
|
|
342
|
+
const labelLower = device.label.toLowerCase();
|
|
343
|
+
if (labelLower.includes('ultra') || labelLower.includes('0.5')) {
|
|
344
|
+
deviceType = exports.DeviceType.ULTRA_WIDE;
|
|
345
|
+
baseZoomRatio = 0.5;
|
|
346
|
+
}
|
|
347
|
+
else if (labelLower.includes('telephoto') || labelLower.includes('tele') || labelLower.includes('2x') || labelLower.includes('3x')) {
|
|
348
|
+
deviceType = exports.DeviceType.TELEPHOTO;
|
|
349
|
+
baseZoomRatio = 2.0;
|
|
350
|
+
}
|
|
351
|
+
else if (labelLower.includes('depth') || labelLower.includes('truedepth')) {
|
|
352
|
+
deviceType = exports.DeviceType.TRUE_DEPTH;
|
|
353
|
+
baseZoomRatio = 1.0;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const currentZoom = settings.zoom || 1;
|
|
358
|
+
const lensInfo = {
|
|
359
|
+
focalLength: 4.25,
|
|
360
|
+
deviceType,
|
|
361
|
+
baseZoomRatio,
|
|
362
|
+
digitalZoom: currentZoom / baseZoomRatio
|
|
363
|
+
};
|
|
364
|
+
return {
|
|
365
|
+
min: capabilities.zoom.min || 1,
|
|
366
|
+
max: capabilities.zoom.max || 1,
|
|
367
|
+
current: currentZoom,
|
|
368
|
+
lens: lensInfo,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
async setZoom(options) {
|
|
372
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
373
|
+
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
374
|
+
throw new Error("camera is not running");
|
|
375
|
+
}
|
|
376
|
+
const stream = video.srcObject;
|
|
377
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
378
|
+
if (!videoTrack) {
|
|
379
|
+
throw new Error("no video track found");
|
|
380
|
+
}
|
|
381
|
+
const capabilities = videoTrack.getCapabilities();
|
|
382
|
+
if (!capabilities.zoom) {
|
|
383
|
+
throw new Error("zoom not supported by this device");
|
|
384
|
+
}
|
|
385
|
+
const zoomLevel = Math.max(capabilities.zoom.min || 1, Math.min(capabilities.zoom.max || 1, options.level));
|
|
386
|
+
try {
|
|
387
|
+
await videoTrack.applyConstraints({
|
|
388
|
+
advanced: [{ zoom: zoomLevel }]
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
throw new Error(`Failed to set zoom: ${error}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async getFlashMode() {
|
|
396
|
+
throw new Error("getFlashMode not supported under the web platform");
|
|
397
|
+
}
|
|
398
|
+
async getDeviceId() {
|
|
399
|
+
return { deviceId: this.currentDeviceId || "" };
|
|
400
|
+
}
|
|
401
|
+
async setDeviceId(options) {
|
|
402
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
403
|
+
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
404
|
+
throw new Error("camera is not running");
|
|
405
|
+
}
|
|
406
|
+
// Stop current stream
|
|
407
|
+
this.stopStream(video.srcObject);
|
|
408
|
+
// Update current device ID
|
|
409
|
+
this.currentDeviceId = options.deviceId;
|
|
410
|
+
// Get new constraints with specific device ID
|
|
411
|
+
const constraints = {
|
|
412
|
+
video: {
|
|
413
|
+
deviceId: { exact: options.deviceId },
|
|
414
|
+
width: { ideal: video.videoWidth || 640 },
|
|
415
|
+
height: { ideal: video.videoHeight || 480 },
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
try {
|
|
419
|
+
// Try to determine camera position from device
|
|
420
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
421
|
+
const device = devices.find(d => d.deviceId === options.deviceId);
|
|
422
|
+
this.isBackCamera = (device === null || device === void 0 ? void 0 : device.label.toLowerCase().includes('back')) || (device === null || device === void 0 ? void 0 : device.label.toLowerCase().includes('rear')) || false;
|
|
423
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
424
|
+
video.srcObject = stream;
|
|
425
|
+
// Update video transform based on camera
|
|
426
|
+
if (this.isBackCamera) {
|
|
427
|
+
video.style.transform = "none";
|
|
428
|
+
video.style.webkitTransform = "none";
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
video.style.transform = "scaleX(-1)";
|
|
432
|
+
video.style.webkitTransform = "scaleX(-1)";
|
|
433
|
+
}
|
|
434
|
+
await video.play();
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
throw new Error(`Failed to swap to device ${options.deviceId}: ${error}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async getAspectRatio() {
|
|
441
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
442
|
+
if (!video) {
|
|
443
|
+
throw new Error("camera is not running");
|
|
444
|
+
}
|
|
445
|
+
const width = video.offsetWidth;
|
|
446
|
+
const height = video.offsetHeight;
|
|
447
|
+
if (width && height) {
|
|
448
|
+
const ratio = width / height;
|
|
449
|
+
// Check for portrait camera ratios: 4:3 -> 3:4, 16:9 -> 9:16
|
|
450
|
+
if (Math.abs(ratio - (3 / 4)) < 0.01) {
|
|
451
|
+
return { aspectRatio: '4:3' };
|
|
452
|
+
}
|
|
453
|
+
if (Math.abs(ratio - (9 / 16)) < 0.01) {
|
|
454
|
+
return { aspectRatio: '16:9' };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Default to 4:3 if no specific aspect ratio is matched
|
|
458
|
+
return { aspectRatio: '4:3' };
|
|
459
|
+
}
|
|
460
|
+
async setAspectRatio(options) {
|
|
461
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
462
|
+
if (!video) {
|
|
463
|
+
throw new Error("camera is not running");
|
|
464
|
+
}
|
|
465
|
+
if (options.aspectRatio) {
|
|
466
|
+
const [widthRatio, heightRatio] = options.aspectRatio.split(':').map(Number);
|
|
467
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
468
|
+
const ratio = heightRatio / widthRatio;
|
|
469
|
+
// Get current position and size
|
|
470
|
+
const rect = video.getBoundingClientRect();
|
|
471
|
+
const currentWidth = rect.width;
|
|
472
|
+
const currentHeight = rect.height;
|
|
473
|
+
const currentRatio = currentWidth / currentHeight;
|
|
474
|
+
let newWidth;
|
|
475
|
+
let newHeight;
|
|
476
|
+
if (currentRatio > ratio) {
|
|
477
|
+
// Width is larger, fit by height and center horizontally
|
|
478
|
+
newWidth = currentHeight * ratio;
|
|
479
|
+
newHeight = currentHeight;
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
// Height is larger, fit by width and center vertically
|
|
483
|
+
newWidth = currentWidth;
|
|
484
|
+
newHeight = currentWidth / ratio;
|
|
485
|
+
}
|
|
486
|
+
// Calculate position
|
|
487
|
+
let x, y;
|
|
488
|
+
if (options.x !== undefined && options.y !== undefined) {
|
|
489
|
+
// Use provided coordinates, ensuring they stay within screen boundaries
|
|
490
|
+
x = Math.max(0, Math.min(options.x, window.innerWidth - newWidth));
|
|
491
|
+
y = Math.max(0, Math.min(options.y, window.innerHeight - newHeight));
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
// Auto-center the view
|
|
495
|
+
x = (window.innerWidth - newWidth) / 2;
|
|
496
|
+
y = (window.innerHeight - newHeight) / 2;
|
|
497
|
+
}
|
|
498
|
+
video.style.width = `${newWidth}px`;
|
|
499
|
+
video.style.height = `${newHeight}px`;
|
|
500
|
+
video.style.left = `${x}px`;
|
|
501
|
+
video.style.top = `${y}px`;
|
|
502
|
+
video.style.position = 'absolute';
|
|
503
|
+
return {
|
|
504
|
+
width: Math.round(newWidth),
|
|
505
|
+
height: Math.round(newHeight),
|
|
506
|
+
x: Math.round(x),
|
|
507
|
+
y: Math.round(y)
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
video.style.objectFit = 'cover';
|
|
512
|
+
const rect = video.getBoundingClientRect();
|
|
513
|
+
return {
|
|
514
|
+
width: Math.round(rect.width),
|
|
515
|
+
height: Math.round(rect.height),
|
|
516
|
+
x: Math.round(rect.left),
|
|
517
|
+
y: Math.round(rect.top)
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
createGridOverlay(gridMode) {
|
|
522
|
+
const overlay = document.createElement("div");
|
|
523
|
+
overlay.style.position = "absolute";
|
|
524
|
+
overlay.style.top = "0";
|
|
525
|
+
overlay.style.left = "0";
|
|
526
|
+
overlay.style.width = "100%";
|
|
527
|
+
overlay.style.height = "100%";
|
|
528
|
+
overlay.style.pointerEvents = "none";
|
|
529
|
+
overlay.style.zIndex = "10";
|
|
530
|
+
const divisions = gridMode === "3x3" ? 3 : 4;
|
|
531
|
+
// Create SVG for grid lines
|
|
532
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
533
|
+
svg.style.width = "100%";
|
|
534
|
+
svg.style.height = "100%";
|
|
535
|
+
svg.style.position = "absolute";
|
|
536
|
+
svg.style.top = "0";
|
|
537
|
+
svg.style.left = "0";
|
|
538
|
+
// Create grid lines
|
|
539
|
+
for (let i = 1; i < divisions; i++) {
|
|
540
|
+
// Vertical lines
|
|
541
|
+
const verticalLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
542
|
+
verticalLine.setAttribute("x1", `${(i / divisions) * 100}%`);
|
|
543
|
+
verticalLine.setAttribute("y1", "0%");
|
|
544
|
+
verticalLine.setAttribute("x2", `${(i / divisions) * 100}%`);
|
|
545
|
+
verticalLine.setAttribute("y2", "100%");
|
|
546
|
+
verticalLine.setAttribute("stroke", "rgba(255, 255, 255, 0.5)");
|
|
547
|
+
verticalLine.setAttribute("stroke-width", "1");
|
|
548
|
+
svg.appendChild(verticalLine);
|
|
549
|
+
// Horizontal lines
|
|
550
|
+
const horizontalLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
551
|
+
horizontalLine.setAttribute("x1", "0%");
|
|
552
|
+
horizontalLine.setAttribute("y1", `${(i / divisions) * 100}%`);
|
|
553
|
+
horizontalLine.setAttribute("x2", "100%");
|
|
554
|
+
horizontalLine.setAttribute("y2", `${(i / divisions) * 100}%`);
|
|
555
|
+
horizontalLine.setAttribute("stroke", "rgba(255, 255, 255, 0.5)");
|
|
556
|
+
horizontalLine.setAttribute("stroke-width", "1");
|
|
557
|
+
svg.appendChild(horizontalLine);
|
|
558
|
+
}
|
|
559
|
+
overlay.appendChild(svg);
|
|
560
|
+
return overlay;
|
|
561
|
+
}
|
|
562
|
+
async setGridMode(options) {
|
|
563
|
+
// Web implementation of grid mode would need to be implemented
|
|
564
|
+
// For now, just resolve as a no-op
|
|
565
|
+
console.warn(`Grid mode '${options.gridMode}' is not yet implemented for web platform`);
|
|
566
|
+
}
|
|
567
|
+
async getGridMode() {
|
|
568
|
+
// Web implementation - default to none
|
|
569
|
+
return { gridMode: 'none' };
|
|
570
|
+
}
|
|
571
|
+
async getPreviewSize() {
|
|
572
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
573
|
+
if (!video) {
|
|
574
|
+
throw new Error("camera is not running");
|
|
575
|
+
}
|
|
576
|
+
return {
|
|
577
|
+
x: video.offsetLeft,
|
|
578
|
+
y: video.offsetTop,
|
|
579
|
+
width: video.width,
|
|
580
|
+
height: video.height
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
async setPreviewSize(options) {
|
|
584
|
+
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
585
|
+
if (!video) {
|
|
586
|
+
throw new Error("camera is not running");
|
|
587
|
+
}
|
|
588
|
+
video.style.left = `${options.x}px`;
|
|
589
|
+
video.style.top = `${options.y}px`;
|
|
590
|
+
video.width = options.width;
|
|
591
|
+
video.height = options.height;
|
|
592
|
+
return {
|
|
593
|
+
width: options.width,
|
|
594
|
+
height: options.height,
|
|
595
|
+
x: options.x,
|
|
596
|
+
y: options.y
|
|
597
|
+
};
|
|
598
|
+
}
|
|
169
599
|
}
|
|
170
600
|
|
|
171
601
|
var web = /*#__PURE__*/Object.freeze({
|