datakeen-session-react 1.1.193 → 1.1.194-rc.1
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/.gitlab-ci.yml +9 -3
- package/dist/cjs/components/document-collection/DocumentProcessing.js +18 -2
- package/dist/cjs/components/document-collection/DocumentProcessing.js.map +1 -1
- package/dist/cjs/components/id-check/BeforePhoto.js +1 -1
- package/dist/cjs/components/id-check/BeforePhoto.js.map +1 -1
- package/dist/cjs/components/id-check/CameraMask.js +12 -6
- package/dist/cjs/components/id-check/CameraMask.js.map +1 -1
- package/dist/cjs/components/id-check/Photo.js +66 -18
- package/dist/cjs/components/id-check/Photo.js.map +1 -1
- package/dist/cjs/components/jdi/JDIProcessing.js +17 -2
- package/dist/cjs/components/jdi/JDIProcessing.js.map +1 -1
- package/dist/cjs/components/start-flow/CGU.js +1 -1
- package/dist/cjs/components/start-flow/Start.js +1 -1
- package/dist/cjs/i18n/en.json.js +16 -14
- package/dist/cjs/i18n/en.json.js.map +1 -1
- package/dist/cjs/i18n/es.json.js +1208 -0
- package/dist/cjs/i18n/es.json.js.map +1 -0
- package/dist/cjs/i18n/fr.json.js +8 -6
- package/dist/cjs/i18n/fr.json.js.map +1 -1
- package/dist/cjs/i18n/index.js +5 -1
- package/dist/cjs/i18n/index.js.map +1 -1
- package/dist/cjs/index.css.js +1 -1
- package/dist/cjs/services/cameraService.js +34 -90
- package/dist/cjs/services/cameraService.js.map +1 -1
- package/dist/cjs/services/documentEdgeDetectionService.js +182 -0
- package/dist/cjs/services/documentEdgeDetectionService.js.map +1 -0
- package/dist/cjs/utils/analysisErrors.js +18 -0
- package/dist/cjs/utils/analysisErrors.js.map +1 -1
- package/dist/cjs/utils/languageFlags.js +6 -0
- package/dist/cjs/utils/languageFlags.js.map +1 -1
- package/dist/esm/components/document-collection/DocumentProcessing.js +19 -3
- package/dist/esm/components/document-collection/DocumentProcessing.js.map +1 -1
- package/dist/esm/components/id-check/BeforePhoto.js +1 -1
- package/dist/esm/components/id-check/BeforePhoto.js.map +1 -1
- package/dist/esm/components/id-check/CameraMask.js +12 -6
- package/dist/esm/components/id-check/CameraMask.js.map +1 -1
- package/dist/esm/components/id-check/Photo.js +66 -18
- package/dist/esm/components/id-check/Photo.js.map +1 -1
- package/dist/esm/components/jdi/JDIProcessing.js +18 -3
- package/dist/esm/components/jdi/JDIProcessing.js.map +1 -1
- package/dist/esm/components/start-flow/CGU.js +1 -1
- package/dist/esm/components/start-flow/Start.js +1 -1
- package/dist/esm/i18n/en.json.js +16 -14
- package/dist/esm/i18n/en.json.js.map +1 -1
- package/dist/esm/i18n/es.json.js +1167 -0
- package/dist/esm/i18n/es.json.js.map +1 -0
- package/dist/esm/i18n/fr.json.js +8 -6
- package/dist/esm/i18n/fr.json.js.map +1 -1
- package/dist/esm/i18n/index.js +5 -1
- package/dist/esm/i18n/index.js.map +1 -1
- package/dist/esm/index.css.js +1 -1
- package/dist/esm/services/cameraService.js +34 -90
- package/dist/esm/services/cameraService.js.map +1 -1
- package/dist/esm/services/documentEdgeDetectionService.js +176 -0
- package/dist/esm/services/documentEdgeDetectionService.js.map +1 -0
- package/dist/esm/utils/analysisErrors.js +17 -1
- package/dist/esm/utils/analysisErrors.js.map +1 -1
- package/dist/esm/utils/languageFlags.js +6 -0
- package/dist/esm/utils/languageFlags.js.map +1 -1
- package/package.json +1 -4
- package/dist/cjs/services/documentDetectionService.js +0 -156
- package/dist/cjs/services/documentDetectionService.js.map +0 -1
- package/dist/esm/services/documentDetectionService.js +0 -153
- package/dist/esm/services/documentDetectionService.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cameraService.js","sources":["../../../../src/services/cameraService.ts"],"sourcesContent":["import type { CameraFacingMode } from \"../types/camera\";\nimport { professionalImageQuality } from \"./professionalImageQuality\";\nimport type { QualityAnalysis } from \"./professionalImageQuality\";\n\n// Permit to enable development mode to test without a camera\nconst DEV_MODE = false; // import.meta.env.DEV;\n// Default image path for development mode\nconst DEFAULT_TEST_IMAGE = \"/mock-id-card.jpeg\";\n\ntype CaptureMethod = \"imageCapture\" | \"canvas\" | \"mock\";\n\nexport interface CameraStartOptions {\n facingMode?: CameraFacingMode;\n idealResolution?: {\n width?: number;\n height?: number;\n };\n deviceId?: string;\n advancedConstraints?: MediaTrackConstraints[];\n preferImageCapture?: boolean;\n}\n\nexport interface CameraStartResult {\n success: boolean;\n error?: string;\n settings?: MediaTrackSettings;\n captureMethod?: CaptureMethod;\n}\n\nexport interface DocumentCropArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface CaptureDocumentOptions {\n facingMode?: CameraFacingMode;\n format?: \"png\" | \"jpeg\";\n jpegQuality?: number;\n preferImageCapture?: boolean;\n}\n\nexport interface CaptureDocumentResult {\n dataUrl: string;\n method: CaptureMethod;\n analysis?: QualityAnalysis;\n sourceDimensions?: { width: number; height: number };\n cropDimensions?: { width: number; height: number };\n}\n\nconst DEFAULT_RESOLUTION = {\n width: 4096,\n height: 3072,\n};\n\nconst QUALITY_REQUIREMENTS = {\n minArea: 3500 * 2200,\n targetArea: 4800 * 3200,\n minLongSide: 3200,\n};\n\nconst supportsImageCapture = (): boolean =>\n typeof window !== \"undefined\" && \"ImageCapture\" in window;\n\ninterface CanvasSource {\n source: CanvasImageSource;\n width: number;\n height: number;\n cleanup?: () => void;\n}\n\nexport class CameraService {\n private stream: MediaStream | null = null;\n private videoTrack: MediaStreamTrack | null = null;\n private imageCapture: ImageCapture | null = null;\n private devMode: boolean = DEV_MODE;\n private mockImagePath: string = DEFAULT_TEST_IMAGE;\n private captureMethod: CaptureMethod = \"canvas\";\n private lastTrackSettings: MediaTrackSettings | null = null;\n private startingPromise: Promise<CameraStartResult> | null = null;\n\n private async startMockCamera(\n videoElement: HTMLVideoElement | null\n ): Promise<CameraStartResult> {\n try {\n if (!videoElement) {\n return { success: false, error: \"Élément vidéo non disponible\" };\n }\n\n const img = new Image();\n img.src = this.mockImagePath;\n\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () =>\n reject(\n new Error(`Impossible de charger l'image: ${this.mockImagePath}`)\n );\n });\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = img.width;\n canvas.height = img.height;\n const ctx = canvas.getContext(\"2d\");\n\n if (!ctx) {\n return { success: false, error: \"Contexte du canvas non disponible\" };\n }\n\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n\n const stream: MediaStream = canvas.captureStream(30);\n this.stream = stream;\n this.captureMethod = \"mock\";\n videoElement.srcObject = stream;\n\n return { success: true, captureMethod: \"mock\" };\n } catch (err) {\n console.error(\"Erreur lors de la création du flux vidéo mock:\", err);\n return {\n success: false,\n error: `Erreur lors de la création du flux vidéo mock: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n }\n\n async startCamera(\n videoElement: HTMLVideoElement | null,\n options: CameraStartOptions = {}\n ): Promise<CameraStartResult> {\n if (this.devMode) {\n return this.startMockCamera(videoElement);\n }\n\n if (!videoElement) {\n return { success: false, error: \"Élément vidéo non disponible\" };\n }\n\n if (!navigator?.mediaDevices?.getUserMedia) {\n return {\n success: false,\n error: \"La capture vidéo n'est pas supportée sur cet appareil.\",\n };\n }\n\n // Si un startCamera est déjà en cours, attendre qu'il se termine plutôt que d'en lancer un second\n if (this.startingPromise) {\n return this.startingPromise;\n }\n\n this.startingPromise = this._doStartCamera(videoElement!, options);\n try {\n return await this.startingPromise;\n } finally {\n this.startingPromise = null;\n }\n }\n\n private async _doStartCamera(\n videoElement: HTMLVideoElement,\n options: CameraStartOptions\n ): Promise<CameraStartResult> {\n const facingMode = options.facingMode ?? \"environment\";\n const preferImageCapture = options.preferImageCapture ?? true;\n const desiredWidth = options.idealResolution?.width ?? DEFAULT_RESOLUTION.width;\n const desiredHeight = options.idealResolution?.height ?? DEFAULT_RESOLUTION.height;\n\n try {\n // Close any existing stream before opening a new one\n if (this.stream) {\n this.stream.getTracks().forEach((t) => t.stop());\n this.stream = null;\n this.videoTrack = null;\n this.imageCapture = null;\n }\n\n // Step 1: Probe the camera to discover its maximum supported resolution\n const maxResolution = await this.getMaxCameraResolution(facingMode, options.deviceId);\n\n // Use the lesser of the desired and the device maximum\n const targetWidth = maxResolution\n ? Math.min(desiredWidth, maxResolution.width)\n : desiredWidth;\n const targetHeight = maxResolution\n ? Math.min(desiredHeight, maxResolution.height)\n : desiredHeight;\n\n console.debug(\"[CameraService] Resolution negotiation\", {\n desired: { width: desiredWidth, height: desiredHeight },\n deviceMax: maxResolution ?? \"unknown\",\n target: { width: targetWidth, height: targetHeight },\n });\n\n const videoConstraints: MediaTrackConstraints = {\n facingMode,\n width: { ideal: targetWidth },\n height: { ideal: targetHeight },\n };\n\n if (options.deviceId) {\n videoConstraints.deviceId = { exact: options.deviceId };\n }\n\n if (options.advancedConstraints?.length) {\n videoConstraints.advanced = options.advancedConstraints;\n }\n\n // Step 2: Open the stream with adapted constraints\n const stream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n });\n\n this.stream = stream;\n this.videoTrack = stream.getVideoTracks()[0] ?? null;\n this.lastTrackSettings = this.videoTrack?.getSettings() ?? null;\n\n // Step 3: Apply continuous autofocus via applyConstraints after stream is open.\n // Done separately so a rejection (unsupported constraint) never kills the stream.\n if (this.videoTrack) {\n try {\n await this.videoTrack.applyConstraints({\n advanced: [{ focusMode: \"continuous\" } as MediaTrackConstraints],\n });\n } catch {\n // Device doesn't support focusMode — stream stays open, autofocus just won't activate\n }\n }\n\n if (supportsImageCapture() && this.videoTrack && preferImageCapture) {\n try {\n this.imageCapture = new ImageCapture(this.videoTrack);\n this.captureMethod = \"imageCapture\";\n } catch (error) {\n console.warn(\n \"ImageCapture API indisponible, fallback sur capture canvas\",\n error\n );\n this.imageCapture = null;\n this.captureMethod = \"canvas\";\n }\n } else {\n this.imageCapture = null;\n this.captureMethod = \"canvas\";\n }\n\n videoElement.srcObject = stream;\n\n await this.waitForVideoReady(videoElement);\n\n return {\n success: true,\n settings: this.lastTrackSettings ?? undefined,\n captureMethod: this.captureMethod,\n };\n } catch (err) {\n console.error(\"Erreur lors de l'accès à la caméra:\", err);\n\n let errorMessage =\n \"Une erreur inconnue s'est produite lors de l'accès à la caméra.\";\n\n if (err instanceof DOMException) {\n if (err.name === \"NotFoundError\") {\n errorMessage = \"Aucune caméra n'a été détectée sur votre appareil.\";\n } else if (err.name === \"NotAllowedError\") {\n errorMessage =\n \"L'accès à la caméra a été refusé. Veuillez autoriser l'accès dans les paramètres de votre navigateur.\";\n } else {\n errorMessage = `Impossible d'accéder à la caméra: ${err.message}`;\n }\n }\n\n return { success: false, error: errorMessage };\n }\n }\n\n async captureDocument(\n videoElement: HTMLVideoElement | null,\n cropArea?: DocumentCropArea | null,\n options: CaptureDocumentOptions = {}\n ): Promise<CaptureDocumentResult> {\n if (!videoElement) {\n throw new Error(\"Élément vidéo requis pour capturer le document\");\n }\n\n if (!videoElement.videoWidth || !videoElement.videoHeight) {\n throw new Error(\n \"La vidéo n'est pas prête. Impossible de déterminer les dimensions.\"\n );\n }\n\n const format = options.format ?? \"jpeg\";\n const jpegQuality = options.jpegQuality ?? 0.95;\n const facingMode = options.facingMode ?? \"environment\";\n const preferImageCapture = options.preferImageCapture ?? true;\n\n const effectiveCropArea: DocumentCropArea = cropArea ?? {\n x: 0,\n y: 0,\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n };\n\n console.debug(\"[CameraService] captureDocument request\", {\n format,\n jpegQuality,\n facingMode,\n preferImageCapture,\n cropArea: effectiveCropArea,\n videoDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n });\n\n if (this.imageCapture && preferImageCapture) {\n try {\n const result = await this.captureWithImageCapture(\n videoElement,\n effectiveCropArea,\n {\n format,\n jpegQuality,\n facingMode,\n }\n );\n\n if (result) {\n console.debug(\"[CameraService] captureDocument via ImageCapture\", {\n cropArea: effectiveCropArea,\n result,\n });\n return result;\n }\n } catch (error) {\n console.warn(\n \"Capture haute résolution impossible, fallback sur capture vidéo\",\n error\n );\n }\n }\n\n const fallback = professionalImageQuality.autoEnhanceImage(\n videoElement,\n effectiveCropArea,\n {\n outputFormat: format,\n jpegQuality,\n flipHorizontal: facingMode === \"user\",\n ...QUALITY_REQUIREMENTS,\n }\n );\n\n console.debug(\"[CameraService] captureDocument via video fallback\", {\n cropArea: effectiveCropArea,\n analysis: fallback.analysis,\n method: this.captureMethod,\n sourceDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n });\n\n return {\n dataUrl: fallback.dataUrl,\n analysis: fallback.analysis,\n method: this.captureMethod,\n sourceDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n cropDimensions: {\n width: effectiveCropArea.width,\n height: effectiveCropArea.height,\n },\n };\n }\n\n captureFrame(\n videoElement: HTMLVideoElement | null,\n canvasElement: HTMLCanvasElement | null\n ): string | null {\n if (!videoElement || !canvasElement || !videoElement.videoWidth) {\n return null;\n }\n\n const ctx = canvasElement.getContext(\"2d\");\n if (!ctx) return null;\n\n canvasElement.width = videoElement.videoWidth;\n canvasElement.height = videoElement.videoHeight;\n\n ctx.drawImage(\n videoElement,\n 0,\n 0,\n canvasElement.width,\n canvasElement.height\n );\n\n return canvasElement.toDataURL(\"image/jpeg\");\n }\n\n stopCamera() {\n if (this.stream) {\n this.stream.getTracks().forEach((track) => track.stop());\n this.stream = null;\n }\n\n this.videoTrack = null;\n this.imageCapture = null;\n this.lastTrackSettings = null;\n this.captureMethod = this.devMode ? \"mock\" : \"canvas\";\n }\n\n setDevMode(enabled: boolean): void {\n this.devMode = enabled;\n }\n\n setMockImage(imagePath: string): void {\n this.mockImagePath = imagePath;\n }\n\n isDevModeEnabled(): boolean {\n return this.devMode;\n }\n\n getCurrentCaptureMethod(): CaptureMethod {\n return this.captureMethod;\n }\n\n /**\n * Probes the camera to discover its maximum supported resolution.\n * Opens a temporary low-res stream, reads getCapabilities(), then closes it.\n * Returns null if capabilities cannot be determined (the caller should fallback to defaults).\n */\n private async getMaxCameraResolution(\n facingMode: string,\n deviceId?: string\n ): Promise<{ width: number; height: number } | null> {\n try {\n const constraints: MediaTrackConstraints = { facingMode };\n if (deviceId) {\n constraints.deviceId = { exact: deviceId };\n }\n\n const probeStream = await navigator.mediaDevices.getUserMedia({\n video: constraints,\n });\n\n const track = probeStream.getVideoTracks()[0];\n if (!track) {\n probeStream.getTracks().forEach((t) => t.stop());\n return null;\n }\n\n let maxWidth: number | undefined;\n let maxHeight: number | undefined;\n\n // getCapabilities() is supported on Chrome/Edge/Android but not all browsers\n if (typeof track.getCapabilities === \"function\") {\n const capabilities = track.getCapabilities();\n maxWidth = (capabilities as Record<string, any>).width?.max;\n maxHeight = (capabilities as Record<string, any>).height?.max;\n }\n\n // Stop the probe stream immediately\n probeStream.getTracks().forEach((t) => t.stop());\n\n if (maxWidth && maxHeight) {\n console.debug(\"[CameraService] Device max resolution\", {\n width: maxWidth,\n height: maxHeight,\n });\n return { width: maxWidth, height: maxHeight };\n }\n\n return null;\n } catch (error) {\n console.warn(\"[CameraService] Could not probe camera capabilities\", error);\n return null;\n }\n }\n\n private async waitForVideoReady(video: HTMLVideoElement): Promise<void> {\n // Explicitly call play() — required on some Android devices even with autoplay attribute\n try {\n await video.play();\n } catch (playError) {\n console.warn(\"[CameraService] video.play() failed, relying on autoplay\", playError);\n }\n\n if (\n video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA &&\n video.videoWidth > 0\n ) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n const TIMEOUT_MS = 5000;\n\n const onReady = () => {\n clearTimeout(timeout);\n video.removeEventListener(\"loadeddata\", onReady);\n video.removeEventListener(\"playing\", onReady);\n resolve();\n };\n\n // Listen for both events — whichever fires first\n video.addEventListener(\"loadeddata\", onReady, { once: true });\n video.addEventListener(\"playing\", onReady, { once: true });\n\n // Safety timeout to avoid hanging indefinitely\n const timeout = setTimeout(() => {\n video.removeEventListener(\"loadeddata\", onReady);\n video.removeEventListener(\"playing\", onReady);\n console.warn(\"[CameraService] waitForVideoReady timed out after\", TIMEOUT_MS, \"ms\");\n resolve();\n }, TIMEOUT_MS);\n });\n }\n\n private async captureWithImageCapture(\n videoElement: HTMLVideoElement,\n cropArea: DocumentCropArea,\n options: Required<Pick<CaptureDocumentOptions, \"format\" | \"jpegQuality\">> & {\n facingMode: CameraFacingMode;\n }\n ): Promise<CaptureDocumentResult | null> {\n if (!this.imageCapture) {\n return null;\n }\n\n // Use the actual stream resolution for takePhoto to ensure consistency\n const photoSettings: PhotoSettings = {};\n if (this.lastTrackSettings?.width && this.lastTrackSettings?.height) {\n photoSettings.imageWidth = this.lastTrackSettings.width;\n photoSettings.imageHeight = this.lastTrackSettings.height;\n console.debug(\"[CameraService] takePhoto with explicit resolution\", photoSettings);\n }\n\n const blob = await this.imageCapture.takePhoto(photoSettings);\n const { source, width, height, cleanup } = await this.loadCanvasSourceFromBlob(\n blob\n );\n\n try {\n const ratioX = width / videoElement.videoWidth;\n const ratioY = height / videoElement.videoHeight;\n\n if (!isFinite(ratioX) || !isFinite(ratioY)) {\n throw new Error(\"Ratios de capture invalides\");\n }\n\n const scaled = this.scaleCropArea(cropArea, ratioX, ratioY, width, height);\n\n const analysis = professionalImageQuality.analyzeQuality(\n scaled.width,\n scaled.height,\n QUALITY_REQUIREMENTS\n );\n\n const outputWidth = Math.max(\n 1,\n Math.round(scaled.width * analysis.recommendedScale)\n );\n const outputHeight = Math.max(\n 1,\n Math.round(scaled.height * analysis.recommendedScale)\n );\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = outputWidth;\n canvas.height = outputHeight;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Impossible de créer le contexte de rendu\");\n }\n\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n\n if (options.facingMode === \"user\") {\n ctx.translate(outputWidth, 0);\n ctx.scale(-1, 1);\n }\n\n ctx.drawImage(\n source,\n scaled.x,\n scaled.y,\n scaled.width,\n scaled.height,\n 0,\n 0,\n outputWidth,\n outputHeight\n );\n\n const dataUrl =\n options.format === \"jpeg\"\n ? canvas.toDataURL(\"image/jpeg\", options.jpegQuality)\n : canvas.toDataURL(\"image/png\");\n\n console.debug(\"[CameraService] ImageCapture crop applied\", {\n originalDimensions: { width, height },\n crop: scaled,\n output: { width: outputWidth, height: outputHeight },\n analysis,\n });\n\n return {\n dataUrl,\n analysis,\n method: \"imageCapture\",\n sourceDimensions: { width, height },\n cropDimensions: {\n width: scaled.width,\n height: scaled.height,\n },\n };\n } finally {\n if (source instanceof ImageBitmap && typeof source.close === \"function\") {\n source.close();\n }\n\n cleanup?.();\n }\n }\n\n private async loadCanvasSourceFromBlob(blob: Blob): Promise<CanvasSource> {\n if (typeof createImageBitmap === \"function\") {\n try {\n const bitmap = await createImageBitmap(blob, {\n imageOrientation: \"from-image\",\n } as ImageBitmapOptions);\n\n return {\n source: bitmap,\n width: bitmap.width,\n height: bitmap.height,\n cleanup: () => {\n if (typeof bitmap.close === \"function\") {\n bitmap.close();\n }\n },\n };\n } catch (error) {\n console.warn(\"createImageBitmap a échoué, fallback sur HTMLImageElement\", error);\n }\n }\n\n const objectUrl = URL.createObjectURL(blob);\n\n const image = await new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = (event) => reject(event);\n img.src = objectUrl;\n });\n\n return {\n source: image,\n width: image.naturalWidth,\n height: image.naturalHeight,\n cleanup: () => URL.revokeObjectURL(objectUrl),\n };\n }\n\n private scaleCropArea(\n cropArea: DocumentCropArea,\n ratioX: number,\n ratioY: number,\n maxWidth: number,\n maxHeight: number\n ): { x: number; y: number; width: number; height: number } {\n const scaledX = Math.max(0, Math.round(cropArea.x * ratioX));\n const scaledY = Math.max(0, Math.round(cropArea.y * ratioY));\n const scaledWidth = Math.min(\n maxWidth - scaledX,\n Math.round(cropArea.width * ratioX)\n );\n const scaledHeight = Math.min(\n maxHeight - scaledY,\n Math.round(cropArea.height * ratioY)\n );\n\n if (scaledWidth <= 0 || scaledHeight <= 0) {\n throw new Error(\"Zone de capture invalide après scaling\");\n }\n\n return {\n x: scaledX,\n y: scaledY,\n width: scaledWidth,\n height: scaledHeight,\n };\n }\n}\n\nexport const cameraService = new CameraService();\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cameraService.js","sources":["../../../../src/services/cameraService.ts"],"sourcesContent":["import type { CameraFacingMode } from \"../types/camera\";\nimport { professionalImageQuality } from \"./professionalImageQuality\";\nimport type { QualityAnalysis } from \"./professionalImageQuality\";\n\n// Permit to enable development mode to test without a camera\nconst DEV_MODE = false; // import.meta.env.DEV;\n// Default image path for development mode\nconst DEFAULT_TEST_IMAGE = \"/mock-id-card.jpeg\";\n\ntype CaptureMethod = \"imageCapture\" | \"canvas\" | \"mock\";\n\nexport interface CameraStartOptions {\n facingMode?: CameraFacingMode;\n idealResolution?: {\n width?: number;\n height?: number;\n };\n deviceId?: string;\n advancedConstraints?: MediaTrackConstraints[];\n preferImageCapture?: boolean;\n}\n\nexport interface CameraStartResult {\n success: boolean;\n error?: string;\n settings?: MediaTrackSettings;\n captureMethod?: CaptureMethod;\n}\n\nexport interface DocumentCropArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface CaptureDocumentOptions {\n facingMode?: CameraFacingMode;\n format?: \"png\" | \"jpeg\";\n jpegQuality?: number;\n preferImageCapture?: boolean;\n}\n\nexport interface CaptureDocumentResult {\n dataUrl: string;\n method: CaptureMethod;\n analysis?: QualityAnalysis;\n sourceDimensions?: { width: number; height: number };\n cropDimensions?: { width: number; height: number };\n}\n\nconst DEFAULT_RESOLUTION = {\n width: 4096,\n height: 3072,\n};\n\n// Aligned with imageProcessing.ts's MAX_WIDTH (2048): the app downsizes every\n// captured image to that width right after capture (DocumentCheck.tsx ->\n// resizeAfterCapture), so synthetically upscaling beyond it here only adds a\n// multi-second canvas encode (observed up to several seconds on mobile) for\n// pixels that get thrown away a moment later. Previously targeted 4800x3200\n// with up to 4x upscale — this caused the capture button to appear \"stuck\"\n// for a few seconds after the flash, with no real quality benefit since the\n// oversized image never survives the post-capture resize anyway.\nconst QUALITY_REQUIREMENTS = {\n minArea: 1_600_000, // ~ 1600x1000, same proportion to targetArea as before\n targetArea: 2048 * 1536,\n minLongSide: 2048,\n};\n\nconst supportsImageCapture = (): boolean =>\n typeof window !== \"undefined\" && \"ImageCapture\" in window;\n\ninterface CanvasSource {\n source: CanvasImageSource;\n width: number;\n height: number;\n cleanup?: () => void;\n}\n\nexport class CameraService {\n private stream: MediaStream | null = null;\n private videoTrack: MediaStreamTrack | null = null;\n private imageCapture: ImageCapture | null = null;\n private devMode: boolean = DEV_MODE;\n private mockImagePath: string = DEFAULT_TEST_IMAGE;\n private captureMethod: CaptureMethod = \"canvas\";\n private lastTrackSettings: MediaTrackSettings | null = null;\n private startingPromise: Promise<CameraStartResult> | null = null;\n\n private async startMockCamera(\n videoElement: HTMLVideoElement | null\n ): Promise<CameraStartResult> {\n try {\n if (!videoElement) {\n return { success: false, error: \"Élément vidéo non disponible\" };\n }\n\n const img = new Image();\n img.src = this.mockImagePath;\n\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () =>\n reject(\n new Error(`Impossible de charger l'image: ${this.mockImagePath}`)\n );\n });\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = img.width;\n canvas.height = img.height;\n const ctx = canvas.getContext(\"2d\");\n\n if (!ctx) {\n return { success: false, error: \"Contexte du canvas non disponible\" };\n }\n\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n\n const stream: MediaStream = canvas.captureStream(30);\n this.stream = stream;\n this.captureMethod = \"mock\";\n videoElement.srcObject = stream;\n\n return { success: true, captureMethod: \"mock\" };\n } catch (err) {\n console.error(\"Erreur lors de la création du flux vidéo mock:\", err);\n return {\n success: false,\n error: `Erreur lors de la création du flux vidéo mock: ${\n err instanceof Error ? err.message : String(err)\n }`,\n };\n }\n }\n\n async startCamera(\n videoElement: HTMLVideoElement | null,\n options: CameraStartOptions = {}\n ): Promise<CameraStartResult> {\n if (this.devMode) {\n return this.startMockCamera(videoElement);\n }\n\n if (!videoElement) {\n return { success: false, error: \"Élément vidéo non disponible\" };\n }\n\n if (!navigator?.mediaDevices?.getUserMedia) {\n return {\n success: false,\n error: \"La capture vidéo n'est pas supportée sur cet appareil.\",\n };\n }\n\n // Si un startCamera est déjà en cours, attendre qu'il se termine plutôt que d'en lancer un second\n if (this.startingPromise) {\n return this.startingPromise;\n }\n\n this.startingPromise = this._doStartCamera(videoElement!, options);\n try {\n return await this.startingPromise;\n } finally {\n this.startingPromise = null;\n }\n }\n\n private async _doStartCamera(\n videoElement: HTMLVideoElement,\n options: CameraStartOptions\n ): Promise<CameraStartResult> {\n const facingMode = options.facingMode ?? \"environment\";\n const preferImageCapture = options.preferImageCapture ?? true;\n const desiredWidth = options.idealResolution?.width ?? DEFAULT_RESOLUTION.width;\n const desiredHeight = options.idealResolution?.height ?? DEFAULT_RESOLUTION.height;\n\n try {\n // Close any existing stream before opening a new one\n if (this.stream) {\n this.stream.getTracks().forEach((t) => t.stop());\n this.stream = null;\n this.videoTrack = null;\n this.imageCapture = null;\n }\n\n // Ask directly for the desired resolution as an \"ideal\" constraint — the\n // browser negotiates the closest resolution the device actually supports\n // in this single call. There is no separate probe stream: opening a\n // camera stream just to read its capabilities and closing it right after\n // doubled the hardware-open latency and could trigger a second\n // permission prompt on some mobile browsers.\n const videoConstraints: MediaTrackConstraints = {\n facingMode,\n width: { ideal: desiredWidth },\n height: { ideal: desiredHeight },\n };\n\n if (options.deviceId) {\n videoConstraints.deviceId = { exact: options.deviceId };\n }\n\n if (options.advancedConstraints?.length) {\n videoConstraints.advanced = options.advancedConstraints;\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n });\n\n this.stream = stream;\n this.videoTrack = stream.getVideoTracks()[0] ?? null;\n this.lastTrackSettings = this.videoTrack?.getSettings() ?? null;\n\n console.debug(\"[CameraService] Camera opened\", {\n desired: { width: desiredWidth, height: desiredHeight },\n actual: this.lastTrackSettings,\n });\n\n // Step 3: Apply continuous autofocus via applyConstraints after stream is open.\n // Done separately so a rejection (unsupported constraint) never kills the stream.\n if (this.videoTrack) {\n try {\n await this.videoTrack.applyConstraints({\n advanced: [{ focusMode: \"continuous\" } as MediaTrackConstraints],\n });\n } catch {\n // Device doesn't support focusMode — stream stays open, autofocus just won't activate\n }\n }\n\n if (supportsImageCapture() && this.videoTrack && preferImageCapture) {\n try {\n this.imageCapture = new ImageCapture(this.videoTrack);\n this.captureMethod = \"imageCapture\";\n } catch (error) {\n console.warn(\n \"ImageCapture API indisponible, fallback sur capture canvas\",\n error\n );\n this.imageCapture = null;\n this.captureMethod = \"canvas\";\n }\n } else {\n this.imageCapture = null;\n this.captureMethod = \"canvas\";\n }\n\n videoElement.srcObject = stream;\n\n await this.waitForVideoReady(videoElement);\n\n return {\n success: true,\n settings: this.lastTrackSettings ?? undefined,\n captureMethod: this.captureMethod,\n };\n } catch (err) {\n console.error(\"Erreur lors de l'accès à la caméra:\", err);\n\n let errorMessage =\n \"Une erreur inconnue s'est produite lors de l'accès à la caméra.\";\n\n if (err instanceof DOMException) {\n if (err.name === \"NotFoundError\") {\n errorMessage = \"Aucune caméra n'a été détectée sur votre appareil.\";\n } else if (err.name === \"NotAllowedError\") {\n errorMessage =\n \"L'accès à la caméra a été refusé. Veuillez autoriser l'accès dans les paramètres de votre navigateur.\";\n } else {\n errorMessage = `Impossible d'accéder à la caméra: ${err.message}`;\n }\n }\n\n return { success: false, error: errorMessage };\n }\n }\n\n async captureDocument(\n videoElement: HTMLVideoElement | null,\n cropArea?: DocumentCropArea | null,\n options: CaptureDocumentOptions = {}\n ): Promise<CaptureDocumentResult> {\n if (!videoElement) {\n throw new Error(\"Élément vidéo requis pour capturer le document\");\n }\n\n if (!videoElement.videoWidth || !videoElement.videoHeight) {\n throw new Error(\n \"La vidéo n'est pas prête. Impossible de déterminer les dimensions.\"\n );\n }\n\n const format = options.format ?? \"jpeg\";\n const jpegQuality = options.jpegQuality ?? 0.95;\n const facingMode = options.facingMode ?? \"environment\";\n const preferImageCapture = options.preferImageCapture ?? true;\n\n const effectiveCropArea: DocumentCropArea = cropArea ?? {\n x: 0,\n y: 0,\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n };\n\n console.debug(\"[CameraService] captureDocument request\", {\n format,\n jpegQuality,\n facingMode,\n preferImageCapture,\n cropArea: effectiveCropArea,\n videoDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n });\n\n if (this.imageCapture && preferImageCapture) {\n try {\n const result = await this.captureWithImageCapture(\n videoElement,\n effectiveCropArea,\n {\n format,\n jpegQuality,\n facingMode,\n }\n );\n\n if (result) {\n console.debug(\"[CameraService] captureDocument via ImageCapture\", {\n cropArea: effectiveCropArea,\n result,\n });\n return result;\n }\n } catch (error) {\n console.warn(\n \"Capture haute résolution impossible, fallback sur capture vidéo\",\n error\n );\n }\n }\n\n const fallback = professionalImageQuality.autoEnhanceImage(\n videoElement,\n effectiveCropArea,\n {\n outputFormat: format,\n jpegQuality,\n flipHorizontal: facingMode === \"user\",\n ...QUALITY_REQUIREMENTS,\n }\n );\n\n console.debug(\"[CameraService] captureDocument via video fallback\", {\n cropArea: effectiveCropArea,\n analysis: fallback.analysis,\n method: this.captureMethod,\n sourceDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n });\n\n return {\n dataUrl: fallback.dataUrl,\n analysis: fallback.analysis,\n method: this.captureMethod,\n sourceDimensions: {\n width: videoElement.videoWidth,\n height: videoElement.videoHeight,\n },\n cropDimensions: {\n width: effectiveCropArea.width,\n height: effectiveCropArea.height,\n },\n };\n }\n\n captureFrame(\n videoElement: HTMLVideoElement | null,\n canvasElement: HTMLCanvasElement | null\n ): string | null {\n if (!videoElement || !canvasElement || !videoElement.videoWidth) {\n return null;\n }\n\n const ctx = canvasElement.getContext(\"2d\");\n if (!ctx) return null;\n\n canvasElement.width = videoElement.videoWidth;\n canvasElement.height = videoElement.videoHeight;\n\n ctx.drawImage(\n videoElement,\n 0,\n 0,\n canvasElement.width,\n canvasElement.height\n );\n\n return canvasElement.toDataURL(\"image/jpeg\");\n }\n\n stopCamera() {\n if (this.stream) {\n this.stream.getTracks().forEach((track) => track.stop());\n this.stream = null;\n }\n\n this.videoTrack = null;\n this.imageCapture = null;\n this.lastTrackSettings = null;\n this.captureMethod = this.devMode ? \"mock\" : \"canvas\";\n }\n\n setDevMode(enabled: boolean): void {\n this.devMode = enabled;\n }\n\n setMockImage(imagePath: string): void {\n this.mockImagePath = imagePath;\n }\n\n isDevModeEnabled(): boolean {\n return this.devMode;\n }\n\n getCurrentCaptureMethod(): CaptureMethod {\n return this.captureMethod;\n }\n\n private async waitForVideoReady(video: HTMLVideoElement): Promise<void> {\n // Explicitly call play() — required on some Android devices even with autoplay attribute\n try {\n await video.play();\n } catch (playError) {\n console.warn(\"[CameraService] video.play() failed, relying on autoplay\", playError);\n }\n\n if (\n video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA &&\n video.videoWidth > 0\n ) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n const TIMEOUT_MS = 5000;\n\n const onReady = () => {\n clearTimeout(timeout);\n video.removeEventListener(\"loadeddata\", onReady);\n video.removeEventListener(\"playing\", onReady);\n resolve();\n };\n\n // Listen for both events — whichever fires first\n video.addEventListener(\"loadeddata\", onReady, { once: true });\n video.addEventListener(\"playing\", onReady, { once: true });\n\n // Safety timeout to avoid hanging indefinitely\n const timeout = setTimeout(() => {\n video.removeEventListener(\"loadeddata\", onReady);\n video.removeEventListener(\"playing\", onReady);\n console.warn(\"[CameraService] waitForVideoReady timed out after\", TIMEOUT_MS, \"ms\");\n resolve();\n }, TIMEOUT_MS);\n });\n }\n\n private async captureWithImageCapture(\n videoElement: HTMLVideoElement,\n cropArea: DocumentCropArea,\n options: Required<Pick<CaptureDocumentOptions, \"format\" | \"jpegQuality\">> & {\n facingMode: CameraFacingMode;\n }\n ): Promise<CaptureDocumentResult | null> {\n if (!this.imageCapture) {\n return null;\n }\n\n // Use the actual stream resolution for takePhoto to ensure consistency\n const photoSettings: PhotoSettings = {};\n if (this.lastTrackSettings?.width && this.lastTrackSettings?.height) {\n photoSettings.imageWidth = this.lastTrackSettings.width;\n photoSettings.imageHeight = this.lastTrackSettings.height;\n console.debug(\"[CameraService] takePhoto with explicit resolution\", photoSettings);\n }\n\n const blob = await this.imageCapture.takePhoto(photoSettings);\n const { source, width, height, cleanup } = await this.loadCanvasSourceFromBlob(\n blob\n );\n\n try {\n const ratioX = width / videoElement.videoWidth;\n const ratioY = height / videoElement.videoHeight;\n\n if (!isFinite(ratioX) || !isFinite(ratioY)) {\n throw new Error(\"Ratios de capture invalides\");\n }\n\n const scaled = this.scaleCropArea(cropArea, ratioX, ratioY, width, height);\n\n const analysis = professionalImageQuality.analyzeQuality(\n scaled.width,\n scaled.height,\n QUALITY_REQUIREMENTS\n );\n\n const outputWidth = Math.max(\n 1,\n Math.round(scaled.width * analysis.recommendedScale)\n );\n const outputHeight = Math.max(\n 1,\n Math.round(scaled.height * analysis.recommendedScale)\n );\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = outputWidth;\n canvas.height = outputHeight;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Impossible de créer le contexte de rendu\");\n }\n\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n\n if (options.facingMode === \"user\") {\n ctx.translate(outputWidth, 0);\n ctx.scale(-1, 1);\n }\n\n ctx.drawImage(\n source,\n scaled.x,\n scaled.y,\n scaled.width,\n scaled.height,\n 0,\n 0,\n outputWidth,\n outputHeight\n );\n\n const dataUrl =\n options.format === \"jpeg\"\n ? canvas.toDataURL(\"image/jpeg\", options.jpegQuality)\n : canvas.toDataURL(\"image/png\");\n\n console.debug(\"[CameraService] ImageCapture crop applied\", {\n originalDimensions: { width, height },\n crop: scaled,\n output: { width: outputWidth, height: outputHeight },\n analysis,\n });\n\n return {\n dataUrl,\n analysis,\n method: \"imageCapture\",\n sourceDimensions: { width, height },\n cropDimensions: {\n width: scaled.width,\n height: scaled.height,\n },\n };\n } finally {\n if (source instanceof ImageBitmap && typeof source.close === \"function\") {\n source.close();\n }\n\n cleanup?.();\n }\n }\n\n private async loadCanvasSourceFromBlob(blob: Blob): Promise<CanvasSource> {\n if (typeof createImageBitmap === \"function\") {\n try {\n const bitmap = await createImageBitmap(blob, {\n imageOrientation: \"from-image\",\n } as ImageBitmapOptions);\n\n return {\n source: bitmap,\n width: bitmap.width,\n height: bitmap.height,\n cleanup: () => {\n if (typeof bitmap.close === \"function\") {\n bitmap.close();\n }\n },\n };\n } catch (error) {\n console.warn(\"createImageBitmap a échoué, fallback sur HTMLImageElement\", error);\n }\n }\n\n const objectUrl = URL.createObjectURL(blob);\n\n const image = await new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = (event) => reject(event);\n img.src = objectUrl;\n });\n\n return {\n source: image,\n width: image.naturalWidth,\n height: image.naturalHeight,\n cleanup: () => URL.revokeObjectURL(objectUrl),\n };\n }\n\n private scaleCropArea(\n cropArea: DocumentCropArea,\n ratioX: number,\n ratioY: number,\n maxWidth: number,\n maxHeight: number\n ): { x: number; y: number; width: number; height: number } {\n const scaledX = Math.max(0, Math.round(cropArea.x * ratioX));\n const scaledY = Math.max(0, Math.round(cropArea.y * ratioY));\n const scaledWidth = Math.min(\n maxWidth - scaledX,\n Math.round(cropArea.width * ratioX)\n );\n const scaledHeight = Math.min(\n maxHeight - scaledY,\n Math.round(cropArea.height * ratioY)\n );\n\n if (scaledWidth <= 0 || scaledHeight <= 0) {\n throw new Error(\"Zone de capture invalide après scaling\");\n }\n\n return {\n x: scaledX,\n y: scaledY,\n width: scaledWidth,\n height: scaledHeight,\n };\n }\n}\n\nexport const cameraService = new CameraService();\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { __awaiter, __generator } from '../node_modules/tslib/tslib.es6.js';
|
|
2
|
+
|
|
3
|
+
// Détection de document légère basée sur des contours (Canvas 2D), sans modèle
|
|
4
|
+
// ML externe. Remplace l'ancienne approche TensorFlow.js + coco-ssd, qui
|
|
5
|
+
// classait le document via des classes d'objets génériques ("book", "cell
|
|
6
|
+
// phone", "tv", "laptop") — peu fiable pour une CNI/passeport et coûteuse à
|
|
7
|
+
// charger (téléchargement de modèle + init WebGL), ce qui contribuait à la
|
|
8
|
+
// lenteur perçue à l'ouverture de la caméra.
|
|
9
|
+
//
|
|
10
|
+
// Le service analyse la luminosité et la netteté (variance du Laplacien, une
|
|
11
|
+
// mesure classique de flou) de la zone du cadre-guide, et en déduit un signal
|
|
12
|
+
// de présence de document ainsi qu'un indice ("hint") exploitable pour guider
|
|
13
|
+
// l'utilisateur (trop sombre / trop de reflets / rien à cadrer). Il ne bloque
|
|
14
|
+
// jamais la capture : c'est un signal d'aide, pas une porte.
|
|
15
|
+
var DETECTION_THRESHOLDS = {
|
|
16
|
+
minBrightness: 0.12,
|
|
17
|
+
maxBrightness: 0.92,
|
|
18
|
+
minSharpness: 0.08,
|
|
19
|
+
};
|
|
20
|
+
var STABILITY_WINDOW = 4; // détections positives consécutives requises avant isStable=true
|
|
21
|
+
var DETECTION_INTERVAL_MS = 200;
|
|
22
|
+
var SAMPLE_WIDTH = 64;
|
|
23
|
+
var SAMPLE_HEIGHT = 64;
|
|
24
|
+
/**
|
|
25
|
+
* Analyse pure d'une frame : luminosité moyenne + netteté (variance du
|
|
26
|
+
* Laplacien). Pas d'état, pas de dépendance DOM — facilement testable avec
|
|
27
|
+
* des buffers de pixels synthétiques.
|
|
28
|
+
*/
|
|
29
|
+
function analyzeDocumentFrame(imageData) {
|
|
30
|
+
var data = imageData.data, width = imageData.width, height = imageData.height;
|
|
31
|
+
var pixelCount = width * height;
|
|
32
|
+
var gray = new Float32Array(pixelCount);
|
|
33
|
+
var sum = 0;
|
|
34
|
+
for (var i = 0, p = 0; i < data.length; i += 4, p++) {
|
|
35
|
+
var g = (data[i] + data[i + 1] + data[i + 2]) / (3 * 255);
|
|
36
|
+
gray[p] = g;
|
|
37
|
+
sum += g;
|
|
38
|
+
}
|
|
39
|
+
var brightness = pixelCount > 0 ? sum / pixelCount : 0;
|
|
40
|
+
var laplacianAbsSum = 0;
|
|
41
|
+
var samples = 0;
|
|
42
|
+
for (var y = 1; y < height - 1; y++) {
|
|
43
|
+
for (var x = 1; x < width - 1; x++) {
|
|
44
|
+
var idx = y * width + x;
|
|
45
|
+
var laplacian = gray[idx - 1] + gray[idx + 1] + gray[idx - width] + gray[idx + width] - 4 * gray[idx];
|
|
46
|
+
laplacianAbsSum += Math.abs(laplacian);
|
|
47
|
+
samples++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var meanAbsLaplacian = samples > 0 ? laplacianAbsSum / samples : 0;
|
|
51
|
+
// Normalisation empirique : un damier noir/blanc pur (contraste maximal) donne ~4.
|
|
52
|
+
var sharpness = Math.min(1, meanAbsLaplacian / 4);
|
|
53
|
+
return { brightness: brightness, sharpness: sharpness };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Décision pure hasDocument/hint à partir des métriques de qualité. Ordre de
|
|
57
|
+
* priorité des hints : luminosité (trop sombre/trop de reflets) avant absence
|
|
58
|
+
* de contours, car une image trop sombre ou surexposée ne peut de toute façon
|
|
59
|
+
* pas révéler de contours fiables.
|
|
60
|
+
*/
|
|
61
|
+
function decideDetection(quality) {
|
|
62
|
+
if (quality.brightness < DETECTION_THRESHOLDS.minBrightness) {
|
|
63
|
+
return { hasDocument: false, hint: "too_dark" };
|
|
64
|
+
}
|
|
65
|
+
if (quality.brightness > DETECTION_THRESHOLDS.maxBrightness) {
|
|
66
|
+
return { hasDocument: false, hint: "too_bright" };
|
|
67
|
+
}
|
|
68
|
+
if (quality.sharpness < DETECTION_THRESHOLDS.minSharpness) {
|
|
69
|
+
return { hasDocument: false, hint: "no_document" };
|
|
70
|
+
}
|
|
71
|
+
return { hasDocument: true, hint: "ok" };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Échantillonneur par défaut : downscale la zone (ou toute la frame vidéo si
|
|
75
|
+
* aucune région n'est fournie) vers un petit canvas fixe, pour un coût CPU
|
|
76
|
+
* constant et faible quelle que soit la résolution source.
|
|
77
|
+
*/
|
|
78
|
+
var defaultSampleFrame = function (video, region) {
|
|
79
|
+
var _a, _b, _c, _d;
|
|
80
|
+
var sourceWidth = (_a = region === null || region === void 0 ? void 0 : region.width) !== null && _a !== void 0 ? _a : video.videoWidth;
|
|
81
|
+
var sourceHeight = (_b = region === null || region === void 0 ? void 0 : region.height) !== null && _b !== void 0 ? _b : video.videoHeight;
|
|
82
|
+
if (!sourceWidth || !sourceHeight) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
var canvas = document.createElement("canvas");
|
|
86
|
+
canvas.width = SAMPLE_WIDTH;
|
|
87
|
+
canvas.height = SAMPLE_HEIGHT;
|
|
88
|
+
var ctx = canvas.getContext("2d");
|
|
89
|
+
if (!ctx) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
ctx.drawImage(video, (_c = region === null || region === void 0 ? void 0 : region.x) !== null && _c !== void 0 ? _c : 0, (_d = region === null || region === void 0 ? void 0 : region.y) !== null && _d !== void 0 ? _d : 0, sourceWidth, sourceHeight, 0, 0, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
93
|
+
return ctx.getImageData(0, 0, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
94
|
+
};
|
|
95
|
+
var DocumentEdgeDetectionService = /** @class */ (function () {
|
|
96
|
+
function DocumentEdgeDetectionService(sampleFrame) {
|
|
97
|
+
if (sampleFrame === void 0) { sampleFrame = defaultSampleFrame; }
|
|
98
|
+
this.detectionTimeoutId = null;
|
|
99
|
+
this.stopped = true;
|
|
100
|
+
this.consecutiveMatches = 0;
|
|
101
|
+
this.lastRawHasDocument = null;
|
|
102
|
+
this.sampleFrame = sampleFrame;
|
|
103
|
+
}
|
|
104
|
+
DocumentEdgeDetectionService.prototype.startDocumentDetection = function (videoElement, region, onDetectionChange) {
|
|
105
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
106
|
+
var detect;
|
|
107
|
+
var _this = this;
|
|
108
|
+
return __generator(this, function (_a) {
|
|
109
|
+
this.stopDocumentDetection();
|
|
110
|
+
this.stopped = false;
|
|
111
|
+
this.consecutiveMatches = 0;
|
|
112
|
+
this.lastRawHasDocument = null;
|
|
113
|
+
detect = function () {
|
|
114
|
+
if (_this.stopped) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!videoElement || !videoElement.videoWidth) {
|
|
118
|
+
_this.scheduleNext(detect);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
var imageData;
|
|
122
|
+
try {
|
|
123
|
+
imageData = _this.sampleFrame(videoElement, region);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.error("[DocumentEdgeDetection] Error sampling frame:", error);
|
|
127
|
+
_this.scheduleNext(detect);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!imageData) {
|
|
131
|
+
_this.scheduleNext(detect);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
var quality = analyzeDocumentFrame(imageData);
|
|
135
|
+
var _a = decideDetection(quality), hasDocument = _a.hasDocument, hint = _a.hint;
|
|
136
|
+
if (hasDocument && _this.lastRawHasDocument) {
|
|
137
|
+
_this.consecutiveMatches += 1;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
_this.consecutiveMatches = hasDocument ? 1 : 0;
|
|
141
|
+
}
|
|
142
|
+
_this.lastRawHasDocument = hasDocument;
|
|
143
|
+
var isStable = hasDocument && _this.consecutiveMatches >= STABILITY_WINDOW;
|
|
144
|
+
onDetectionChange({
|
|
145
|
+
hasDocument: hasDocument,
|
|
146
|
+
isStable: isStable,
|
|
147
|
+
hint: hint,
|
|
148
|
+
quality: quality,
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
});
|
|
151
|
+
_this.scheduleNext(detect);
|
|
152
|
+
};
|
|
153
|
+
detect();
|
|
154
|
+
return [2 /*return*/, { stop: function () { return _this.stopDocumentDetection(); } }];
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
DocumentEdgeDetectionService.prototype.stopDocumentDetection = function () {
|
|
159
|
+
this.stopped = true;
|
|
160
|
+
if (this.detectionTimeoutId) {
|
|
161
|
+
clearTimeout(this.detectionTimeoutId);
|
|
162
|
+
this.detectionTimeoutId = null;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
DocumentEdgeDetectionService.prototype.scheduleNext = function (callback) {
|
|
166
|
+
if (this.detectionTimeoutId) {
|
|
167
|
+
clearTimeout(this.detectionTimeoutId);
|
|
168
|
+
}
|
|
169
|
+
this.detectionTimeoutId = window.setTimeout(callback, DETECTION_INTERVAL_MS);
|
|
170
|
+
};
|
|
171
|
+
return DocumentEdgeDetectionService;
|
|
172
|
+
}());
|
|
173
|
+
var documentEdgeDetectionService = new DocumentEdgeDetectionService();
|
|
174
|
+
|
|
175
|
+
export { DETECTION_THRESHOLDS, DocumentEdgeDetectionService, analyzeDocumentFrame, decideDetection, documentEdgeDetectionService };
|
|
176
|
+
//# sourceMappingURL=documentEdgeDetectionService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentEdgeDetectionService.js","sources":["../../../../src/services/documentEdgeDetectionService.ts"],"sourcesContent":["// Détection de document légère basée sur des contours (Canvas 2D), sans modèle\n// ML externe. Remplace l'ancienne approche TensorFlow.js + coco-ssd, qui\n// classait le document via des classes d'objets génériques (\"book\", \"cell\n// phone\", \"tv\", \"laptop\") — peu fiable pour une CNI/passeport et coûteuse à\n// charger (téléchargement de modèle + init WebGL), ce qui contribuait à la\n// lenteur perçue à l'ouverture de la caméra.\n//\n// Le service analyse la luminosité et la netteté (variance du Laplacien, une\n// mesure classique de flou) de la zone du cadre-guide, et en déduit un signal\n// de présence de document ainsi qu'un indice (\"hint\") exploitable pour guider\n// l'utilisateur (trop sombre / trop de reflets / rien à cadrer). Il ne bloque\n// jamais la capture : c'est un signal d'aide, pas une porte.\n\nexport interface ImageDataLike {\n data: Uint8ClampedArray;\n width: number;\n height: number;\n}\n\nexport interface DetectionRegion {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport type DocumentDetectionHint = \"too_dark\" | \"too_bright\" | \"no_document\" | \"ok\";\n\nexport interface DocumentQuality {\n brightness: number; // 0..1\n sharpness: number; // 0..1 (normalisé)\n}\n\nexport interface DocumentDetectionResult {\n hasDocument: boolean;\n isStable: boolean;\n hint: DocumentDetectionHint;\n quality: DocumentQuality;\n timestamp: number;\n}\n\nexport type FrameSampler = (\n video: HTMLVideoElement,\n region: DetectionRegion | null\n) => ImageDataLike | null;\n\nexport const DETECTION_THRESHOLDS = {\n minBrightness: 0.12,\n maxBrightness: 0.92,\n minSharpness: 0.08,\n};\n\nconst STABILITY_WINDOW = 4; // détections positives consécutives requises avant isStable=true\nconst DETECTION_INTERVAL_MS = 200;\nconst SAMPLE_WIDTH = 64;\nconst SAMPLE_HEIGHT = 64;\n\n/**\n * Analyse pure d'une frame : luminosité moyenne + netteté (variance du\n * Laplacien). Pas d'état, pas de dépendance DOM — facilement testable avec\n * des buffers de pixels synthétiques.\n */\nexport function analyzeDocumentFrame(imageData: ImageDataLike): DocumentQuality {\n const { data, width, height } = imageData;\n const pixelCount = width * height;\n\n const gray = new Float32Array(pixelCount);\n let sum = 0;\n for (let i = 0, p = 0; i < data.length; i += 4, p++) {\n const g = (data[i] + data[i + 1] + data[i + 2]) / (3 * 255);\n gray[p] = g;\n sum += g;\n }\n const brightness = pixelCount > 0 ? sum / pixelCount : 0;\n\n let laplacianAbsSum = 0;\n let samples = 0;\n for (let y = 1; y < height - 1; y++) {\n for (let x = 1; x < width - 1; x++) {\n const idx = y * width + x;\n const laplacian =\n gray[idx - 1] + gray[idx + 1] + gray[idx - width] + gray[idx + width] - 4 * gray[idx];\n laplacianAbsSum += Math.abs(laplacian);\n samples++;\n }\n }\n const meanAbsLaplacian = samples > 0 ? laplacianAbsSum / samples : 0;\n // Normalisation empirique : un damier noir/blanc pur (contraste maximal) donne ~4.\n const sharpness = Math.min(1, meanAbsLaplacian / 4);\n\n return { brightness, sharpness };\n}\n\n/**\n * Décision pure hasDocument/hint à partir des métriques de qualité. Ordre de\n * priorité des hints : luminosité (trop sombre/trop de reflets) avant absence\n * de contours, car une image trop sombre ou surexposée ne peut de toute façon\n * pas révéler de contours fiables.\n */\nexport function decideDetection(\n quality: DocumentQuality\n): { hasDocument: boolean; hint: DocumentDetectionHint } {\n if (quality.brightness < DETECTION_THRESHOLDS.minBrightness) {\n return { hasDocument: false, hint: \"too_dark\" };\n }\n if (quality.brightness > DETECTION_THRESHOLDS.maxBrightness) {\n return { hasDocument: false, hint: \"too_bright\" };\n }\n if (quality.sharpness < DETECTION_THRESHOLDS.minSharpness) {\n return { hasDocument: false, hint: \"no_document\" };\n }\n return { hasDocument: true, hint: \"ok\" };\n}\n\n/**\n * Échantillonneur par défaut : downscale la zone (ou toute la frame vidéo si\n * aucune région n'est fournie) vers un petit canvas fixe, pour un coût CPU\n * constant et faible quelle que soit la résolution source.\n */\nconst defaultSampleFrame: FrameSampler = (video, region) => {\n const sourceWidth = region?.width ?? video.videoWidth;\n const sourceHeight = region?.height ?? video.videoHeight;\n if (!sourceWidth || !sourceHeight) {\n return null;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = SAMPLE_WIDTH;\n canvas.height = SAMPLE_HEIGHT;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return null;\n }\n\n ctx.drawImage(\n video,\n region?.x ?? 0,\n region?.y ?? 0,\n sourceWidth,\n sourceHeight,\n 0,\n 0,\n SAMPLE_WIDTH,\n SAMPLE_HEIGHT\n );\n\n return ctx.getImageData(0, 0, SAMPLE_WIDTH, SAMPLE_HEIGHT);\n};\n\nexport class DocumentEdgeDetectionService {\n private detectionTimeoutId: number | null = null;\n private stopped = true;\n private consecutiveMatches = 0;\n private lastRawHasDocument: boolean | null = null;\n private readonly sampleFrame: FrameSampler;\n\n constructor(sampleFrame: FrameSampler = defaultSampleFrame) {\n this.sampleFrame = sampleFrame;\n }\n\n async startDocumentDetection(\n videoElement: HTMLVideoElement | null,\n region: DetectionRegion | null,\n onDetectionChange: (result: DocumentDetectionResult) => void\n ): Promise<{ stop: () => void }> {\n this.stopDocumentDetection();\n this.stopped = false;\n this.consecutiveMatches = 0;\n this.lastRawHasDocument = null;\n\n const detect = () => {\n if (this.stopped) {\n return;\n }\n\n if (!videoElement || !videoElement.videoWidth) {\n this.scheduleNext(detect);\n return;\n }\n\n let imageData: ImageDataLike | null;\n try {\n imageData = this.sampleFrame(videoElement, region);\n } catch (error) {\n console.error(\"[DocumentEdgeDetection] Error sampling frame:\", error);\n this.scheduleNext(detect);\n return;\n }\n\n if (!imageData) {\n this.scheduleNext(detect);\n return;\n }\n\n const quality = analyzeDocumentFrame(imageData);\n const { hasDocument, hint } = decideDetection(quality);\n\n if (hasDocument && this.lastRawHasDocument) {\n this.consecutiveMatches += 1;\n } else {\n this.consecutiveMatches = hasDocument ? 1 : 0;\n }\n this.lastRawHasDocument = hasDocument;\n\n const isStable = hasDocument && this.consecutiveMatches >= STABILITY_WINDOW;\n\n onDetectionChange({\n hasDocument,\n isStable,\n hint,\n quality,\n timestamp: Date.now(),\n });\n\n this.scheduleNext(detect);\n };\n\n detect();\n\n return { stop: () => this.stopDocumentDetection() };\n }\n\n stopDocumentDetection() {\n this.stopped = true;\n if (this.detectionTimeoutId) {\n clearTimeout(this.detectionTimeoutId);\n this.detectionTimeoutId = null;\n }\n }\n\n private scheduleNext(callback: () => void) {\n if (this.detectionTimeoutId) {\n clearTimeout(this.detectionTimeoutId);\n }\n this.detectionTimeoutId = window.setTimeout(callback, DETECTION_INTERVAL_MS);\n }\n}\n\nexport const documentEdgeDetectionService = new DocumentEdgeDetectionService();\n"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,22 @@ var isS3UploadNotConfirmedError = function (error) {
|
|
|
14
14
|
return (apiError.details.code ===
|
|
15
15
|
S3_UPLOAD_NOT_CONFIRMED_CODE);
|
|
16
16
|
};
|
|
17
|
+
// Must stay aligned with QUOTA_EXCEEDED_CODE in the backend
|
|
18
|
+
// (src/common/constants/quota-exceeded.constant.ts).
|
|
19
|
+
var QUOTA_EXCEEDED_CODE = "QUOTA_EXCEEDED";
|
|
20
|
+
var isQuotaExceededError = function (error) {
|
|
21
|
+
if (typeof error !== "object" || error === null) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
var apiError = error;
|
|
25
|
+
if (apiError.code === QUOTA_EXCEEDED_CODE) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (typeof apiError.details !== "object" || apiError.details === null) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return (apiError.details.code === QUOTA_EXCEEDED_CODE);
|
|
32
|
+
};
|
|
17
33
|
|
|
18
|
-
export { S3_UPLOAD_NOT_CONFIRMED_CODE, isS3UploadNotConfirmedError };
|
|
34
|
+
export { QUOTA_EXCEEDED_CODE, S3_UPLOAD_NOT_CONFIRMED_CODE, isQuotaExceededError, isS3UploadNotConfirmedError };
|
|
19
35
|
//# sourceMappingURL=analysisErrors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysisErrors.js","sources":["../../../../src/utils/analysisErrors.ts"],"sourcesContent":["// Must stay aligned with the public error code returned by the backend AnalysisService.\nexport const S3_UPLOAD_NOT_CONFIRMED_CODE = \"S3_UPLOAD_NOT_CONFIRMED\";\n\nexport const isS3UploadNotConfirmedError = (error: unknown): boolean => {\n if (typeof error !== \"object\" || error === null) {\n return false;\n }\n\n const apiError = error as { code?: unknown; details?: unknown };\n if (apiError.code === S3_UPLOAD_NOT_CONFIRMED_CODE) {\n return true;\n }\n\n if (typeof apiError.details !== \"object\" || apiError.details === null) {\n return false;\n }\n\n return (\n (apiError.details as { code?: unknown }).code ===\n S3_UPLOAD_NOT_CONFIRMED_CODE\n );\n};\n"],"names":[],"mappings":"AAAA;AACO,IAAM,4BAA4B,GAAG;AAErC,IAAM,2BAA2B,GAAG,UAAC,KAAc,EAAA;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;AAC/C,QAAA,OAAO,KAAK;IACd;IAEA,IAAM,QAAQ,GAAG,KAA8C;AAC/D,IAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,4BAA4B,EAAE;AAClD,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE;AACrE,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,QACG,QAAQ,CAAC,OAA8B,CAAC,IAAI;AAC7C,QAAA,4BAA4B;AAEhC;;;;"}
|
|
1
|
+
{"version":3,"file":"analysisErrors.js","sources":["../../../../src/utils/analysisErrors.ts"],"sourcesContent":["// Must stay aligned with the public error code returned by the backend AnalysisService.\nexport const S3_UPLOAD_NOT_CONFIRMED_CODE = \"S3_UPLOAD_NOT_CONFIRMED\";\n\nexport const isS3UploadNotConfirmedError = (error: unknown): boolean => {\n if (typeof error !== \"object\" || error === null) {\n return false;\n }\n\n const apiError = error as { code?: unknown; details?: unknown };\n if (apiError.code === S3_UPLOAD_NOT_CONFIRMED_CODE) {\n return true;\n }\n\n if (typeof apiError.details !== \"object\" || apiError.details === null) {\n return false;\n }\n\n return (\n (apiError.details as { code?: unknown }).code ===\n S3_UPLOAD_NOT_CONFIRMED_CODE\n );\n};\n\n// Must stay aligned with QUOTA_EXCEEDED_CODE in the backend\n// (src/common/constants/quota-exceeded.constant.ts).\nexport const QUOTA_EXCEEDED_CODE = \"QUOTA_EXCEEDED\";\n\nexport const isQuotaExceededError = (error: unknown): boolean => {\n if (typeof error !== \"object\" || error === null) {\n return false;\n }\n\n const apiError = error as { code?: unknown; details?: unknown };\n if (apiError.code === QUOTA_EXCEEDED_CODE) {\n return true;\n }\n\n if (typeof apiError.details !== \"object\" || apiError.details === null) {\n return false;\n }\n\n return (\n (apiError.details as { code?: unknown }).code === QUOTA_EXCEEDED_CODE\n );\n};\n"],"names":[],"mappings":"AAAA;AACO,IAAM,4BAA4B,GAAG;AAErC,IAAM,2BAA2B,GAAG,UAAC,KAAc,EAAA;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;AAC/C,QAAA,OAAO,KAAK;IACd;IAEA,IAAM,QAAQ,GAAG,KAA8C;AAC/D,IAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,4BAA4B,EAAE;AAClD,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE;AACrE,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,QACG,QAAQ,CAAC,OAA8B,CAAC,IAAI;AAC7C,QAAA,4BAA4B;AAEhC;AAEA;AACA;AACO,IAAM,mBAAmB,GAAG;AAE5B,IAAM,oBAAoB,GAAG,UAAC,KAAc,EAAA;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE;AAC/C,QAAA,OAAO,KAAK;IACd;IAEA,IAAM,QAAQ,GAAG,KAA8C;AAC/D,IAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,mBAAmB,EAAE;AACzC,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE;AACrE,QAAA,OAAO,KAAK;IACd;IAEA,QACG,QAAQ,CAAC,OAA8B,CAAC,IAAI,KAAK,mBAAmB;AAEzE;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"languageFlags.js","sources":["../../../../src/utils/languageFlags.ts"],"sourcesContent":["/**\n * Language flag mapping utility\n * Maps language codes to their corresponding country flags\n */\nexport interface LanguageFlag {\n code: string;\n name: string;\n alpha2: string;\n nativeName: string;\n}\n\n/**\n * Mapping of language codes to country flags and names\n */\nexport const LANGUAGE_FLAGS: Record<string, LanguageFlag> = {\n fr: {\n code: 'fr',\n name: 'French',\n alpha2: 'fr',\n nativeName: 'Français'\n },\n en: {\n code: 'en',\n name: 'English',\n alpha2: 'gb',\n nativeName: 'English'\n }\n};\n\n/**\n * Get flag for a language code\n * @param languageCode - The language code (e.g., 'fr', 'en')\n * @returns The flag emoji or empty string if not found\n*/\nexport const getLanguageAlpha2 = (languageCode: string): string | null => {\n return LANGUAGE_FLAGS[languageCode]?.alpha2;\n};\n\n/**\n * Get language info for a language code\n * @param languageCode - The language code (e.g., 'fr', 'en')\n * @returns The language flag info or null if not found\n */\nexport const getLanguageInfo = (languageCode: string): LanguageFlag | null => {\n return LANGUAGE_FLAGS[languageCode] || null;\n};\n\n/**\n * Get all supported languages with their flags\n * @returns Array of all supported language flags\n */\nexport const getSupportedLanguages = (): LanguageFlag[] => {\n return Object.values(LANGUAGE_FLAGS);\n};\n\n/**\n * Check if a language code is supported\n * @param languageCode - The language code to check\n * @returns True if the language is supported\n */\nexport const isLanguageSupported = (languageCode: string): boolean => {\n return languageCode in LANGUAGE_FLAGS;\n}
|
|
1
|
+
{"version":3,"file":"languageFlags.js","sources":["../../../../src/utils/languageFlags.ts"],"sourcesContent":["/**\n * Language flag mapping utility\n * Maps language codes to their corresponding country flags\n */\nexport interface LanguageFlag {\n code: string;\n name: string;\n alpha2: string;\n nativeName: string;\n}\n\n/**\n * Mapping of language codes to country flags and names\n */\nexport const LANGUAGE_FLAGS: Record<string, LanguageFlag> = {\n fr: {\n code: 'fr',\n name: 'French',\n alpha2: 'fr',\n nativeName: 'Français'\n },\n en: {\n code: 'en',\n name: 'English',\n alpha2: 'gb',\n nativeName: 'English'\n },\n es: {\n code: 'es',\n name: 'Spanish',\n alpha2: 'es',\n nativeName: 'Español'\n }\n};\n\n/**\n * Get flag for a language code\n * @param languageCode - The language code (e.g., 'fr', 'en')\n * @returns The flag emoji or empty string if not found\n*/\nexport const getLanguageAlpha2 = (languageCode: string): string | null => {\n return LANGUAGE_FLAGS[languageCode]?.alpha2;\n};\n\n/**\n * Get language info for a language code\n * @param languageCode - The language code (e.g., 'fr', 'en')\n * @returns The language flag info or null if not found\n */\nexport const getLanguageInfo = (languageCode: string): LanguageFlag | null => {\n return LANGUAGE_FLAGS[languageCode] || null;\n};\n\n/**\n * Get all supported languages with their flags\n * @returns Array of all supported language flags\n */\nexport const getSupportedLanguages = (): LanguageFlag[] => {\n return Object.values(LANGUAGE_FLAGS);\n};\n\n/**\n * Check if a language code is supported\n * @param languageCode - The language code to check\n * @returns True if the language is supported\n */\nexport const isLanguageSupported = (languageCode: string): boolean => {\n return languageCode in LANGUAGE_FLAGS;\n};\n"],"names":[],"mappings":"AAWA;;AAEG;AACI,IAAM,cAAc,GAAiC;AAC1D,IAAA,EAAE,EAAE;AACF,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,UAAU,EAAE;AACb,KAAA;AACD,IAAA,EAAE,EAAE;AACF,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,UAAU,EAAE;AACb,KAAA;AACD,IAAA,EAAE,EAAE;AACF,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,UAAU,EAAE;AACb;;AAGH;;;;AAIE;AACK,IAAM,iBAAiB,GAAG,UAAC,YAAoB,EAAA;;AAClD,IAAA,OAAO,MAAA,cAAc,CAAC,YAAY,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAE,MAAM;AAC/C;AAWA;;;AAGG;AACI,IAAM,qBAAqB,GAAG,YAAA;AACnC,IAAA,OAAO,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;AACtC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datakeen-session-react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.194-rc.1",
|
|
4
4
|
"description": "React SDK component to manage and render Datakeen session experiences easily.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -100,9 +100,6 @@
|
|
|
100
100
|
"@radix-ui/react-label": "^2.1.6",
|
|
101
101
|
"@radix-ui/react-popover": "^1.1.15",
|
|
102
102
|
"@radix-ui/react-select": "^2.2.5",
|
|
103
|
-
"@tensorflow-models/coco-ssd": "^2.2.3",
|
|
104
|
-
"@tensorflow/tfjs": "^4.22.0",
|
|
105
|
-
"@tensorflow/tfjs-backend-webgl": "^4.22.0",
|
|
106
103
|
"@testing-library/dom": "^8.20.0",
|
|
107
104
|
"@unissey-web/sdk-react": "^4.4.0",
|
|
108
105
|
"clsx": "^2.1.1",
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var tslib_es6 = require('../node_modules/tslib/tslib.es6.js');
|
|
4
|
-
|
|
5
|
-
var DocumentDetectionService = /** @class */ (function () {
|
|
6
|
-
function DocumentDetectionService() {
|
|
7
|
-
this.detectionTimeoutId = null;
|
|
8
|
-
this.model = null;
|
|
9
|
-
this.isDetecting = false;
|
|
10
|
-
this.lastResult = null;
|
|
11
|
-
this.DETECTION_INTERVAL_MS = 350;
|
|
12
|
-
}
|
|
13
|
-
DocumentDetectionService.prototype.loadModel = function () {
|
|
14
|
-
return tslib_es6.__awaiter(this, void 0, void 0, function () {
|
|
15
|
-
var tf, cocoSsd, _a;
|
|
16
|
-
return tslib_es6.__generator(this, function (_b) {
|
|
17
|
-
switch (_b.label) {
|
|
18
|
-
case 0:
|
|
19
|
-
if (!!this.model) return [3 /*break*/, 7];
|
|
20
|
-
return [4 /*yield*/, import('@tensorflow/tfjs')];
|
|
21
|
-
case 1:
|
|
22
|
-
tf = _b.sent();
|
|
23
|
-
return [4 /*yield*/, import('@tensorflow/tfjs-backend-webgl')];
|
|
24
|
-
case 2:
|
|
25
|
-
_b.sent();
|
|
26
|
-
return [4 /*yield*/, import('@tensorflow-models/coco-ssd')];
|
|
27
|
-
case 3:
|
|
28
|
-
cocoSsd = _b.sent();
|
|
29
|
-
return [4 /*yield*/, tf.setBackend("webgl")];
|
|
30
|
-
case 4:
|
|
31
|
-
_b.sent();
|
|
32
|
-
return [4 /*yield*/, tf.ready()];
|
|
33
|
-
case 5:
|
|
34
|
-
_b.sent();
|
|
35
|
-
_a = this;
|
|
36
|
-
return [4 /*yield*/, cocoSsd.load()];
|
|
37
|
-
case 6:
|
|
38
|
-
_a.model = _b.sent();
|
|
39
|
-
_b.label = 7;
|
|
40
|
-
case 7: return [2 /*return*/];
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
|
-
DocumentDetectionService.prototype.startDocumentDetection = function (videoElement, onDetectionChange) {
|
|
46
|
-
return tslib_es6.__awaiter(this, void 0, void 0, function () {
|
|
47
|
-
var detect;
|
|
48
|
-
var _this = this;
|
|
49
|
-
return tslib_es6.__generator(this, function (_a) {
|
|
50
|
-
switch (_a.label) {
|
|
51
|
-
case 0:
|
|
52
|
-
this.stopDocumentDetection();
|
|
53
|
-
return [4 /*yield*/, this.loadModel()];
|
|
54
|
-
case 1:
|
|
55
|
-
_a.sent();
|
|
56
|
-
detect = function () { return tslib_es6.__awaiter(_this, void 0, void 0, function () {
|
|
57
|
-
var predictions, documentLike, result, err_1;
|
|
58
|
-
return tslib_es6.__generator(this, function (_a) {
|
|
59
|
-
switch (_a.label) {
|
|
60
|
-
case 0:
|
|
61
|
-
if (!videoElement || !this.model || !videoElement.videoWidth) {
|
|
62
|
-
this.scheduleNextDetection(detect);
|
|
63
|
-
return [2 /*return*/];
|
|
64
|
-
}
|
|
65
|
-
if (this.isDetecting) {
|
|
66
|
-
this.scheduleNextDetection(detect);
|
|
67
|
-
return [2 /*return*/];
|
|
68
|
-
}
|
|
69
|
-
this.isDetecting = true;
|
|
70
|
-
_a.label = 1;
|
|
71
|
-
case 1:
|
|
72
|
-
_a.trys.push([1, 3, 4, 5]);
|
|
73
|
-
return [4 /*yield*/, this.model.detect(videoElement)];
|
|
74
|
-
case 2:
|
|
75
|
-
predictions = _a.sent();
|
|
76
|
-
documentLike = predictions.find(function (pred) {
|
|
77
|
-
return ["book", "cell phone", "tv", "laptop"].includes(pred.class) &&
|
|
78
|
-
pred.score > 0.6;
|
|
79
|
-
});
|
|
80
|
-
result = documentLike
|
|
81
|
-
? {
|
|
82
|
-
hasDocument: true,
|
|
83
|
-
score: documentLike.score,
|
|
84
|
-
label: documentLike.class,
|
|
85
|
-
bbox: documentLike.bbox,
|
|
86
|
-
timestamp: Date.now(),
|
|
87
|
-
}
|
|
88
|
-
: {
|
|
89
|
-
hasDocument: false,
|
|
90
|
-
timestamp: Date.now(),
|
|
91
|
-
};
|
|
92
|
-
if (this.shouldEmitResult(result)) {
|
|
93
|
-
onDetectionChange(result);
|
|
94
|
-
this.lastResult = result;
|
|
95
|
-
}
|
|
96
|
-
return [3 /*break*/, 5];
|
|
97
|
-
case 3:
|
|
98
|
-
err_1 = _a.sent();
|
|
99
|
-
console.error("[DocumentDetection] Error during detection:", err_1);
|
|
100
|
-
return [3 /*break*/, 5];
|
|
101
|
-
case 4:
|
|
102
|
-
this.isDetecting = false;
|
|
103
|
-
this.scheduleNextDetection(detect);
|
|
104
|
-
return [7 /*endfinally*/];
|
|
105
|
-
case 5: return [2 /*return*/];
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}); };
|
|
109
|
-
detect();
|
|
110
|
-
return [2 /*return*/, {
|
|
111
|
-
stop: function () { return _this.stopDocumentDetection(); },
|
|
112
|
-
}];
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
};
|
|
117
|
-
DocumentDetectionService.prototype.stopDocumentDetection = function () {
|
|
118
|
-
if (this.detectionTimeoutId) {
|
|
119
|
-
clearTimeout(this.detectionTimeoutId);
|
|
120
|
-
this.detectionTimeoutId = null;
|
|
121
|
-
}
|
|
122
|
-
this.isDetecting = false;
|
|
123
|
-
this.lastResult = null;
|
|
124
|
-
};
|
|
125
|
-
DocumentDetectionService.prototype.shouldEmitResult = function (result) {
|
|
126
|
-
if (!this.lastResult) {
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
if (this.lastResult.hasDocument !== result.hasDocument) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
if (!result.hasDocument) {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
if (!this.lastResult.bbox || !result.bbox) {
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
var _a = this.lastResult.bbox, x1 = _a[0], y1 = _a[1], w1 = _a[2], h1 = _a[3];
|
|
139
|
-
var _b = result.bbox, x2 = _b[0], y2 = _b[1], w2 = _b[2], h2 = _b[3];
|
|
140
|
-
var delta = Math.abs(x1 - x2) + Math.abs(y1 - y2);
|
|
141
|
-
var sizeDelta = Math.abs(w1 - w2) + Math.abs(h1 - h2);
|
|
142
|
-
return delta > 10 || sizeDelta > 10;
|
|
143
|
-
};
|
|
144
|
-
DocumentDetectionService.prototype.scheduleNextDetection = function (callback) {
|
|
145
|
-
if (this.detectionTimeoutId) {
|
|
146
|
-
clearTimeout(this.detectionTimeoutId);
|
|
147
|
-
}
|
|
148
|
-
this.detectionTimeoutId = window.setTimeout(callback, this.DETECTION_INTERVAL_MS);
|
|
149
|
-
};
|
|
150
|
-
return DocumentDetectionService;
|
|
151
|
-
}());
|
|
152
|
-
var documentDetectionService = new DocumentDetectionService();
|
|
153
|
-
|
|
154
|
-
exports.DocumentDetectionService = DocumentDetectionService;
|
|
155
|
-
exports.documentDetectionService = documentDetectionService;
|
|
156
|
-
//# sourceMappingURL=documentDetectionService.js.map
|