@jaak.ai/stamps 2.0.0-beta.4 → 2.0.0-beta.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/README.md +660 -510
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +241 -41
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/my-component/my-component.css +54 -24
- package/dist/collection/components/my-component/my-component.js +91 -5
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +158 -21
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/DetectionService.js +34 -16
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/components/jaak-stamps.js +244 -41
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps-webcomponent.js +1 -1
- package/dist/esm/jaak-stamps.entry.js +241 -41
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-65990bdd.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-65990bdd.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +6 -0
- package/dist/types/components.d.ts +18 -2
- package/dist/types/services/CameraService.d.ts +1 -0
- package/package.json +2 -2
- package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js.map +0 -1
|
@@ -6,6 +6,7 @@ export class CameraService {
|
|
|
6
6
|
deviceType = 'desktop';
|
|
7
7
|
preferredCameraFacing = null;
|
|
8
8
|
preferredCamera = 'auto';
|
|
9
|
+
isManuallySelected = false;
|
|
9
10
|
constructor(logger, eventBus, preferredCamera = 'auto') {
|
|
10
11
|
this.logger = logger;
|
|
11
12
|
this.eventBus = eventBus;
|
|
@@ -52,6 +53,11 @@ export class CameraService {
|
|
|
52
53
|
}))
|
|
53
54
|
});
|
|
54
55
|
this.setInitialCameraPreference();
|
|
56
|
+
this.logger.state('PREFERENCIA_INICIAL_APLICADA', {
|
|
57
|
+
selectedCameraId: this.selectedCameraId,
|
|
58
|
+
preferredCameraFacing: this.preferredCameraFacing,
|
|
59
|
+
preferredCamera: this.preferredCamera
|
|
60
|
+
});
|
|
55
61
|
this.eventBus.emit('camera-changed', this.selectedCameraId);
|
|
56
62
|
return this.availableCameras;
|
|
57
63
|
}
|
|
@@ -77,6 +83,7 @@ export class CameraService {
|
|
|
77
83
|
}
|
|
78
84
|
this.selectedCameraId = cameraId;
|
|
79
85
|
this.updatePreferredFacing(camera);
|
|
86
|
+
this.isManuallySelected = true; // Mark as manually selected
|
|
80
87
|
this.savePreference();
|
|
81
88
|
this.eventBus.emit('camera-changed', cameraId);
|
|
82
89
|
}
|
|
@@ -84,12 +91,31 @@ export class CameraService {
|
|
|
84
91
|
return this.preferredCameraFacing;
|
|
85
92
|
}
|
|
86
93
|
async setupCamera(constraints) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
try {
|
|
95
|
+
const finalConstraints = constraints || await this.getMaxResolution();
|
|
96
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
97
|
+
video: finalConstraints,
|
|
98
|
+
audio: false
|
|
99
|
+
});
|
|
100
|
+
return stream;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.logger.error('Error en setupCamera, intentando con restricciones básicas:', error);
|
|
104
|
+
// Fallback to basic constraints if getMaxResolution fails
|
|
105
|
+
const basicConstraints = {
|
|
106
|
+
width: { ideal: 1280 },
|
|
107
|
+
height: { ideal: 720 }
|
|
108
|
+
};
|
|
109
|
+
// Only add facingMode if not on desktop to avoid OverconstrainedError
|
|
110
|
+
if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {
|
|
111
|
+
basicConstraints.facingMode = this.preferredCameraFacing;
|
|
112
|
+
}
|
|
113
|
+
this.logger.state('USANDO_RESTRICCIONES_BASICAS', { constraints: basicConstraints });
|
|
114
|
+
return await navigator.mediaDevices.getUserMedia({
|
|
115
|
+
video: basicConstraints,
|
|
116
|
+
audio: false
|
|
117
|
+
});
|
|
118
|
+
}
|
|
93
119
|
}
|
|
94
120
|
async switchCamera(cameraId) {
|
|
95
121
|
const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
|
|
@@ -101,7 +127,8 @@ export class CameraService {
|
|
|
101
127
|
await this.setSelectedCamera(cameraId);
|
|
102
128
|
this.logger.state('CAMARA_CAMBIADA', {
|
|
103
129
|
label: selectedCamera.label,
|
|
104
|
-
deviceId: selectedCamera.deviceId
|
|
130
|
+
deviceId: selectedCamera.deviceId,
|
|
131
|
+
isManuallySelected: this.isManuallySelected
|
|
105
132
|
});
|
|
106
133
|
}
|
|
107
134
|
async flipToNextCamera() {
|
|
@@ -183,6 +210,13 @@ export class CameraService {
|
|
|
183
210
|
setInitialCameraPreference() {
|
|
184
211
|
if (this.availableCameras.length === 0)
|
|
185
212
|
return;
|
|
213
|
+
// Clear any existing localStorage preferences to ensure fresh start
|
|
214
|
+
localStorage.removeItem('jaak-stamps-camera-preference');
|
|
215
|
+
this.logger.state('APLICANDO_PREFERENCIA_INICIAL', {
|
|
216
|
+
preferredCamera: this.preferredCamera,
|
|
217
|
+
availableCamerasCount: this.availableCameras.length
|
|
218
|
+
});
|
|
219
|
+
this.isManuallySelected = false; // Reset manual selection flag
|
|
186
220
|
if (this.preferredCamera === 'front') {
|
|
187
221
|
this.selectFrontCamera();
|
|
188
222
|
}
|
|
@@ -195,23 +229,56 @@ export class CameraService {
|
|
|
195
229
|
}
|
|
196
230
|
selectFrontCamera() {
|
|
197
231
|
this.preferredCameraFacing = 'user';
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
232
|
+
this.logger.state('BUSCANDO_CAMARA_FRONTAL', {
|
|
233
|
+
availableCameras: this.availableCameras.map(cam => ({
|
|
234
|
+
id: cam.deviceId,
|
|
235
|
+
label: cam.label
|
|
236
|
+
}))
|
|
237
|
+
});
|
|
238
|
+
const frontCamera = this.availableCameras.find(camera => {
|
|
239
|
+
const label = camera.label.toLowerCase();
|
|
240
|
+
return label.includes('front') ||
|
|
241
|
+
label.includes('user') ||
|
|
242
|
+
label.includes('selfie') ||
|
|
243
|
+
label.includes('frontal') ||
|
|
244
|
+
(!label.includes('back') && !label.includes('rear') && !label.includes('environment'));
|
|
245
|
+
});
|
|
246
|
+
// If not found, use the first camera (usually front on mobile)
|
|
202
247
|
this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;
|
|
203
248
|
this.logger.state('CAMARA_FRONTAL_SELECCIONADA', {
|
|
249
|
+
found: !!frontCamera,
|
|
204
250
|
label: frontCamera?.label || this.availableCameras[0].label,
|
|
205
251
|
deviceId: this.selectedCameraId
|
|
206
252
|
});
|
|
207
253
|
}
|
|
208
254
|
selectBackCamera() {
|
|
209
255
|
this.preferredCameraFacing = 'environment';
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
256
|
+
this.logger.state('BUSCANDO_CAMARA_TRASERA', {
|
|
257
|
+
availableCameras: this.availableCameras.map(cam => ({
|
|
258
|
+
id: cam.deviceId,
|
|
259
|
+
label: cam.label
|
|
260
|
+
}))
|
|
261
|
+
});
|
|
262
|
+
// Try to find rear camera with multiple detection methods
|
|
263
|
+
let backCamera = this.availableCameras.find(camera => {
|
|
264
|
+
const label = camera.label.toLowerCase();
|
|
265
|
+
return label.includes('back') ||
|
|
266
|
+
label.includes('rear') ||
|
|
267
|
+
label.includes('environment') ||
|
|
268
|
+
label.includes('trasera') ||
|
|
269
|
+
label.includes('posterior');
|
|
270
|
+
});
|
|
271
|
+
// If not found by label, try to use the last camera (usually rear on mobile)
|
|
272
|
+
if (!backCamera && this.availableCameras.length > 1) {
|
|
273
|
+
backCamera = this.availableCameras[this.availableCameras.length - 1];
|
|
274
|
+
this.logger.state('USANDO_ULTIMA_CAMARA_COMO_TRASERA', {
|
|
275
|
+
label: backCamera.label,
|
|
276
|
+
deviceId: backCamera.deviceId
|
|
277
|
+
});
|
|
278
|
+
}
|
|
213
279
|
this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;
|
|
214
280
|
this.logger.state('CAMARA_TRASERA_SELECCIONADA', {
|
|
281
|
+
found: !!backCamera,
|
|
215
282
|
label: backCamera?.label || this.availableCameras[0].label,
|
|
216
283
|
deviceId: this.selectedCameraId
|
|
217
284
|
});
|
|
@@ -222,8 +289,10 @@ export class CameraService {
|
|
|
222
289
|
this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });
|
|
223
290
|
}
|
|
224
291
|
else {
|
|
225
|
-
|
|
292
|
+
// For desktop, prefer front camera (usually built-in webcam)
|
|
293
|
+
this.selectFrontCamera();
|
|
226
294
|
this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', {
|
|
295
|
+
type: 'front',
|
|
227
296
|
label: this.availableCameras[0].label,
|
|
228
297
|
deviceId: this.selectedCameraId
|
|
229
298
|
});
|
|
@@ -237,15 +306,60 @@ export class CameraService {
|
|
|
237
306
|
}
|
|
238
307
|
async getMaxResolution() {
|
|
239
308
|
try {
|
|
309
|
+
// Ensure device type is detected before determining constraints
|
|
310
|
+
if (!this.deviceType || this.deviceType === 'desktop') {
|
|
311
|
+
await this.detectDeviceType();
|
|
312
|
+
}
|
|
240
313
|
const videoConstraints = {};
|
|
241
|
-
|
|
314
|
+
this.logger.state('CONFIGURANDO_CONSTRAINS_CAMARA', {
|
|
315
|
+
selectedCameraId: this.selectedCameraId,
|
|
316
|
+
preferredCameraFacing: this.preferredCameraFacing,
|
|
317
|
+
preferredCamera: this.preferredCamera,
|
|
318
|
+
deviceType: this.deviceType,
|
|
319
|
+
isManuallySelected: this.isManuallySelected
|
|
320
|
+
});
|
|
321
|
+
if (this.isManuallySelected && this.selectedCameraId) {
|
|
322
|
+
// When manually selected, use deviceId for exact camera selection
|
|
242
323
|
videoConstraints.deviceId = { exact: this.selectedCameraId };
|
|
324
|
+
this.logger.state('USANDO_CAMARA_MANUAL', {
|
|
325
|
+
deviceId: this.selectedCameraId
|
|
326
|
+
});
|
|
243
327
|
}
|
|
244
328
|
else if (this.preferredCameraFacing) {
|
|
245
|
-
|
|
329
|
+
// Use facingMode for initial preference-based selection
|
|
330
|
+
// Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
|
|
331
|
+
const facingConstraint = this.deviceType === 'desktop'
|
|
332
|
+
? { ideal: this.preferredCameraFacing }
|
|
333
|
+
: { exact: this.preferredCameraFacing };
|
|
334
|
+
videoConstraints.facingMode = facingConstraint;
|
|
335
|
+
this.logger.state('USANDO_FACING_CONSTRAINT', {
|
|
336
|
+
facingMode: this.preferredCameraFacing,
|
|
337
|
+
constraintType: this.deviceType === 'desktop' ? 'ideal' : 'exact'
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
else if (this.selectedCameraId) {
|
|
341
|
+
videoConstraints.deviceId = { exact: this.selectedCameraId };
|
|
342
|
+
this.logger.state('USANDO_CAMARA_SELECCIONADA', {
|
|
343
|
+
deviceId: this.selectedCameraId
|
|
344
|
+
});
|
|
246
345
|
}
|
|
247
346
|
else {
|
|
248
|
-
|
|
347
|
+
// Use preferredCamera setting to determine default facing mode
|
|
348
|
+
if (this.preferredCamera === 'front') {
|
|
349
|
+
videoConstraints.facingMode = "user";
|
|
350
|
+
}
|
|
351
|
+
else if (this.preferredCamera === 'back') {
|
|
352
|
+
videoConstraints.facingMode = "environment";
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
// Auto mode: use environment for mobile/tablet, user for desktop
|
|
356
|
+
videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
|
|
357
|
+
}
|
|
358
|
+
this.logger.state('USANDO_PREFERENCIA_CONFIGURADA', {
|
|
359
|
+
facingMode: videoConstraints.facingMode,
|
|
360
|
+
preferredCamera: this.preferredCamera,
|
|
361
|
+
deviceType: this.deviceType
|
|
362
|
+
});
|
|
249
363
|
}
|
|
250
364
|
const tempStream = await navigator.mediaDevices.getUserMedia({
|
|
251
365
|
video: videoConstraints
|
|
@@ -277,6 +391,10 @@ export class CameraService {
|
|
|
277
391
|
}
|
|
278
392
|
catch (err) {
|
|
279
393
|
this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
|
|
394
|
+
// Ensure device type is detected before determining constraints
|
|
395
|
+
if (!this.deviceType || this.deviceType === 'desktop') {
|
|
396
|
+
await this.detectDeviceType();
|
|
397
|
+
}
|
|
280
398
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
281
399
|
const fallbackConstraints = {
|
|
282
400
|
width: { ideal: isTablet ? 1280 : 1920 },
|
|
@@ -284,14 +402,33 @@ export class CameraService {
|
|
|
284
402
|
};
|
|
285
403
|
// Apply basic focus settings even for fallback
|
|
286
404
|
this.applyBasicFocusSettings(fallbackConstraints);
|
|
287
|
-
if (this.selectedCameraId) {
|
|
405
|
+
if (this.isManuallySelected && this.selectedCameraId) {
|
|
406
|
+
// When manually selected, use deviceId for exact camera selection
|
|
288
407
|
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
289
408
|
}
|
|
290
409
|
else if (this.preferredCameraFacing) {
|
|
291
|
-
|
|
410
|
+
// Use facingMode for initial preference-based selection
|
|
411
|
+
// Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
|
|
412
|
+
const facingConstraint = this.deviceType === 'desktop'
|
|
413
|
+
? { ideal: this.preferredCameraFacing }
|
|
414
|
+
: { exact: this.preferredCameraFacing };
|
|
415
|
+
fallbackConstraints.facingMode = facingConstraint;
|
|
416
|
+
}
|
|
417
|
+
else if (this.selectedCameraId) {
|
|
418
|
+
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
292
419
|
}
|
|
293
420
|
else {
|
|
294
|
-
|
|
421
|
+
// Use preferredCamera setting to determine default facing mode
|
|
422
|
+
if (this.preferredCamera === 'front') {
|
|
423
|
+
fallbackConstraints.facingMode = "user";
|
|
424
|
+
}
|
|
425
|
+
else if (this.preferredCamera === 'back') {
|
|
426
|
+
fallbackConstraints.facingMode = "environment";
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
// Auto mode: use environment for mobile/tablet, user for desktop
|
|
430
|
+
fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
|
|
431
|
+
}
|
|
295
432
|
}
|
|
296
433
|
return fallbackConstraints;
|
|
297
434
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"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","sourcesContent":["import { ICameraService, CameraInfo, CameraPreference } from './interfaces/ICameraService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n\n constructor(\n private logger: ILogger,\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n this.logger.state('DISPOSITIVO_DETECTADO', {\n deviceType: this.deviceType,\n userAgent: navigator.userAgent,\n screenDimensions: { width: window.innerWidth, height: window.innerHeight }\n });\n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n const permissionStatus = await this.checkCameraPermission();\n \n if (permissionStatus === 'denied') {\n this.logger.error('Permiso de cámara denegado por el usuario');\n return [];\n }\n \n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n \n const devices = await navigator.mediaDevices.enumerateDevices();\n this.availableCameras = devices.filter(device => device.kind === 'videoinput');\n \n this.logger.state('CAMARAS_DETECTADAS', {\n count: this.availableCameras.length,\n cameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label || 'Unknown Camera'\n }))\n });\n \n this.setInitialCameraPreference();\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n \n return this.availableCameras;\n } catch (error) {\n this.logger.error('Error al enumerar cámaras disponibles:', error);\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.savePreference();\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n const finalConstraints = constraints || await this.getMaxResolution();\n \n const stream = await navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n return stream;\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');\n await this.enumerateDevices();\n return;\n }\n \n await this.setSelectedCamera(cameraId);\n this.logger.state('CAMARA_CAMBIADA', { \n label: selectedCamera.label, \n deviceId: selectedCamera.deviceId \n });\n }\n\n async flipToNextCamera(): Promise<void> {\n if (!this.isMultipleCamerasAvailable()) return;\n \n const currentIndex = this.availableCameras.findIndex(\n camera => camera.deviceId === this.selectedCameraId\n );\n \n const nextIndex = (currentIndex + 1) % this.availableCameras.length;\n const nextCamera = this.availableCameras[nextIndex];\n \n await this.switchCamera(nextCamera.deviceId);\n }\n\n savePreference(): void {\n try {\n const preference: CameraPreference = {\n cameraId: this.selectedCameraId!,\n facing: this.preferredCameraFacing,\n timestamp: Date.now()\n };\n \n localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));\n this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);\n } catch (error) {\n this.logger.warn('Error al guardar preferencia de cámara:', error);\n }\n }\n\n loadPreference(): void {\n try {\n const saved = localStorage.getItem('jaak-stamps-camera-preference');\n if (saved) {\n const preference: CameraPreference = JSON.parse(saved);\n \n const isStillAvailable = this.availableCameras.some(\n camera => camera.deviceId === preference.cameraId\n );\n \n if (isStillAvailable) {\n this.selectedCameraId = preference.cameraId;\n this.preferredCameraFacing = preference.facing;\n this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);\n }\n }\n } catch (error) {\n this.logger.warn('Error al cargar preferencia de cámara:', error);\n }\n }\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n } {\n return {\n availableCameras: this.availableCameras.map(camera => ({\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId\n })),\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n this.logger.warn('No se pudo verificar permisos de cámara:', error);\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private setInitialCameraPreference(): void {\n if (this.availableCameras.length === 0) return;\n \n if (this.preferredCamera === 'front') {\n this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n this.selectBackCamera();\n } else {\n this.selectAutoCamera();\n }\n }\n\n private selectFrontCamera(): void {\n this.preferredCameraFacing = 'user';\n \n const frontCamera = this.availableCameras.find(camera => \n camera.label.toLowerCase().includes('front') || \n camera.label.toLowerCase().includes('user') ||\n camera.label.toLowerCase().includes('selfie') ||\n !camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear')\n );\n \n this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { \n label: frontCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectBackCamera(): void {\n this.preferredCameraFacing = 'environment';\n \n const backCamera = this.availableCameras.find(camera => \n camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment')\n );\n \n this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_TRASERA_SELECCIONADA', { \n label: backCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectAutoCamera(): void {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n this.selectBackCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });\n } else {\n this.selectedCameraId = this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { \n label: this.availableCameras[0].label, \n deviceId: this.selectedCameraId \n });\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n const videoConstraints: MediaTrackConstraints = {};\n \n if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n videoConstraints.facingMode = this.preferredCameraFacing;\n } else {\n videoConstraints.facingMode = \"environment\";\n }\n \n const tempStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints\n });\n \n const videoTrack = tempStream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n // Enhanced focus and image quality settings\n this.applyAdvancedCameraSettings(constraints, capabilities);\n \n if (capabilities.width && capabilities.height) {\n const maxWidth = Math.min(capabilities.width.max, 1920);\n const maxHeight = Math.min(capabilities.height.max, 1080);\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n constraints.width = { ideal: Math.min(maxWidth, 1280) };\n constraints.height = { ideal: Math.min(maxHeight, 720) };\n } else {\n constraints.width = { ideal: maxWidth };\n constraints.height = { ideal: maxHeight };\n }\n }\n \n this.logger.state('CONFIGURACION_CAMARA_OPTIMIZADA', {\n constraints,\n capabilities: this.getCapabilitiesSummary(capabilities)\n });\n \n return constraints;\n } catch (err) {\n this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: isTablet ? 1280 : 1920 },\n height: { ideal: isTablet ? 720 : 1080 }\n };\n \n // Apply basic focus settings even for fallback\n this.applyBasicFocusSettings(fallbackConstraints);\n \n if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n fallbackConstraints.facingMode = this.preferredCameraFacing;\n } else {\n fallbackConstraints.facingMode = \"environment\";\n }\n \n return fallbackConstraints;\n }\n }\n\n private applyAdvancedCameraSettings(constraints: MediaTrackConstraints, capabilities: MediaTrackCapabilities): void {\n // Apply standard camera settings that are widely supported\n \n // Frame rate optimization\n if (capabilities.frameRate) {\n constraints.frameRate = {\n ideal: 30,\n min: 15,\n max: 60\n };\n }\n\n // Width and height constraints for optimal resolution\n if (capabilities.width && capabilities.height) {\n constraints.width = {\n ideal: Math.min(1920, capabilities.width.max || 1920),\n min: 640\n };\n constraints.height = {\n ideal: Math.min(1080, capabilities.height.max || 1080),\n min: 480\n };\n }\n\n // Apply enhanced constraints through advanced array for better browser compatibility\n const advancedConstraints: MediaTrackConstraintSet[] = [];\n \n // Try to set optimal settings through advanced constraints\n const advanced: any = {};\n \n // Focus mode - use 'any' type to bypass TypeScript limitations\n if ((capabilities as any).focusMode) {\n if ((capabilities as any).focusMode.includes('continuous')) {\n advanced.focusMode = 'continuous';\n } else if ((capabilities as any).focusMode.includes('single-shot')) {\n advanced.focusMode = 'single-shot';\n }\n }\n\n // Focus distance for close objects\n if ((capabilities as any).focusDistance) {\n advanced.focusDistance = {\n ideal: 0.4, // 40cm - optimal for document capture\n min: 0.2,\n max: 1.0\n };\n }\n\n // Zoom control\n if ((capabilities as any).zoom) {\n advanced.zoom = {\n ideal: 1.0,\n min: (capabilities as any).zoom.min,\n max: Math.min((capabilities as any).zoom.max, 3.0)\n };\n }\n\n // Add advanced constraints if any were set\n if (Object.keys(advanced).length > 0) {\n advancedConstraints.push(advanced);\n }\n\n if (advancedConstraints.length > 0) {\n constraints.advanced = advancedConstraints;\n }\n }\n\n private applyBasicFocusSettings(constraints: MediaTrackConstraints): void {\n // Apply basic focus settings when capabilities are not available\n // Use advanced constraints for non-standard properties\n const advanced: any = {\n focusMode: 'continuous',\n exposureMode: 'continuous',\n whiteBalanceMode: 'continuous'\n };\n \n if (!constraints.advanced) {\n constraints.advanced = [];\n }\n constraints.advanced.push(advanced);\n \n constraints.frameRate = { ideal: 30 };\n }\n\n private getCapabilitiesSummary(capabilities: MediaTrackCapabilities): any {\n return {\n hasAutoFocus: !!(capabilities as any).focusMode,\n hasFocusDistance: !!(capabilities as any).focusDistance,\n hasExposureControl: !!(capabilities as any).exposureMode,\n hasWhiteBalance: !!(capabilities as any).whiteBalanceMode,\n hasZoom: !!(capabilities as any).zoom,\n hasTorch: (capabilities as any).torch !== undefined,\n hasImageControls: !!((capabilities as any).brightness || (capabilities as any).contrast || (capabilities as any).saturation || (capabilities as any).sharpness),\n resolutionRange: capabilities.width && capabilities.height ? \n `${capabilities.width.min}x${capabilities.height.min} - ${capabilities.width.max}x${capabilities.height.max}` : 'unknown'\n };\n }\n\n // New method to enable torch/flash for better illumination\n async setTorchEnabled(enabled: boolean, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para controlar el flash');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if ((capabilities as any).torch === undefined) {\n this.logger.warn('El dispositivo no soporta control de flash');\n return false;\n }\n\n await videoTrack.applyConstraints({\n advanced: [{ torch: enabled } as any]\n });\n\n this.logger.state('FLASH_CONTROLADO', { enabled });\n return true;\n } catch (error) {\n this.logger.error('Error al controlar el flash:', error);\n return false;\n }\n }\n\n // Method to manually trigger focus on a specific point\n async focusAtPoint(x: number, y: number, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para enfocar');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if (!(capabilities as any).focusMode || !(capabilities as any).focusMode.includes('single-shot')) {\n this.logger.warn('El dispositivo no soporta enfoque manual');\n return false;\n }\n\n // Trigger single-shot focus\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'single-shot' } as any]\n });\n\n // Return to continuous focus after a short delay\n setTimeout(async () => {\n try {\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'continuous' } as any]\n });\n } catch (error) {\n this.logger.warn('Error al volver a enfoque continuo:', error);\n }\n }, 1000);\n\n this.logger.state('ENFOQUE_MANUAL_ACTIVADO', { x, y });\n return true;\n } catch (error) {\n this.logger.error('Error al enfocar manualmente:', error);\n return false;\n }\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,aAAa;IASd;IACA;IATF,gBAAgB,GAAsB,EAAE,CAAC;IACzC,gBAAgB,GAAkB,IAAI,CAAC;IACvC,UAAU,GAAoC,SAAS,CAAC;IACxD,qBAAqB,GAAkC,IAAI,CAAC;IAC5D,eAAe,GAA8B,MAAM,CAAC;IACpD,kBAAkB,GAAY,KAAK,CAAC;IAE5C,YACU,MAAe,EACf,QAAmB,EAC3B,kBAA6C,MAAM;QAF3C,WAAM,GAAN,MAAM,CAAS;QACf,aAAQ,GAAR,QAAQ,CAAW;QAG3B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;QACtC,MAAM,QAAQ,GAAG,0DAA0D,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5F,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC;QAE7E,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;QAC7B,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;YACzC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,SAAS,CAAC,SAAS;YAC9B,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;SAC3E,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC;YACH,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAE5D,IAAI,gBAAgB,KAAK,QAAQ,EAAE,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;gBAC/D,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,IAAI,gBAAgB,KAAK,QAAQ,EAAE,CAAC;gBAClC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9E,UAAU,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;YAChE,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;YAE/E,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE;gBACtC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM;gBACnC,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACzC,EAAE,EAAE,GAAG,CAAC,QAAQ;oBAChB,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,gBAAgB;iBACrC,CAAC,CAAC;aACJ,CAAC,CAAC;YAEH,IAAI,CAAC,0BAA0B,EAAE,CAAC;YAElC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE;gBAChD,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;gBACvC,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;gBACjD,eAAe,EAAE,IAAI,CAAC,eAAe;aACtC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,CAAC,gBAAgB,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;YACnE,IAAI,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC;YACxC,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,OAAO,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAED,0BAA0B;QACxB,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,YAAY,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,4BAA4B;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,WAAmC;QACnD,IAAI,CAAC;YACH,MAAM,gBAAgB,GAAG,WAAW,IAAI,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAEtE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBACvD,KAAK,EAAE,gBAAgB;gBACvB,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6DAA6D,EAAE,KAAK,CAAC,CAAC;YAExF,0DAA0D;YAC1D,MAAM,gBAAgB,GAA0B;gBAC9C,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;gBACtB,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;aACvB,CAAC;YAEF,sEAAsE;YACtE,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAChE,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAAC;YAC3D,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAErF,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBAC/C,KAAK,EAAE,gBAAgB;gBACvB,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAgB;QACjC,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QACpF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;YACrF,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;YACnC,KAAK,EAAE,cAAc,CAAC,KAAK;YAC3B,QAAQ,EAAE,cAAc,CAAC,QAAQ;YACjC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE;YAAE,OAAO;QAE/C,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAClD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,gBAAgB,CACpD,CAAC;QAEF,MAAM,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAEpD,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,cAAc;QACZ,IAAI,CAAC;YACH,MAAM,UAAU,GAAqB;gBACnC,QAAQ,EAAE,IAAI,CAAC,gBAAiB;gBAChC,MAAM,EAAE,IAAI,CAAC,qBAAqB;gBAClC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC;YAEF,YAAY,CAAC,OAAO,CAAC,+BAA+B,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YAClF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,UAAU,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,cAAc;QACZ,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;YACpE,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,UAAU,GAAqB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAEvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CACjD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,CAClD,CAAC;gBAEF,IAAI,gBAAgB,EAAE,CAAC;oBACrB,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,QAAQ,CAAC;oBAC5C,IAAI,CAAC,qBAAqB,GAAG,UAAU,CAAC,MAAM,CAAC;oBAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,UAAU,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,YAAY,CAAC,MAAmB;QAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAE9B,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QAC1C,OAAO,QAAQ,CAAC,UAAU,KAAK,aAAa,CAAC;IAC/C,CAAC;IAED,aAAa;QAOX,OAAO;YACL,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACrD,EAAE,EAAE,MAAM,CAAC,QAAQ;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,gBAAgB;gBACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,gBAAgB;aACpD,CAAC,CAAC;YACH,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,0BAA0B,EAAE,IAAI,CAAC,0BAA0B,EAAE;YAC7D,eAAe,EAAE,IAAI,CAAC,qBAAqB;SAC5C,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,qBAAqB;QACjC,IAAI,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;gBAC3B,OAAO,QAAQ,CAAC;YAClB,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAA0B,EAAE,CAAC,CAAC;YAC3F,OAAO,UAAU,CAAC,KAAK,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;YACpE,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAEO,2BAA2B,CAAC,KAAU;QAC5C,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IAEO,0BAA0B;QAChC,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE/C,oEAAoE;QACpE,YAAY,CAAC,UAAU,CAAC,+BAA+B,CAAC,CAAC;QAEzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE;YACjD,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,qBAAqB,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM;SACpD,CAAC,CAAC;QAEH,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,CAAC,8BAA8B;QAE/D,IAAI,IAAI,CAAC,eAAe,KAAK,OAAO,EAAE,CAAC;YACrC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;aAAM,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;YAC3C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAEO,iBAAiB;QACvB,IAAI,CAAC,qBAAqB,GAAG,MAAM,CAAC;QAEpC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;YAC3C,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClD,EAAE,EAAE,GAAG,CAAC,QAAQ;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACtD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACvB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACtB,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBACxB,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;gBACzB,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QAEH,+DAA+D;QAC/D,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC/F,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;YAC/C,KAAK,EAAE,CAAC,CAAC,WAAW;YACpB,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK;YAC3D,QAAQ,EAAE,IAAI,CAAC,gBAAgB;SAChC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,qBAAqB,GAAG,aAAa,CAAC;QAE3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;YAC3C,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClD,EAAE,EAAE,GAAG,CAAC,QAAQ;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,0DAA0D;QAC1D,IAAI,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACnD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACtB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACtB,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAC7B,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;gBACzB,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,6EAA6E;QAC7E,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE;gBACrD,KAAK,EAAE,UAAU,CAAC,KAAK;gBACvB,QAAQ,EAAE,UAAU,CAAC,QAAQ;aAC9B,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7F,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE;YAC/C,KAAK,EAAE,CAAC,CAAC,UAAU;YACnB,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK;YAC1D,QAAQ,EAAE,IAAI,CAAC,gBAAgB;SAChC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YACjE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,6DAA6D;YAC7D,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE;gBACpD,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK;gBACrC,QAAQ,EAAE,IAAI,CAAC,gBAAgB;aAChC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,MAAuB;QACnD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACvE,IAAI,CAAC,qBAAqB,GAAG,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;IACrE,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,IAAI,CAAC;YACH,gEAAgE;YAChE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACtD,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAChC,CAAC;YAED,MAAM,gBAAgB,GAA0B,EAAE,CAAC;YAEnD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;gBAClD,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;gBACvC,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;gBACjD,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;aAC5C,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACrD,kEAAkE;gBAClE,gBAAgB,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE;oBACxC,QAAQ,EAAE,IAAI,CAAC,gBAAgB;iBAChC,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBACtC,wDAAwD;gBACxD,0EAA0E;gBAC1E,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,KAAK,SAAS;oBACpD,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE;oBACvC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC1C,gBAAgB,CAAC,UAAU,GAAG,gBAAgB,CAAC;gBAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;oBAC5C,UAAU,EAAE,IAAI,CAAC,qBAAqB;oBACtC,cAAc,EAAE,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;iBAClE,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACjC,gBAAgB,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE;oBAC9C,QAAQ,EAAE,IAAI,CAAC,gBAAgB;iBAChC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,IAAI,IAAI,CAAC,eAAe,KAAK,OAAO,EAAE,CAAC;oBACrC,gBAAgB,CAAC,UAAU,GAAG,MAAM,CAAC;gBACvC,CAAC;qBAAM,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;oBAC3C,gBAAgB,CAAC,UAAU,GAAG,aAAa,CAAC;gBAC9C,CAAC;qBAAM,CAAC;oBACN,iEAAiE;oBACjE,gBAAgB,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;gBACxH,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;oBAClD,UAAU,EAAE,gBAAgB,CAAC,UAAU;oBACvC,eAAe,EAAE,IAAI,CAAC,eAAe;oBACrC,UAAU,EAAE,IAAI,CAAC,UAAU;iBAC5B,CAAC,CAAC;YACL,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBAC3D,KAAK,EAAE,gBAAgB;aACxB,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,YAAY,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC;YAClD,UAAU,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAEtD,MAAM,WAAW,GAA0B,EAAE,GAAG,gBAAgB,EAAE,CAAC;YAEnE,4CAA4C;YAC5C,IAAI,CAAC,2BAA2B,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;YAE5D,IAAI,YAAY,CAAC,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;gBAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAE1D,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC;gBAEvF,IAAI,QAAQ,EAAE,CAAC;oBACb,WAAW,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;oBACxD,WAAW,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC3D,CAAC;qBAAM,CAAC;oBACN,WAAW,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;oBACxC,WAAW,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;gBAC5C,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;gBACnD,WAAW;gBACX,YAAY,EAAE,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC;aACxD,CAAC,CAAC;YAEH,OAAO,WAAW,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;YAEnG,gEAAgE;YAChE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACtD,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAChC,CAAC;YAED,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC;YACvF,MAAM,mBAAmB,GAA0B;gBACjD,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;gBACxC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;aACzC,CAAC;YAEF,+CAA+C;YAC/C,IAAI,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;YAElD,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACrD,kEAAkE;gBAClE,mBAAmB,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAClE,CAAC;iBAAM,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBACtC,wDAAwD;gBACxD,0EAA0E;gBAC1E,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,KAAK,SAAS;oBACpD,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE;oBACvC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC1C,mBAAmB,CAAC,UAAU,GAAG,gBAAgB,CAAC;YACpD,CAAC;iBAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACjC,mBAAmB,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,+DAA+D;gBAC/D,IAAI,IAAI,CAAC,eAAe,KAAK,OAAO,EAAE,CAAC;oBACrC,mBAAmB,CAAC,UAAU,GAAG,MAAM,CAAC;gBAC1C,CAAC;qBAAM,IAAI,IAAI,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;oBAC3C,mBAAmB,CAAC,UAAU,GAAG,aAAa,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,iEAAiE;oBACjE,mBAAmB,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC3H,CAAC;YACH,CAAC;YAED,OAAO,mBAAmB,CAAC;QAC7B,CAAC;IACH,CAAC;IAEO,2BAA2B,CAAC,WAAkC,EAAE,YAAoC;QAC1G,2DAA2D;QAE3D,0BAA0B;QAC1B,IAAI,YAAY,CAAC,SAAS,EAAE,CAAC;YAC3B,WAAW,CAAC,SAAS,GAAG;gBACtB,KAAK,EAAE,EAAE;gBACT,GAAG,EAAE,EAAE;gBACP,GAAG,EAAE,EAAE;aACR,CAAC;QACJ,CAAC;QAED,sDAAsD;QACtD,IAAI,YAAY,CAAC,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;YAC9C,WAAW,CAAC,KAAK,GAAG;gBAClB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;gBACrD,GAAG,EAAE,GAAG;aACT,CAAC;YACF,WAAW,CAAC,MAAM,GAAG;gBACnB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC;gBACtD,GAAG,EAAE,GAAG;aACT,CAAC;QACJ,CAAC;QAED,qFAAqF;QACrF,MAAM,mBAAmB,GAA8B,EAAE,CAAC;QAE1D,2DAA2D;QAC3D,MAAM,QAAQ,GAAQ,EAAE,CAAC;QAEzB,+DAA+D;QAC/D,IAAK,YAAoB,CAAC,SAAS,EAAE,CAAC;YACpC,IAAK,YAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC3D,QAAQ,CAAC,SAAS,GAAG,YAAY,CAAC;YACpC,CAAC;iBAAM,IAAK,YAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACnE,QAAQ,CAAC,SAAS,GAAG,aAAa,CAAC;YACrC,CAAC;QACH,CAAC;QAED,mCAAmC;QACnC,IAAK,YAAoB,CAAC,aAAa,EAAE,CAAC;YACxC,QAAQ,CAAC,aAAa,GAAG;gBACvB,KAAK,EAAE,GAAG,EAAE,sCAAsC;gBAClD,GAAG,EAAE,GAAG;gBACR,GAAG,EAAE,GAAG;aACT,CAAC;QACJ,CAAC;QAED,eAAe;QACf,IAAK,YAAoB,CAAC,IAAI,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,GAAG;gBACd,KAAK,EAAE,GAAG;gBACV,GAAG,EAAG,YAAoB,CAAC,IAAI,CAAC,GAAG;gBACnC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAE,YAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC;aACnD,CAAC;QACJ,CAAC;QAED,2CAA2C;QAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,WAAW,CAAC,QAAQ,GAAG,mBAAmB,CAAC;QAC7C,CAAC;IACH,CAAC;IAEO,uBAAuB,CAAC,WAAkC;QAChE,iEAAiE;QACjE,uDAAuD;QACvD,MAAM,QAAQ,GAAQ;YACpB,SAAS,EAAE,YAAY;YACvB,YAAY,EAAE,YAAY;YAC1B,gBAAgB,EAAE,YAAY;SAC/B,CAAC;QAEF,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC1B,WAAW,CAAC,QAAQ,GAAG,EAAE,CAAC;QAC5B,CAAC;QACD,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEpC,WAAW,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACxC,CAAC;IAEO,sBAAsB,CAAC,YAAoC;QACjE,OAAO;YACL,YAAY,EAAE,CAAC,CAAE,YAAoB,CAAC,SAAS;YAC/C,gBAAgB,EAAE,CAAC,CAAE,YAAoB,CAAC,aAAa;YACvD,kBAAkB,EAAE,CAAC,CAAE,YAAoB,CAAC,YAAY;YACxD,eAAe,EAAE,CAAC,CAAE,YAAoB,CAAC,gBAAgB;YACzD,OAAO,EAAE,CAAC,CAAE,YAAoB,CAAC,IAAI;YACrC,QAAQ,EAAG,YAAoB,CAAC,KAAK,KAAK,SAAS;YACnD,gBAAgB,EAAE,CAAC,CAAC,CAAE,YAAoB,CAAC,UAAU,IAAK,YAAoB,CAAC,QAAQ,IAAK,YAAoB,CAAC,UAAU,IAAK,YAAoB,CAAC,SAAS,CAAC;YAC/J,eAAe,EAAE,YAAY,CAAC,KAAK,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;gBAC1D,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;SAC5H,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,eAAe,CAAC,OAAgB,EAAE,MAAoB;QAC1D,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBACrE,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,YAAY,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC;YAClD,IAAK,YAAoB,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;gBAC/D,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,UAAU,CAAC,gBAAgB,CAAC;gBAChC,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAS,CAAC;aACtC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,YAAY,CAAC,CAAS,EAAE,CAAS,EAAE,MAAoB;QAC3D,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBAC1D,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;gBACrD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,YAAY,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC;YAClD,IAAI,CAAE,YAAoB,CAAC,SAAS,IAAI,CAAE,YAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACjG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;gBAC7D,OAAO,KAAK,CAAC;YACf,CAAC;YAED,4BAA4B;YAC5B,MAAM,UAAU,CAAC,gBAAgB,CAAC;gBAChC,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,aAAa,EAAS,CAAC;aAChD,CAAC,CAAC;YAEH,iDAAiD;YACjD,UAAU,CAAC,KAAK,IAAI,EAAE;gBACpB,IAAI,CAAC;oBACH,MAAM,UAAU,CAAC,gBAAgB,CAAC;wBAChC,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAS,CAAC;qBAC/C,CAAC,CAAC;gBACL,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAC;YAET,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;YAC1D,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF","sourcesContent":["import { ICameraService, CameraInfo, CameraPreference } from './interfaces/ICameraService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n private isManuallySelected: boolean = false;\n\n constructor(\n private logger: ILogger,\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n this.logger.state('DISPOSITIVO_DETECTADO', {\n deviceType: this.deviceType,\n userAgent: navigator.userAgent,\n screenDimensions: { width: window.innerWidth, height: window.innerHeight }\n });\n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n const permissionStatus = await this.checkCameraPermission();\n \n if (permissionStatus === 'denied') {\n this.logger.error('Permiso de cámara denegado por el usuario');\n return [];\n }\n \n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n \n const devices = await navigator.mediaDevices.enumerateDevices();\n this.availableCameras = devices.filter(device => device.kind === 'videoinput');\n \n this.logger.state('CAMARAS_DETECTADAS', {\n count: this.availableCameras.length,\n cameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label || 'Unknown Camera'\n }))\n });\n \n this.setInitialCameraPreference();\n \n this.logger.state('PREFERENCIA_INICIAL_APLICADA', {\n selectedCameraId: this.selectedCameraId,\n preferredCameraFacing: this.preferredCameraFacing,\n preferredCamera: this.preferredCamera\n });\n \n this.eventBus.emit('camera-changed', this.selectedCameraId);\n \n return this.availableCameras;\n } catch (error) {\n this.logger.error('Error al enumerar cámaras disponibles:', error);\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.isManuallySelected = true; // Mark as manually selected\n this.savePreference();\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n try {\n const finalConstraints = constraints || await this.getMaxResolution();\n \n const stream = await navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n return stream;\n } catch (error) {\n this.logger.error('Error en setupCamera, intentando con restricciones básicas:', error);\n \n // Fallback to basic constraints if getMaxResolution fails\n const basicConstraints: MediaTrackConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 }\n };\n \n // Only add facingMode if not on desktop to avoid OverconstrainedError\n if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {\n basicConstraints.facingMode = this.preferredCameraFacing;\n }\n \n this.logger.state('USANDO_RESTRICCIONES_BASICAS', { constraints: basicConstraints });\n \n return await navigator.mediaDevices.getUserMedia({\n video: basicConstraints,\n audio: false\n });\n }\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');\n await this.enumerateDevices();\n return;\n }\n \n await this.setSelectedCamera(cameraId);\n this.logger.state('CAMARA_CAMBIADA', { \n label: selectedCamera.label, \n deviceId: selectedCamera.deviceId,\n isManuallySelected: this.isManuallySelected\n });\n }\n\n async flipToNextCamera(): Promise<void> {\n if (!this.isMultipleCamerasAvailable()) return;\n \n const currentIndex = this.availableCameras.findIndex(\n camera => camera.deviceId === this.selectedCameraId\n );\n \n const nextIndex = (currentIndex + 1) % this.availableCameras.length;\n const nextCamera = this.availableCameras[nextIndex];\n \n await this.switchCamera(nextCamera.deviceId);\n }\n\n savePreference(): void {\n try {\n const preference: CameraPreference = {\n cameraId: this.selectedCameraId!,\n facing: this.preferredCameraFacing,\n timestamp: Date.now()\n };\n \n localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));\n this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);\n } catch (error) {\n this.logger.warn('Error al guardar preferencia de cámara:', error);\n }\n }\n\n loadPreference(): void {\n try {\n const saved = localStorage.getItem('jaak-stamps-camera-preference');\n if (saved) {\n const preference: CameraPreference = JSON.parse(saved);\n \n const isStillAvailable = this.availableCameras.some(\n camera => camera.deviceId === preference.cameraId\n );\n \n if (isStillAvailable) {\n this.selectedCameraId = preference.cameraId;\n this.preferredCameraFacing = preference.facing;\n this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);\n }\n }\n } catch (error) {\n this.logger.warn('Error al cargar preferencia de cámara:', error);\n }\n }\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n } {\n return {\n availableCameras: this.availableCameras.map(camera => ({\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId\n })),\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n this.logger.warn('No se pudo verificar permisos de cámara:', error);\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private setInitialCameraPreference(): void {\n if (this.availableCameras.length === 0) return;\n \n // Clear any existing localStorage preferences to ensure fresh start\n localStorage.removeItem('jaak-stamps-camera-preference');\n \n this.logger.state('APLICANDO_PREFERENCIA_INICIAL', {\n preferredCamera: this.preferredCamera,\n availableCamerasCount: this.availableCameras.length\n });\n \n this.isManuallySelected = false; // Reset manual selection flag\n \n if (this.preferredCamera === 'front') {\n this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n this.selectBackCamera();\n } else {\n this.selectAutoCamera();\n }\n }\n\n private selectFrontCamera(): void {\n this.preferredCameraFacing = 'user';\n \n this.logger.state('BUSCANDO_CAMARA_FRONTAL', {\n availableCameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label\n }))\n });\n \n const frontCamera = this.availableCameras.find(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('front') || \n label.includes('user') ||\n label.includes('selfie') ||\n label.includes('frontal') ||\n (!label.includes('back') && !label.includes('rear') && !label.includes('environment'));\n });\n \n // If not found, use the first camera (usually front on mobile)\n this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { \n found: !!frontCamera,\n label: frontCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectBackCamera(): void {\n this.preferredCameraFacing = 'environment';\n \n this.logger.state('BUSCANDO_CAMARA_TRASERA', {\n availableCameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label\n }))\n });\n \n // Try to find rear camera with multiple detection methods\n let backCamera = this.availableCameras.find(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('back') || \n label.includes('rear') ||\n label.includes('environment') ||\n label.includes('trasera') ||\n label.includes('posterior');\n });\n \n // If not found by label, try to use the last camera (usually rear on mobile)\n if (!backCamera && this.availableCameras.length > 1) {\n backCamera = this.availableCameras[this.availableCameras.length - 1];\n this.logger.state('USANDO_ULTIMA_CAMARA_COMO_TRASERA', {\n label: backCamera.label,\n deviceId: backCamera.deviceId\n });\n }\n \n this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_TRASERA_SELECCIONADA', { \n found: !!backCamera,\n label: backCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectAutoCamera(): void {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n this.selectBackCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });\n } else {\n // For desktop, prefer front camera (usually built-in webcam)\n this.selectFrontCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { \n type: 'front',\n label: this.availableCameras[0].label, \n deviceId: this.selectedCameraId \n });\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const videoConstraints: MediaTrackConstraints = {};\n \n this.logger.state('CONFIGURANDO_CONSTRAINS_CAMARA', {\n selectedCameraId: this.selectedCameraId,\n preferredCameraFacing: this.preferredCameraFacing,\n preferredCamera: this.preferredCamera,\n deviceType: this.deviceType,\n isManuallySelected: this.isManuallySelected\n });\n \n if (this.isManuallySelected && this.selectedCameraId) {\n // When manually selected, use deviceId for exact camera selection\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n this.logger.state('USANDO_CAMARA_MANUAL', { \n deviceId: this.selectedCameraId\n });\n } else if (this.preferredCameraFacing) {\n // Use facingMode for initial preference-based selection\n // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n videoConstraints.facingMode = facingConstraint;\n this.logger.state('USANDO_FACING_CONSTRAINT', { \n facingMode: this.preferredCameraFacing,\n constraintType: this.deviceType === 'desktop' ? 'ideal' : 'exact'\n });\n } else if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n this.logger.state('USANDO_CAMARA_SELECCIONADA', { \n deviceId: this.selectedCameraId\n });\n } else {\n // Use preferredCamera setting to determine default facing mode\n if (this.preferredCamera === 'front') {\n videoConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n videoConstraints.facingMode = \"environment\"; \n } else {\n // Auto mode: use environment for mobile/tablet, user for desktop\n videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n this.logger.state('USANDO_PREFERENCIA_CONFIGURADA', { \n facingMode: videoConstraints.facingMode,\n preferredCamera: this.preferredCamera,\n deviceType: this.deviceType\n });\n }\n \n const tempStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints\n });\n \n const videoTrack = tempStream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n // Enhanced focus and image quality settings\n this.applyAdvancedCameraSettings(constraints, capabilities);\n \n if (capabilities.width && capabilities.height) {\n const maxWidth = Math.min(capabilities.width.max, 1920);\n const maxHeight = Math.min(capabilities.height.max, 1080);\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n constraints.width = { ideal: Math.min(maxWidth, 1280) };\n constraints.height = { ideal: Math.min(maxHeight, 720) };\n } else {\n constraints.width = { ideal: maxWidth };\n constraints.height = { ideal: maxHeight };\n }\n }\n \n this.logger.state('CONFIGURACION_CAMARA_OPTIMIZADA', {\n constraints,\n capabilities: this.getCapabilitiesSummary(capabilities)\n });\n \n return constraints;\n } catch (err) {\n this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');\n \n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: isTablet ? 1280 : 1920 },\n height: { ideal: isTablet ? 720 : 1080 }\n };\n \n // Apply basic focus settings even for fallback\n this.applyBasicFocusSettings(fallbackConstraints);\n \n if (this.isManuallySelected && this.selectedCameraId) {\n // When manually selected, use deviceId for exact camera selection\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n // Use facingMode for initial preference-based selection\n // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n fallbackConstraints.facingMode = facingConstraint;\n } else if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else {\n // Use preferredCamera setting to determine default facing mode\n if (this.preferredCamera === 'front') {\n fallbackConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n fallbackConstraints.facingMode = \"environment\"; \n } else {\n // Auto mode: use environment for mobile/tablet, user for desktop\n fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n return fallbackConstraints;\n }\n }\n\n private applyAdvancedCameraSettings(constraints: MediaTrackConstraints, capabilities: MediaTrackCapabilities): void {\n // Apply standard camera settings that are widely supported\n \n // Frame rate optimization\n if (capabilities.frameRate) {\n constraints.frameRate = {\n ideal: 30,\n min: 15,\n max: 60\n };\n }\n\n // Width and height constraints for optimal resolution\n if (capabilities.width && capabilities.height) {\n constraints.width = {\n ideal: Math.min(1920, capabilities.width.max || 1920),\n min: 640\n };\n constraints.height = {\n ideal: Math.min(1080, capabilities.height.max || 1080),\n min: 480\n };\n }\n\n // Apply enhanced constraints through advanced array for better browser compatibility\n const advancedConstraints: MediaTrackConstraintSet[] = [];\n \n // Try to set optimal settings through advanced constraints\n const advanced: any = {};\n \n // Focus mode - use 'any' type to bypass TypeScript limitations\n if ((capabilities as any).focusMode) {\n if ((capabilities as any).focusMode.includes('continuous')) {\n advanced.focusMode = 'continuous';\n } else if ((capabilities as any).focusMode.includes('single-shot')) {\n advanced.focusMode = 'single-shot';\n }\n }\n\n // Focus distance for close objects\n if ((capabilities as any).focusDistance) {\n advanced.focusDistance = {\n ideal: 0.4, // 40cm - optimal for document capture\n min: 0.2,\n max: 1.0\n };\n }\n\n // Zoom control\n if ((capabilities as any).zoom) {\n advanced.zoom = {\n ideal: 1.0,\n min: (capabilities as any).zoom.min,\n max: Math.min((capabilities as any).zoom.max, 3.0)\n };\n }\n\n // Add advanced constraints if any were set\n if (Object.keys(advanced).length > 0) {\n advancedConstraints.push(advanced);\n }\n\n if (advancedConstraints.length > 0) {\n constraints.advanced = advancedConstraints;\n }\n }\n\n private applyBasicFocusSettings(constraints: MediaTrackConstraints): void {\n // Apply basic focus settings when capabilities are not available\n // Use advanced constraints for non-standard properties\n const advanced: any = {\n focusMode: 'continuous',\n exposureMode: 'continuous',\n whiteBalanceMode: 'continuous'\n };\n \n if (!constraints.advanced) {\n constraints.advanced = [];\n }\n constraints.advanced.push(advanced);\n \n constraints.frameRate = { ideal: 30 };\n }\n\n private getCapabilitiesSummary(capabilities: MediaTrackCapabilities): any {\n return {\n hasAutoFocus: !!(capabilities as any).focusMode,\n hasFocusDistance: !!(capabilities as any).focusDistance,\n hasExposureControl: !!(capabilities as any).exposureMode,\n hasWhiteBalance: !!(capabilities as any).whiteBalanceMode,\n hasZoom: !!(capabilities as any).zoom,\n hasTorch: (capabilities as any).torch !== undefined,\n hasImageControls: !!((capabilities as any).brightness || (capabilities as any).contrast || (capabilities as any).saturation || (capabilities as any).sharpness),\n resolutionRange: capabilities.width && capabilities.height ? \n `${capabilities.width.min}x${capabilities.height.min} - ${capabilities.width.max}x${capabilities.height.max}` : 'unknown'\n };\n }\n\n // New method to enable torch/flash for better illumination\n async setTorchEnabled(enabled: boolean, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para controlar el flash');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if ((capabilities as any).torch === undefined) {\n this.logger.warn('El dispositivo no soporta control de flash');\n return false;\n }\n\n await videoTrack.applyConstraints({\n advanced: [{ torch: enabled } as any]\n });\n\n this.logger.state('FLASH_CONTROLADO', { enabled });\n return true;\n } catch (error) {\n this.logger.error('Error al controlar el flash:', error);\n return false;\n }\n }\n\n // Method to manually trigger focus on a specific point\n async focusAtPoint(x: number, y: number, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para enfocar');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if (!(capabilities as any).focusMode || !(capabilities as any).focusMode.includes('single-shot')) {\n this.logger.warn('El dispositivo no soporta enfoque manual');\n return false;\n }\n\n // Trigger single-shot focus\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'single-shot' } as any]\n });\n\n // Return to continuous focus after a short delay\n setTimeout(async () => {\n try {\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'continuous' } as any]\n });\n } catch (error) {\n this.logger.warn('Error al volver a enfoque continuo:', error);\n }\n }, 1000);\n\n this.logger.state('ENFOQUE_MANUAL_ACTIVADO', { x, y });\n return true;\n } catch (error) {\n this.logger.error('Error al enfocar manualmente:', error);\n return false;\n }\n }\n}"]}
|
|
@@ -9,7 +9,7 @@ export class DetectionService {
|
|
|
9
9
|
modelLoaded = false;
|
|
10
10
|
deviceStrategy;
|
|
11
11
|
MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
|
|
12
|
-
MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/
|
|
12
|
+
MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet_new_fp32.onnx";
|
|
13
13
|
MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
|
|
14
14
|
INPUT_SIZE = 320;
|
|
15
15
|
CONFIDENCE_THRESHOLD = 0.6;
|
|
@@ -71,15 +71,27 @@ export class DetectionService {
|
|
|
71
71
|
}
|
|
72
72
|
try {
|
|
73
73
|
this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
// Try to load class map (optional - SqueezeNet may not need it for basic classification)
|
|
75
|
+
try {
|
|
76
|
+
const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
|
|
77
|
+
if (classResponse.ok) {
|
|
78
|
+
this.mobileNetClassMap = await classResponse.json();
|
|
79
|
+
this.logger.state('CLASES_MOBILENET_CARGADAS', {
|
|
80
|
+
classCount: Object.keys(this.mobileNetClassMap).length
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
this.logger.warn('No se pudo cargar el mapa de clases de MobileNet, usando clasificación básica');
|
|
86
|
+
// Create a basic class map for document types
|
|
87
|
+
this.mobileNetClassMap = {
|
|
88
|
+
"0": "document",
|
|
89
|
+
"1": "id_card",
|
|
90
|
+
"2": "passport",
|
|
91
|
+
"3": "license",
|
|
92
|
+
"4": "other"
|
|
93
|
+
};
|
|
78
94
|
}
|
|
79
|
-
this.mobileNetClassMap = await classResponse.json();
|
|
80
|
-
this.logger.state('CLASES_MOBILENET_CARGADAS', {
|
|
81
|
-
classCount: Object.keys(this.mobileNetClassMap).length
|
|
82
|
-
});
|
|
83
95
|
// Load model
|
|
84
96
|
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
85
97
|
try {
|
|
@@ -168,7 +180,7 @@ export class DetectionService {
|
|
|
168
180
|
try {
|
|
169
181
|
this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
|
|
170
182
|
const inputTensor = this.preprocessMobileNet(canvas);
|
|
171
|
-
const feeds = {
|
|
183
|
+
const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };
|
|
172
184
|
const results = await this.mobileNetSession.run(feeds);
|
|
173
185
|
const output = results[Object.keys(results)[0]].data;
|
|
174
186
|
const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
|
|
@@ -178,7 +190,8 @@ export class DetectionService {
|
|
|
178
190
|
class: className,
|
|
179
191
|
confidence: confidence.toFixed(3),
|
|
180
192
|
classIndex: maxIdx,
|
|
181
|
-
timestamp: Date.now()
|
|
193
|
+
timestamp: Date.now(),
|
|
194
|
+
results
|
|
182
195
|
});
|
|
183
196
|
return {
|
|
184
197
|
class: className,
|
|
@@ -217,7 +230,7 @@ export class DetectionService {
|
|
|
217
230
|
displayedVideoHeight = INPUT_SIZE / videoAspectRatio;
|
|
218
231
|
}
|
|
219
232
|
else {
|
|
220
|
-
// Video is taller - pillarboxed in display
|
|
233
|
+
// Video is taller - pillarboxed in display
|
|
221
234
|
displayedVideoHeight = INPUT_SIZE;
|
|
222
235
|
displayedVideoWidth = INPUT_SIZE * videoAspectRatio;
|
|
223
236
|
}
|
|
@@ -268,7 +281,7 @@ export class DetectionService {
|
|
|
268
281
|
const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;
|
|
269
282
|
return {
|
|
270
283
|
top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados
|
|
271
|
-
right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
|
|
284
|
+
right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
|
|
272
285
|
bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados
|
|
273
286
|
left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados
|
|
274
287
|
};
|
|
@@ -353,15 +366,20 @@ export class DetectionService {
|
|
|
353
366
|
tempCanvas.width = 224;
|
|
354
367
|
tempCanvas.height = 224;
|
|
355
368
|
const tempCtx = tempCanvas.getContext('2d');
|
|
369
|
+
// Resize image to 224x224 for SqueezeNet (using MobileNet interface)
|
|
356
370
|
tempCtx.drawImage(canvas, 0, 0, 224, 224);
|
|
357
371
|
const imageData = tempCtx.getImageData(0, 0, 224, 224);
|
|
358
372
|
const data = imageData.data;
|
|
359
373
|
const hw = 224 * 224;
|
|
360
374
|
const arr = new Float32Array(3 * hw);
|
|
375
|
+
// SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format
|
|
361
376
|
for (let i = 0; i < hw; i++) {
|
|
362
|
-
|
|
363
|
-
arr[
|
|
364
|
-
|
|
377
|
+
// Red channel
|
|
378
|
+
arr[i] = data[i * 4 + 0] / 255.0;
|
|
379
|
+
// Green channel
|
|
380
|
+
arr[hw + i] = data[i * 4 + 1] / 255.0;
|
|
381
|
+
// Blue channel
|
|
382
|
+
arr[2 * hw + i] = data[i * 4 + 2] / 255.0;
|
|
365
383
|
}
|
|
366
384
|
return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
|
|
367
385
|
}
|