@jaak.ai/stamps 2.0.0-dev.40 → 2.0.0-dev.41

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.
Files changed (43) hide show
  1. package/README.md +4 -1
  2. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
  3. package/dist/cjs/jaak-stamps.cjs.entry.js +868 -11
  4. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  5. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/collection/components/my-component/my-component.css +66 -0
  8. package/dist/collection/components/my-component/my-component.js +494 -8
  9. package/dist/collection/components/my-component/my-component.js.map +1 -1
  10. package/dist/collection/services/CameraService.js +161 -0
  11. package/dist/collection/services/CameraService.js.map +1 -1
  12. package/dist/collection/services/DetectionService.js +164 -1
  13. package/dist/collection/services/DetectionService.js.map +1 -1
  14. package/dist/collection/services/ImageQualityService.js +329 -0
  15. package/dist/collection/services/ImageQualityService.js.map +1 -0
  16. package/dist/collection/services/ServiceContainer.js +6 -1
  17. package/dist/collection/services/ServiceContainer.js.map +1 -1
  18. package/dist/collection/services/interfaces/ICameraService.js.map +1 -1
  19. package/dist/collection/services/interfaces/IDetectionService.js.map +1 -1
  20. package/dist/collection/services/interfaces/IImageQualityService.js +2 -0
  21. package/dist/collection/services/interfaces/IImageQualityService.js.map +1 -0
  22. package/dist/components/jaak-stamps.js +885 -12
  23. package/dist/components/jaak-stamps.js.map +1 -1
  24. package/dist/esm/jaak-stamps-webcomponent.js +1 -1
  25. package/dist/esm/jaak-stamps.entry.js +868 -11
  26. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  27. package/dist/esm/loader.js +1 -1
  28. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  29. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  30. package/dist/jaak-stamps-webcomponent/p-47f37982.entry.js +2 -0
  31. package/dist/jaak-stamps-webcomponent/p-47f37982.entry.js.map +1 -0
  32. package/dist/types/components/my-component/my-component.d.ts +48 -0
  33. package/dist/types/components.d.ts +65 -0
  34. package/dist/types/services/CameraService.d.ts +5 -0
  35. package/dist/types/services/DetectionService.d.ts +22 -2
  36. package/dist/types/services/ImageQualityService.d.ts +31 -0
  37. package/dist/types/services/ServiceContainer.d.ts +7 -0
  38. package/dist/types/services/interfaces/ICameraService.d.ts +2 -0
  39. package/dist/types/services/interfaces/IDetectionService.d.ts +13 -0
  40. package/dist/types/services/interfaces/IImageQualityService.d.ts +58 -0
  41. package/package.json +1 -1
  42. package/dist/jaak-stamps-webcomponent/p-c30c7b47.entry.js +0 -2
  43. package/dist/jaak-stamps-webcomponent/p-c30c7b47.entry.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DetectionService.js","sourceRoot":"","sources":["../../src/services/DetectionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { IDetectionService, DetectionBox, SideAlignment, ClassificationResult } from './interfaces/IDetectionService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IDeviceStrategy } from './strategies/IDeviceStrategy';\nimport { DeviceStrategyFactory } from './factories/DeviceStrategyFactory';\n\nexport class DetectionService implements IDetectionService {\n private session?: any;\n private mobileNetSession?: any;\n private mobileNetClassMap?: any;\n private modelLoaded: boolean = false;\n private deviceStrategy: IDeviceStrategy;\n \n private readonly MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx\";\n private readonly MOBILENET_MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx\";\n private readonly MOBILENET_CLASSES_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json\";\n private readonly INPUT_SIZE = 320;\n private readonly CONFIDENCE_THRESHOLD = 0.6;\n\n // Canvas pool for optimization\n private preprocessCanvas?: HTMLCanvasElement;\n private preprocessCtx?: CanvasRenderingContext2D;\n private captureCanvas?: HTMLCanvasElement;\n\n constructor(\n private logger: ILogger,\n private debug: boolean = false,\n private useDocumentClassification: boolean = false\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n this.logger.state('MODELO_YA_PRECARGADO', { \n sessionExists: !!this.session, \n modelPreloaded: this.modelLoaded \n });\n return;\n }\n\n try {\n this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });\n \n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n \n try {\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n \n this.modelLoaded = true;\n this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });\n } catch (error) {\n this.logger.error('Error al precargar modelo de detección:', error);\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });\n \n // Load class map\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);\n if (!classResponse.ok) {\n throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);\n }\n this.mobileNetClassMap = await classResponse.json();\n this.logger.state('CLASES_MOBILENET_CARGADAS', { \n classCount: Object.keys(this.mobileNetClassMap).length \n });\n \n // Load model\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n try {\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { \n sessionCreated: !!this.mobileNetSession \n });\n \n } catch (error) {\n this.logger.error('Error al cargar modelo MobileNet:', error);\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\n return this.modelLoaded && !!this.session;\n }\n\n preprocess(video: HTMLVideoElement): any {\n if (!this.preprocessCanvas || !this.preprocessCtx) {\n this.initializeCanvasPool();\n }\n \n this.preprocessCtx!.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n this.preprocessCtx!.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n \n const imageData = this.preprocessCtx!.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n const [R, G, B] = [[], [], []] as number[][];\n const { data } = imageData;\n\n for (let i = 0; i < data.length; i += 4) {\n R.push(data[i] / 255);\n G.push(data[i + 1] / 255);\n B.push(data[i + 2] / 255);\n }\n\n const transposedData = new Float32Array(R.concat(G, B));\n const float16Data = new Uint16Array(transposedData.length);\n for (let i = 0; i < transposedData.length; i++) {\n float16Data[i] = this.float32ToFloat16(transposedData[i]);\n }\n return new (window as any).ort.Tensor(\"float16\", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);\n }\n\n async runInference(inputTensor: any): Promise<DetectionBox[]> {\n if (!this.session) {\n throw new Error('Detection model not loaded');\n }\n\n const feeds = { [this.session.inputNames[0]]: inputTensor };\n const results = await this.session.run(feeds);\n const output = results[this.session.outputNames[0]].data;\n\n const detections: DetectionBox[] = [];\n for (let i = 0; i < output.length; i += 6) {\n const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);\n if (score > this.CONFIDENCE_THRESHOLD) {\n detections.push({ \n x: x1, \n y: y1, \n w: x2 - x1, \n h: y2 - y1, \n score, \n classId \n });\n }\n }\n\n return detections;\n }\n\n async classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null> {\n if (!this.mobileNetSession || !this.mobileNetClassMap) {\n this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');\n return null;\n }\n\n try {\n this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });\n \n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { input: inputTensor };\n const results = await this.mobileNetSession.run(feeds);\n const output = results[Object.keys(results)[0]].data;\n \n const maxIdx = output.reduce((bestIdx: number, val: number, idx: number, arr: number[]) => \n val > arr[bestIdx] ? idx : bestIdx, 0);\n const confidence = output[maxIdx];\n \n const className = this.mobileNetClassMap[maxIdx.toString()] || \"unknown\";\n \n this.logger.state('DOCUMENTO_CLASIFICADO', {\n class: className,\n confidence: confidence.toFixed(3),\n classIndex: maxIdx,\n timestamp: Date.now()\n });\n \n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n \n } catch (error) {\n this.logger.error('Error al clasificar documento:', error);\n return null;\n }\n }\n\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment {\n const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;\n \n if (!videoRef) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Get video dimensions to calculate actual mask boundaries in model space\n const videoWidth = videoRef.videoWidth;\n const videoHeight = videoRef.videoHeight;\n \n if (videoWidth === 0 || videoHeight === 0) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Calculate video aspect ratio\n const videoAspectRatio = videoWidth / videoHeight;\n \n // The model sees video stretched to 320x320, but we need to calculate where\n // the mask should be in this distorted space to match the visual mask\n \n // In the visual display, we calculate mask size based on the limiting dimension\n // We need to replicate this logic but account for the distortion in model space\n \n // Calculate the \"display\" dimensions (what the visual mask calculations use)\n const containerAspectRatio = 1; // Assume square container for simplicity\n let displayedVideoWidth, displayedVideoHeight;\n \n if (videoAspectRatio > containerAspectRatio) {\n // Video is wider - letterboxed in display\n displayedVideoWidth = INPUT_SIZE;\n displayedVideoHeight = INPUT_SIZE / videoAspectRatio;\n } else {\n // Video is taller - pillarboxed in display \n displayedVideoHeight = INPUT_SIZE;\n displayedVideoWidth = INPUT_SIZE * videoAspectRatio;\n }\n \n // Calculate mask dimensions using the same logic as updateMaskDimensions\n const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;\n \n let visualMaskWidth, visualMaskHeight;\n const sizeRatio = maskSize / 100;\n \n if (maxWidthByHeight <= displayedVideoWidth) {\n // Video height is the limiting factor\n visualMaskHeight = displayedVideoHeight * sizeRatio;\n visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;\n } else {\n // Video width is the limiting factor\n visualMaskWidth = displayedVideoWidth * sizeRatio;\n visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;\n }\n \n // Now map these visual mask dimensions to the distorted model space\n // The model stretches video to 320x320, so we need to apply the inverse transformation\n const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);\n const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);\n \n // Calculate mask boundaries in model coordinate system (always centered in 320x320)\n const maskCenterX = INPUT_SIZE / 2;\n const maskCenterY = INPUT_SIZE / 2;\n const maskLeft = maskCenterX - (modelMaskWidth / 2);\n const maskRight = maskCenterX + (modelMaskWidth / 2);\n const maskTop = maskCenterY - (modelMaskHeight / 2);\n const maskBottom = maskCenterY + (modelMaskHeight / 2);\n \n // Obtener las coordenadas del documento detectado\n let docLeft = box.x;\n let docRight = box.x + box.w;\n const docTop = box.y;\n const docBottom = box.y + box.h;\n \n // Si el video está en modo mirror, invertir las coordenadas horizontales\n if (shouldMirrorVideo) {\n const originalDocLeft = docLeft;\n const originalDocRight = docRight;\n docLeft = INPUT_SIZE - originalDocRight;\n docRight = INPUT_SIZE - originalDocLeft;\n }\n \n // Tolerancia para considerar que un lado está alineado (en píxeles)\n const tolerance = alignmentTolerance;\n \n // Verificar alineación de esquinas más estricta\n // Una esquina está alineada solo si AMBOS bordes que la forman están alineados\n const topAligned = Math.abs(docTop - maskTop) <= tolerance;\n const rightAligned = Math.abs(docRight - maskRight) <= tolerance;\n const bottomAligned = Math.abs(docBottom - maskBottom) <= tolerance;\n const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;\n \n return {\n top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados\n right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados \n bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados\n left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados\n };\n }\n\n isCardInFrame(box: DetectionBox): boolean {\n const cardCenterX = box.x + box.w / 2;\n const cardCenterY = box.y + box.h / 2;\n const frameCenterX = this.INPUT_SIZE / 2;\n const frameCenterY = this.INPUT_SIZE / 2;\n const toleranceX = 40;\n const toleranceY = 30;\n \n const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX && \n Math.abs(cardCenterY - frameCenterY) < toleranceY;\n const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;\n \n return isCentered && isGoodSize;\n }\n\n areAllSidesAligned(alignment: SideAlignment): boolean {\n return alignment.top && alignment.right && alignment.bottom && alignment.left;\n }\n\n cleanup(): void {\n this.cleanupCanvasPool();\n \n if (this.session) {\n this.session.release?.();\n this.session = undefined;\n }\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n this.modelLoaded = false;\n \n this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });\n }\n\n private initializeCanvasPool(): void {\n this.preprocessCanvas = document.createElement('canvas');\n this.preprocessCanvas.width = this.INPUT_SIZE;\n this.preprocessCanvas.height = this.INPUT_SIZE;\n this.preprocessCtx = this.preprocessCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true\n })!;\n \n this.captureCanvas = document.createElement('canvas');\n \n this.logger.state('CANVAS_POOL_INICIALIZADO', { \n preprocessCanvasSize: this.INPUT_SIZE \n });\n }\n\n private cleanupCanvasPool(): void {\n if (this.preprocessCanvas) {\n this.preprocessCtx = undefined;\n this.preprocessCanvas = undefined;\n }\n if (this.captureCanvas) {\n this.captureCanvas = undefined;\n }\n }\n\n private float32ToFloat16(value: number): number {\n const buffer = new ArrayBuffer(4);\n const view = new DataView(buffer);\n view.setFloat32(0, value, true);\n \n const f = view.getUint32(0, true);\n const sign = (f >> 31) & 0x1;\n const exp = (f >> 23) & 0xFF;\n const frac = f & 0x7FFFFF;\n \n let newExp = exp - 127 + 15;\n \n if (exp === 0) {\n newExp = 0;\n } else if (exp === 0xFF) {\n newExp = 0x1F;\n } else if (newExp >= 0x1F) {\n newExp = 0x1F;\n return (sign << 15) | (newExp << 10);\n } else if (newExp <= 0) {\n return (sign << 15);\n }\n \n return (sign << 15) | (newExp << 10) | (frac >> 13);\n }\n\n private preprocessMobileNet(canvas: HTMLCanvasElement): any {\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = 224;\n tempCanvas.height = 224;\n const tempCtx = tempCanvas.getContext('2d')!;\n \n tempCtx.drawImage(canvas, 0, 0, 224, 224);\n \n const imageData = tempCtx.getImageData(0, 0, 224, 224);\n const data = imageData.data;\n const hw = 224 * 224;\n const arr = new Float32Array(3 * hw);\n \n for (let i = 0; i < hw; i++) {\n arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;\n arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;\n arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;\n }\n \n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n}"]}
1
+ {"version":3,"file":"DetectionService.js","sourceRoot":"","sources":["../../src/services/DetectionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { IDetectionService, DetectionBox, SideAlignment, ClassificationResult, QualityThresholds } from './interfaces/IDetectionService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IDeviceStrategy } from './strategies/IDeviceStrategy';\nimport { DeviceStrategyFactory } from './factories/DeviceStrategyFactory';\nimport { ImageQualityService } from './ImageQualityService';\nimport { ImageQualityResult } from './interfaces/IImageQualityService';\n\nexport class DetectionService implements IDetectionService {\n private session?: any;\n private mobileNetSession?: any;\n private mobileNetClassMap?: any;\n private modelLoaded: boolean = false;\n private deviceStrategy: IDeviceStrategy;\n private imageQualityService: ImageQualityService;\n \n private readonly MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx\";\n private readonly MOBILENET_MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx\";\n private readonly MOBILENET_CLASSES_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json\";\n private readonly INPUT_SIZE = 320;\n private readonly CONFIDENCE_THRESHOLD = 0.6;\n\n // Canvas pool for optimization\n private preprocessCanvas?: HTMLCanvasElement;\n private preprocessCtx?: CanvasRenderingContext2D;\n private captureCanvas?: HTMLCanvasElement;\n\n constructor(\n private logger: ILogger,\n private debug: boolean = false,\n private useDocumentClassification: boolean = false,\n private qualityThresholds: QualityThresholds = {}\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.imageQualityService = new ImageQualityService(logger);\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n this.logger.state('MODELO_YA_PRECARGADO', { \n sessionExists: !!this.session, \n modelPreloaded: this.modelLoaded \n });\n return;\n }\n\n try {\n this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });\n \n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n \n try {\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n \n this.modelLoaded = true;\n this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });\n } catch (error) {\n this.logger.error('Error al precargar modelo de detección:', error);\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });\n \n // Load class map\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);\n if (!classResponse.ok) {\n throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);\n }\n this.mobileNetClassMap = await classResponse.json();\n this.logger.state('CLASES_MOBILENET_CARGADAS', { \n classCount: Object.keys(this.mobileNetClassMap).length \n });\n \n // Load model\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n try {\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { \n sessionCreated: !!this.mobileNetSession \n });\n \n } catch (error) {\n this.logger.error('Error al cargar modelo MobileNet:', error);\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\n return this.modelLoaded && !!this.session;\n }\n\n preprocess(video: HTMLVideoElement): any {\n if (!this.preprocessCanvas || !this.preprocessCtx) {\n this.initializeCanvasPool();\n }\n \n this.preprocessCtx!.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n this.preprocessCtx!.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n \n const imageData = this.preprocessCtx!.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n const [R, G, B] = [[], [], []] as number[][];\n const { data } = imageData;\n\n for (let i = 0; i < data.length; i += 4) {\n R.push(data[i] / 255);\n G.push(data[i + 1] / 255);\n B.push(data[i + 2] / 255);\n }\n\n const transposedData = new Float32Array(R.concat(G, B));\n const float16Data = new Uint16Array(transposedData.length);\n for (let i = 0; i < transposedData.length; i++) {\n float16Data[i] = this.float32ToFloat16(transposedData[i]);\n }\n return new (window as any).ort.Tensor(\"float16\", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);\n }\n\n async runInference(inputTensor: any): Promise<DetectionBox[]> {\n if (!this.session) {\n throw new Error('Detection model not loaded');\n }\n\n const feeds = { [this.session.inputNames[0]]: inputTensor };\n const results = await this.session.run(feeds);\n const output = results[this.session.outputNames[0]].data;\n\n const detections: DetectionBox[] = [];\n for (let i = 0; i < output.length; i += 6) {\n const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);\n if (score > this.CONFIDENCE_THRESHOLD) {\n detections.push({ \n x: x1, \n y: y1, \n w: x2 - x1, \n h: y2 - y1, \n score, \n classId \n });\n }\n }\n\n return detections;\n }\n\n async classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null> {\n if (!this.mobileNetSession || !this.mobileNetClassMap) {\n this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');\n return null;\n }\n\n try {\n this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });\n \n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { input: inputTensor };\n const results = await this.mobileNetSession.run(feeds);\n const output = results[Object.keys(results)[0]].data;\n \n const maxIdx = output.reduce((bestIdx: number, val: number, idx: number, arr: number[]) => \n val > arr[bestIdx] ? idx : bestIdx, 0);\n const confidence = output[maxIdx];\n \n const className = this.mobileNetClassMap[maxIdx.toString()] || \"unknown\";\n \n this.logger.state('DOCUMENTO_CLASIFICADO', {\n class: className,\n confidence: confidence.toFixed(3),\n classIndex: maxIdx,\n timestamp: Date.now()\n });\n \n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n \n } catch (error) {\n this.logger.error('Error al clasificar documento:', error);\n return null;\n }\n }\n\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment {\n const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;\n \n if (!videoRef) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Get video dimensions to calculate actual mask boundaries in model space\n const videoWidth = videoRef.videoWidth;\n const videoHeight = videoRef.videoHeight;\n \n if (videoWidth === 0 || videoHeight === 0) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Calculate video aspect ratio\n const videoAspectRatio = videoWidth / videoHeight;\n \n // The model sees video stretched to 320x320, but we need to calculate where\n // the mask should be in this distorted space to match the visual mask\n \n // In the visual display, we calculate mask size based on the limiting dimension\n // We need to replicate this logic but account for the distortion in model space\n \n // Calculate the \"display\" dimensions (what the visual mask calculations use)\n const containerAspectRatio = 1; // Assume square container for simplicity\n let displayedVideoWidth, displayedVideoHeight;\n \n if (videoAspectRatio > containerAspectRatio) {\n // Video is wider - letterboxed in display\n displayedVideoWidth = INPUT_SIZE;\n displayedVideoHeight = INPUT_SIZE / videoAspectRatio;\n } else {\n // Video is taller - pillarboxed in display \n displayedVideoHeight = INPUT_SIZE;\n displayedVideoWidth = INPUT_SIZE * videoAspectRatio;\n }\n \n // Calculate mask dimensions using the same logic as updateMaskDimensions\n const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;\n \n let visualMaskWidth, visualMaskHeight;\n const sizeRatio = maskSize / 100;\n \n if (maxWidthByHeight <= displayedVideoWidth) {\n // Video height is the limiting factor\n visualMaskHeight = displayedVideoHeight * sizeRatio;\n visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;\n } else {\n // Video width is the limiting factor\n visualMaskWidth = displayedVideoWidth * sizeRatio;\n visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;\n }\n \n // Now map these visual mask dimensions to the distorted model space\n // The model stretches video to 320x320, so we need to apply the inverse transformation\n const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);\n const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);\n \n // Calculate mask boundaries in model coordinate system (always centered in 320x320)\n const maskCenterX = INPUT_SIZE / 2;\n const maskCenterY = INPUT_SIZE / 2;\n const maskLeft = maskCenterX - (modelMaskWidth / 2);\n const maskRight = maskCenterX + (modelMaskWidth / 2);\n const maskTop = maskCenterY - (modelMaskHeight / 2);\n const maskBottom = maskCenterY + (modelMaskHeight / 2);\n \n // Obtener las coordenadas del documento detectado\n let docLeft = box.x;\n let docRight = box.x + box.w;\n const docTop = box.y;\n const docBottom = box.y + box.h;\n \n // Si el video está en modo mirror, invertir las coordenadas horizontales\n if (shouldMirrorVideo) {\n const originalDocLeft = docLeft;\n const originalDocRight = docRight;\n docLeft = INPUT_SIZE - originalDocRight;\n docRight = INPUT_SIZE - originalDocLeft;\n }\n \n // Tolerancia para considerar que un lado está alineado (en píxeles)\n const tolerance = alignmentTolerance;\n \n // Verificar alineación de esquinas más estricta\n // Una esquina está alineada solo si AMBOS bordes que la forman están alineados\n const topAligned = Math.abs(docTop - maskTop) <= tolerance;\n const rightAligned = Math.abs(docRight - maskRight) <= tolerance;\n const bottomAligned = Math.abs(docBottom - maskBottom) <= tolerance;\n const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;\n \n return {\n top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados\n right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados \n bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados\n left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados\n };\n }\n\n isCardInFrame(box: DetectionBox): boolean {\n const cardCenterX = box.x + box.w / 2;\n const cardCenterY = box.y + box.h / 2;\n const frameCenterX = this.INPUT_SIZE / 2;\n const frameCenterY = this.INPUT_SIZE / 2;\n const toleranceX = 40;\n const toleranceY = 30;\n \n const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX && \n Math.abs(cardCenterY - frameCenterY) < toleranceY;\n const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;\n \n return isCentered && isGoodSize;\n }\n\n areAllSidesAligned(alignment: SideAlignment): boolean {\n return alignment.top && alignment.right && alignment.bottom && alignment.left;\n }\n\n cleanup(): void {\n this.cleanupCanvasPool();\n \n if (this.session) {\n this.session.release?.();\n this.session = undefined;\n }\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n this.modelLoaded = false;\n \n this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });\n }\n\n private initializeCanvasPool(): void {\n this.preprocessCanvas = document.createElement('canvas');\n this.preprocessCanvas.width = this.INPUT_SIZE;\n this.preprocessCanvas.height = this.INPUT_SIZE;\n this.preprocessCtx = this.preprocessCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true\n })!;\n \n this.captureCanvas = document.createElement('canvas');\n \n this.logger.state('CANVAS_POOL_INICIALIZADO', { \n preprocessCanvasSize: this.INPUT_SIZE \n });\n }\n\n private cleanupCanvasPool(): void {\n if (this.preprocessCanvas) {\n this.preprocessCtx = undefined;\n this.preprocessCanvas = undefined;\n }\n if (this.captureCanvas) {\n this.captureCanvas = undefined;\n }\n }\n\n private float32ToFloat16(value: number): number {\n const buffer = new ArrayBuffer(4);\n const view = new DataView(buffer);\n view.setFloat32(0, value, true);\n \n const f = view.getUint32(0, true);\n const sign = (f >> 31) & 0x1;\n const exp = (f >> 23) & 0xFF;\n const frac = f & 0x7FFFFF;\n \n let newExp = exp - 127 + 15;\n \n if (exp === 0) {\n newExp = 0;\n } else if (exp === 0xFF) {\n newExp = 0x1F;\n } else if (newExp >= 0x1F) {\n newExp = 0x1F;\n return (sign << 15) | (newExp << 10);\n } else if (newExp <= 0) {\n return (sign << 15);\n }\n \n return (sign << 15) | (newExp << 10) | (frac >> 13);\n }\n\n private preprocessMobileNet(canvas: HTMLCanvasElement): any {\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = 224;\n tempCanvas.height = 224;\n const tempCtx = tempCanvas.getContext('2d')!;\n \n tempCtx.drawImage(canvas, 0, 0, 224, 224);\n \n const imageData = tempCtx.getImageData(0, 0, 224, 224);\n const data = imageData.data;\n const hw = 224 * 224;\n const arr = new Float32Array(3 * hw);\n \n for (let i = 0; i < hw; i++) {\n arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;\n arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;\n arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;\n }\n \n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n\n // New methods for image quality validation\n validateImageQuality(video: HTMLVideoElement, detectedBox?: DetectionBox): ImageQualityResult {\n // Create a canvas to capture the current frame\n const canvas = document.createElement('canvas');\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext('2d')!;\n ctx.drawImage(video, 0, 0);\n\n // If we have a detected document, focus quality analysis on that area\n let documentBounds;\n if (detectedBox) {\n const scaleX = video.videoWidth / this.INPUT_SIZE;\n const scaleY = video.videoHeight / this.INPUT_SIZE;\n documentBounds = {\n x: Math.max(0, detectedBox.x * scaleX),\n y: Math.max(0, detectedBox.y * scaleY),\n w: Math.min(detectedBox.w * scaleX, video.videoWidth),\n h: Math.min(detectedBox.h * scaleY, video.videoHeight)\n };\n }\n\n return this.imageQualityService.analyzeImageQuality(canvas, documentBounds);\n }\n\n isImageQualityAcceptable(qualityResult: ImageQualityResult): boolean {\n // Use configurable thresholds with fallback defaults\n const minQualityScore = this.qualityThresholds.minQualityScore ?? 45;\n const minFocusScore = this.qualityThresholds.minFocusScore ?? 16;\n const minBlurScore = this.qualityThresholds.minBlurScore ?? 22;\n const maxReflectionScore = this.qualityThresholds.maxReflectionScore ?? 15;\n \n // Check overall quality score - primary metric\n if (qualityResult.qualityScore < minQualityScore) {\n this.logger.state('QUALITY_REJECTION_SCORE', {\n qualityScore: qualityResult.qualityScore,\n minQualityScore,\n reason: 'score_too_low'\n });\n return false;\n }\n\n // Check focus score\n if (qualityResult.focus.focusScore < minFocusScore) {\n this.logger.state('QUALITY_REJECTION_FOCUS', {\n focusScore: qualityResult.focus.focusScore,\n minFocusScore,\n reason: 'severe_focus_issues'\n });\n return false;\n }\n\n // Check blur score\n if (qualityResult.blur.blurScore < minBlurScore) {\n this.logger.state('QUALITY_REJECTION_BLUR', {\n blurScore: qualityResult.blur.blurScore,\n minBlurScore,\n reason: 'severe_blur_issues'\n });\n return false;\n }\n\n // Check reflection score\n if (qualityResult.reflection.hasReflection && qualityResult.reflection.reflectionScore > maxReflectionScore) {\n this.logger.state('QUALITY_REJECTION_REFLECTION', {\n hasReflection: qualityResult.reflection.hasReflection,\n reflectionScore: qualityResult.reflection.reflectionScore,\n maxReflectionScore,\n reason: 'severe_reflection_issues'\n });\n return false;\n }\n\n this.logger.state('QUALITY_ACCEPTANCE', {\n qualityScore: qualityResult.qualityScore,\n focusScore: qualityResult.focus.focusScore,\n blurScore: qualityResult.blur.blurScore,\n reflectionScore: qualityResult.reflection.reflectionScore,\n issues: qualityResult.issues,\n reason: 'quality_acceptable'\n });\n\n return true;\n }\n\n updateQualityThresholds(thresholds: QualityThresholds): void {\n this.qualityThresholds = { ...this.qualityThresholds, ...thresholds };\n this.logger.state('QUALITY_THRESHOLDS_UPDATED', {\n newThresholds: this.qualityThresholds\n });\n }\n\n getQualityThresholds(): QualityThresholds {\n return { ...this.qualityThresholds };\n }\n\n getQualityFeedback(qualityResult: ImageQualityResult): string {\n if (qualityResult.qualityScore >= 85) {\n return 'Calidad excelente - listo para capturar';\n } else if (qualityResult.qualityScore >= 70) {\n return 'Buena calidad - puede capturar';\n } else if (qualityResult.qualityScore >= 50) {\n const primaryIssue = qualityResult.issues[0];\n return primaryIssue ? `Calidad aceptable - ${primaryIssue.toLowerCase()}` : 'Calidad aceptable';\n } else {\n const mainIssues = qualityResult.issues.slice(0, 2).join(', ').toLowerCase();\n return `Calidad insuficiente - ${mainIssues}`;\n }\n }\n\n // Enhanced detection method that includes quality validation\n async runInferenceWithQuality(inputTensor: any, video: HTMLVideoElement): Promise<{\n detections: DetectionBox[];\n qualityResult: ImageQualityResult;\n canCapture: boolean;\n feedback: string;\n }> {\n const detections = await this.runInference(inputTensor);\n \n // Get the best detection for quality analysis\n const bestDetection = detections.length > 0 ? \n detections.reduce((best, current) => current.score > best.score ? current : best) : \n undefined;\n\n const qualityResult = this.validateImageQuality(video, bestDetection);\n const canCapture = this.isImageQualityAcceptable(qualityResult);\n const feedback = this.getQualityFeedback(qualityResult);\n\n this.logger.state('DETECCION_CON_CALIDAD', {\n detectionsCount: detections.length,\n qualityScore: qualityResult.qualityScore,\n canCapture,\n issues: qualityResult.issues.length,\n bestDetectionScore: bestDetection?.score || 0\n });\n\n return {\n detections,\n qualityResult,\n canCapture,\n feedback\n };\n }\n\n // Method to get real-time quality feedback without full analysis\n getQuickQualityFeedback(video: HTMLVideoElement): {\n hasBlur: boolean;\n hasReflections: boolean;\n isFocused: boolean;\n feedback: string;\n } {\n const canvas = document.createElement('canvas');\n canvas.width = Math.min(video.videoWidth, 640); // Reduced resolution for performance\n canvas.height = Math.min(video.videoHeight, 480);\n const ctx = canvas.getContext('2d')!;\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n \n // Quick blur detection\n const blurMetrics = this.imageQualityService.detectBlur(imageData);\n \n // Quick reflection detection\n const reflectionMetrics = this.imageQualityService.detectReflections(imageData);\n \n // Quick focus measurement\n const focusMetrics = this.imageQualityService.measureFocus(imageData);\n\n let feedback = 'Analizando calidad...';\n \n if (!blurMetrics.isAcceptable) {\n feedback = 'Estabilice el dispositivo';\n } else if (reflectionMetrics.hasReflection) {\n feedback = 'Evite reflejos en el documento';\n } else if (!focusMetrics.isFocused) {\n feedback = 'Permitiendo enfoque automático...';\n } else {\n feedback = 'Calidad óptima';\n }\n\n return {\n hasBlur: !blurMetrics.isAcceptable,\n hasReflections: reflectionMetrics.hasReflection,\n isFocused: focusMetrics.isFocused,\n feedback\n };\n }\n}"]}
@@ -0,0 +1,329 @@
1
+ export class ImageQualityService {
2
+ logger;
3
+ // Thresholds for quality assessment
4
+ BLUR_THRESHOLD = 80; // Reduced from 100 to 80 for better acceptance
5
+ FOCUS_THRESHOLD = 40; // Reduced from 50 to 40 for better acceptance
6
+ REFLECTION_THRESHOLD = 240; // Pixel brightness threshold for reflections
7
+ MIN_BRIGHTNESS = 50; // Minimum acceptable brightness
8
+ MAX_BRIGHTNESS = 200; // Maximum acceptable brightness
9
+ MIN_CONTRAST = 30; // Minimum acceptable contrast
10
+ constructor(logger) {
11
+ this.logger = logger;
12
+ }
13
+ analyzeImageQuality(canvas, documentBounds) {
14
+ const ctx = canvas.getContext('2d');
15
+ if (!ctx) {
16
+ throw new Error('Unable to get canvas context');
17
+ }
18
+ // Get image data for the document area or full canvas
19
+ let imageData;
20
+ if (documentBounds) {
21
+ imageData = ctx.getImageData(documentBounds.x, documentBounds.y, documentBounds.w, documentBounds.h);
22
+ }
23
+ else {
24
+ imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
25
+ }
26
+ // Perform all quality assessments
27
+ const blur = this.detectBlur(imageData);
28
+ const reflection = this.detectReflections(imageData);
29
+ const focus = this.measureFocus(imageData);
30
+ const brightness = this.measureBrightness(imageData);
31
+ const contrast = this.measureContrast(imageData);
32
+ // Calculate overall quality score (0-100)
33
+ const qualityScore = this.calculateOverallQuality(blur, reflection, focus, brightness, contrast);
34
+ const overallQuality = this.getQualityLevel(qualityScore);
35
+ // Identify issues and recommendations
36
+ const issues = this.identifyIssues(blur, reflection, focus, brightness, contrast);
37
+ const recommendations = this.getQualityRecommendations({
38
+ blur, reflection, focus, brightness, contrast,
39
+ overallQuality, qualityScore, issues, recommendations: []
40
+ });
41
+ const result = {
42
+ blur,
43
+ reflection,
44
+ focus,
45
+ brightness,
46
+ contrast,
47
+ overallQuality,
48
+ qualityScore,
49
+ issues,
50
+ recommendations
51
+ };
52
+ this.logger.state('CALIDAD_IMAGEN_ANALIZADA', {
53
+ qualityScore,
54
+ overallQuality,
55
+ issues: issues.length,
56
+ hasBlur: !blur.isAcceptable,
57
+ hasReflection: reflection.hasReflection,
58
+ isFocused: focus.isFocused
59
+ });
60
+ return result;
61
+ }
62
+ detectBlur(imageData) {
63
+ const { data, width, height } = imageData;
64
+ let totalVariance = 0;
65
+ let pixelCount = 0;
66
+ // Calculate Laplacian variance for blur detection
67
+ for (let y = 1; y < height - 1; y++) {
68
+ for (let x = 1; x < width - 1; x++) {
69
+ const idx = (y * width + x) * 4;
70
+ // Convert to grayscale
71
+ const gray = 0.299 * data[idx] + 0.587 * data[idx + 1] + 0.114 * data[idx + 2];
72
+ // Calculate Laplacian (edge detection)
73
+ const neighbors = [
74
+ this.getGrayscale(data, x - 1, y - 1, width),
75
+ this.getGrayscale(data, x, y - 1, width),
76
+ this.getGrayscale(data, x + 1, y - 1, width),
77
+ this.getGrayscale(data, x - 1, y, width),
78
+ this.getGrayscale(data, x + 1, y, width),
79
+ this.getGrayscale(data, x - 1, y + 1, width),
80
+ this.getGrayscale(data, x, y + 1, width),
81
+ this.getGrayscale(data, x + 1, y + 1, width)
82
+ ];
83
+ const laplacian = 8 * gray - neighbors.reduce((sum, val) => sum + val, 0);
84
+ totalVariance += laplacian * laplacian;
85
+ pixelCount++;
86
+ }
87
+ }
88
+ const blurScore = Math.sqrt(totalVariance / pixelCount);
89
+ const isAcceptable = blurScore > this.BLUR_THRESHOLD;
90
+ return {
91
+ blurScore,
92
+ isAcceptable,
93
+ threshold: this.BLUR_THRESHOLD
94
+ };
95
+ }
96
+ detectReflections(imageData) {
97
+ const { data, width, height } = imageData;
98
+ let reflectionPixels = 0;
99
+ const totalPixels = width * height;
100
+ const reflectionAreas = [];
101
+ // Track bright regions that could be reflections
102
+ const brightRegions = Array(height).fill(null).map(() => Array(width).fill(false));
103
+ for (let y = 0; y < height; y++) {
104
+ for (let x = 0; x < width; x++) {
105
+ const idx = (y * width + x) * 4;
106
+ const brightness = (data[idx] + data[idx + 1] + data[idx + 2]) / 3;
107
+ if (brightness > this.REFLECTION_THRESHOLD) {
108
+ brightRegions[y][x] = true;
109
+ reflectionPixels++;
110
+ }
111
+ }
112
+ }
113
+ // Find connected bright regions (potential reflections)
114
+ const visited = Array(height).fill(null).map(() => Array(width).fill(false));
115
+ for (let y = 0; y < height; y++) {
116
+ for (let x = 0; x < width; x++) {
117
+ if (brightRegions[y][x] && !visited[y][x]) {
118
+ const region = this.findConnectedRegion(brightRegions, visited, x, y, width, height);
119
+ if (region.size > 100) { // Minimum size for a reflection
120
+ reflectionAreas.push({
121
+ x: region.minX,
122
+ y: region.minY,
123
+ width: region.maxX - region.minX,
124
+ height: region.maxY - region.minY
125
+ });
126
+ }
127
+ }
128
+ }
129
+ }
130
+ const reflectionScore = (reflectionPixels / totalPixels) * 100;
131
+ const hasReflection = reflectionScore > 5 || reflectionAreas.length > 0; // 5% threshold
132
+ return {
133
+ reflectionScore,
134
+ hasReflection,
135
+ threshold: 5,
136
+ reflectionAreas
137
+ };
138
+ }
139
+ measureFocus(imageData) {
140
+ const { data, width, height } = imageData;
141
+ let edgeStrength = 0;
142
+ let edgeCount = 0;
143
+ // Sobel edge detection for focus measurement
144
+ for (let y = 1; y < height - 1; y++) {
145
+ for (let x = 1; x < width - 1; x++) {
146
+ const gx = this.sobelX(data, x, y, width);
147
+ const gy = this.sobelY(data, x, y, width);
148
+ const magnitude = Math.sqrt(gx * gx + gy * gy);
149
+ edgeStrength += magnitude;
150
+ edgeCount++;
151
+ }
152
+ }
153
+ const focusScore = edgeCount > 0 ? edgeStrength / edgeCount : 0;
154
+ const isFocused = focusScore > this.FOCUS_THRESHOLD;
155
+ return {
156
+ focusScore,
157
+ isFocused,
158
+ threshold: this.FOCUS_THRESHOLD,
159
+ edgeStrength
160
+ };
161
+ }
162
+ measureBrightness(imageData) {
163
+ const { data } = imageData;
164
+ let totalBrightness = 0;
165
+ const pixelCount = data.length / 4;
166
+ for (let i = 0; i < data.length; i += 4) {
167
+ const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;
168
+ totalBrightness += brightness;
169
+ }
170
+ const brightness = totalBrightness / pixelCount;
171
+ const isAcceptable = brightness >= this.MIN_BRIGHTNESS && brightness <= this.MAX_BRIGHTNESS;
172
+ return {
173
+ brightness,
174
+ isAcceptable,
175
+ minThreshold: this.MIN_BRIGHTNESS,
176
+ maxThreshold: this.MAX_BRIGHTNESS
177
+ };
178
+ }
179
+ measureContrast(imageData) {
180
+ const { data } = imageData;
181
+ let min = 255;
182
+ let max = 0;
183
+ for (let i = 0; i < data.length; i += 4) {
184
+ const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;
185
+ min = Math.min(min, brightness);
186
+ max = Math.max(max, brightness);
187
+ }
188
+ const contrast = max - min;
189
+ const isAcceptable = contrast > this.MIN_CONTRAST;
190
+ return {
191
+ contrast,
192
+ isAcceptable,
193
+ threshold: this.MIN_CONTRAST
194
+ };
195
+ }
196
+ getQualityRecommendations(result) {
197
+ const recommendations = [];
198
+ if (!result.blur.isAcceptable) {
199
+ recommendations.push('Mantenga el dispositivo estable para reducir el desenfoque');
200
+ recommendations.push('Acérquese al documento para mejorar la nitidez');
201
+ }
202
+ if (result.reflection.hasReflection) {
203
+ recommendations.push('Cambie el ángulo del dispositivo para evitar reflejos');
204
+ recommendations.push('Mejore la iluminación indirecta del área');
205
+ }
206
+ if (!result.focus.isFocused) {
207
+ recommendations.push('Permita que la cámara enfoque automáticamente');
208
+ recommendations.push('Toque la pantalla sobre el documento para enfocar');
209
+ }
210
+ if (!result.brightness.isAcceptable) {
211
+ if (result.brightness.brightness < result.brightness.minThreshold) {
212
+ recommendations.push('Aumente la iluminación del área');
213
+ recommendations.push('Muévase a un lugar con mejor luz');
214
+ }
215
+ else {
216
+ recommendations.push('Reduzca la iluminación directa sobre el documento');
217
+ recommendations.push('Evite la luz solar directa');
218
+ }
219
+ }
220
+ if (!result.contrast.isAcceptable) {
221
+ recommendations.push('Mejore la iluminación para aumentar el contraste');
222
+ recommendations.push('Asegúrese de que el fondo contraste con el documento');
223
+ }
224
+ if (recommendations.length === 0) {
225
+ recommendations.push('La calidad de la imagen es óptima para la captura');
226
+ }
227
+ return recommendations;
228
+ }
229
+ calculateOverallQuality(blur, reflection, focus, brightness, contrast) {
230
+ let score = 0;
231
+ // Blur contribution (25%)
232
+ score += blur.isAcceptable ? 25 : Math.max(0, (blur.blurScore / this.BLUR_THRESHOLD) * 25);
233
+ // Reflection contribution (20%)
234
+ score += reflection.hasReflection ? Math.max(0, 20 - reflection.reflectionScore * 2) : 20;
235
+ // Focus contribution (25%)
236
+ score += focus.isFocused ? 25 : Math.max(0, (focus.focusScore / this.FOCUS_THRESHOLD) * 25);
237
+ // Brightness contribution (15%)
238
+ if (brightness.isAcceptable) {
239
+ score += 15;
240
+ }
241
+ else {
242
+ const brightnessPenalty = Math.abs(brightness.brightness - (brightness.minThreshold + brightness.maxThreshold) / 2);
243
+ score += Math.max(0, 15 - brightnessPenalty / 10);
244
+ }
245
+ // Contrast contribution (15%)
246
+ score += contrast.isAcceptable ? 15 : Math.max(0, (contrast.contrast / this.MIN_CONTRAST) * 15);
247
+ return Math.round(Math.max(0, Math.min(100, score)));
248
+ }
249
+ getQualityLevel(score) {
250
+ if (score >= 85)
251
+ return 'excellent';
252
+ if (score >= 70)
253
+ return 'good';
254
+ if (score >= 50)
255
+ return 'acceptable';
256
+ return 'poor';
257
+ }
258
+ identifyIssues(blur, reflection, focus, brightness, contrast) {
259
+ const issues = [];
260
+ if (!blur.isAcceptable) {
261
+ issues.push('Imagen desenfocada por movimiento');
262
+ }
263
+ if (reflection.hasReflection) {
264
+ issues.push('Reflejos detectados en el documento');
265
+ }
266
+ if (!focus.isFocused) {
267
+ issues.push('Documento fuera de foco');
268
+ }
269
+ if (!brightness.isAcceptable) {
270
+ if (brightness.brightness < brightness.minThreshold) {
271
+ issues.push('Iluminación insuficiente');
272
+ }
273
+ else {
274
+ issues.push('Imagen sobreexpuesta');
275
+ }
276
+ }
277
+ if (!contrast.isAcceptable) {
278
+ issues.push('Contraste insuficiente');
279
+ }
280
+ return issues;
281
+ }
282
+ getGrayscale(data, x, y, width) {
283
+ const idx = (y * width + x) * 4;
284
+ return 0.299 * data[idx] + 0.587 * data[idx + 1] + 0.114 * data[idx + 2];
285
+ }
286
+ findConnectedRegion(brightRegions, visited, startX, startY, width, height) {
287
+ const stack = [{ x: startX, y: startY }];
288
+ let size = 0;
289
+ let minX = startX, maxX = startX, minY = startY, maxY = startY;
290
+ while (stack.length > 0) {
291
+ const { x, y } = stack.pop();
292
+ if (x < 0 || x >= width || y < 0 || y >= height || visited[y][x] || !brightRegions[y][x]) {
293
+ continue;
294
+ }
295
+ visited[y][x] = true;
296
+ size++;
297
+ minX = Math.min(minX, x);
298
+ maxX = Math.max(maxX, x);
299
+ minY = Math.min(minY, y);
300
+ maxY = Math.max(maxY, y);
301
+ // Add adjacent pixels
302
+ stack.push({ x: x + 1, y }, { x: x - 1, y }, { x, y: y + 1 }, { x, y: y - 1 });
303
+ }
304
+ return { size, minX, maxX, minY, maxY };
305
+ }
306
+ sobelX(data, x, y, width) {
307
+ const kernel = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]];
308
+ let sum = 0;
309
+ for (let ky = -1; ky <= 1; ky++) {
310
+ for (let kx = -1; kx <= 1; kx++) {
311
+ const gray = this.getGrayscale(data, x + kx, y + ky, width);
312
+ sum += gray * kernel[ky + 1][kx + 1];
313
+ }
314
+ }
315
+ return sum;
316
+ }
317
+ sobelY(data, x, y, width) {
318
+ const kernel = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
319
+ let sum = 0;
320
+ for (let ky = -1; ky <= 1; ky++) {
321
+ for (let kx = -1; kx <= 1; kx++) {
322
+ const gray = this.getGrayscale(data, x + kx, y + ky, width);
323
+ sum += gray * kernel[ky + 1][kx + 1];
324
+ }
325
+ }
326
+ return sum;
327
+ }
328
+ }
329
+ //# sourceMappingURL=ImageQualityService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageQualityService.js","sourceRoot":"","sources":["../../src/services/ImageQualityService.ts"],"names":[],"mappings":"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","sourcesContent":["import { \n IImageQualityService, \n ImageQualityResult, \n BlurMetrics, \n ReflectionMetrics, \n FocusMetrics, \n BrightnessMetrics, \n ContrastMetrics \n} from './interfaces/IImageQualityService';\nimport { ILogger } from './interfaces/ILogger';\n\nexport class ImageQualityService implements IImageQualityService {\n // Thresholds for quality assessment\n private readonly BLUR_THRESHOLD = 80; // Reduced from 100 to 80 for better acceptance\n private readonly FOCUS_THRESHOLD = 40; // Reduced from 50 to 40 for better acceptance\n private readonly REFLECTION_THRESHOLD = 240; // Pixel brightness threshold for reflections\n private readonly MIN_BRIGHTNESS = 50; // Minimum acceptable brightness\n private readonly MAX_BRIGHTNESS = 200; // Maximum acceptable brightness\n private readonly MIN_CONTRAST = 30; // Minimum acceptable contrast\n\n constructor(private logger: ILogger) {}\n\n analyzeImageQuality(canvas: HTMLCanvasElement, documentBounds?: { x: number; y: number; w: number; h: number }): ImageQualityResult {\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Unable to get canvas context');\n }\n\n // Get image data for the document area or full canvas\n let imageData: ImageData;\n if (documentBounds) {\n imageData = ctx.getImageData(documentBounds.x, documentBounds.y, documentBounds.w, documentBounds.h);\n } else {\n imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n }\n\n // Perform all quality assessments\n const blur = this.detectBlur(imageData);\n const reflection = this.detectReflections(imageData);\n const focus = this.measureFocus(imageData);\n const brightness = this.measureBrightness(imageData);\n const contrast = this.measureContrast(imageData);\n\n // Calculate overall quality score (0-100)\n const qualityScore = this.calculateOverallQuality(blur, reflection, focus, brightness, contrast);\n const overallQuality = this.getQualityLevel(qualityScore);\n \n // Identify issues and recommendations\n const issues = this.identifyIssues(blur, reflection, focus, brightness, contrast);\n const recommendations = this.getQualityRecommendations({ \n blur, reflection, focus, brightness, contrast, \n overallQuality, qualityScore, issues, recommendations: [] \n });\n\n const result: ImageQualityResult = {\n blur,\n reflection,\n focus,\n brightness,\n contrast,\n overallQuality,\n qualityScore,\n issues,\n recommendations\n };\n\n this.logger.state('CALIDAD_IMAGEN_ANALIZADA', {\n qualityScore,\n overallQuality,\n issues: issues.length,\n hasBlur: !blur.isAcceptable,\n hasReflection: reflection.hasReflection,\n isFocused: focus.isFocused\n });\n\n return result;\n }\n\n detectBlur(imageData: ImageData): BlurMetrics {\n const { data, width, height } = imageData;\n let totalVariance = 0;\n let pixelCount = 0;\n\n // Calculate Laplacian variance for blur detection\n for (let y = 1; y < height - 1; y++) {\n for (let x = 1; x < width - 1; x++) {\n const idx = (y * width + x) * 4;\n \n // Convert to grayscale\n const gray = 0.299 * data[idx] + 0.587 * data[idx + 1] + 0.114 * data[idx + 2];\n \n // Calculate Laplacian (edge detection)\n const neighbors = [\n this.getGrayscale(data, x - 1, y - 1, width),\n this.getGrayscale(data, x, y - 1, width),\n this.getGrayscale(data, x + 1, y - 1, width),\n this.getGrayscale(data, x - 1, y, width),\n this.getGrayscale(data, x + 1, y, width),\n this.getGrayscale(data, x - 1, y + 1, width),\n this.getGrayscale(data, x, y + 1, width),\n this.getGrayscale(data, x + 1, y + 1, width)\n ];\n \n const laplacian = 8 * gray - neighbors.reduce((sum, val) => sum + val, 0);\n totalVariance += laplacian * laplacian;\n pixelCount++;\n }\n }\n\n const blurScore = Math.sqrt(totalVariance / pixelCount);\n const isAcceptable = blurScore > this.BLUR_THRESHOLD;\n\n return {\n blurScore,\n isAcceptable,\n threshold: this.BLUR_THRESHOLD\n };\n }\n\n detectReflections(imageData: ImageData): ReflectionMetrics {\n const { data, width, height } = imageData;\n let reflectionPixels = 0;\n const totalPixels = width * height;\n const reflectionAreas: { x: number; y: number; width: number; height: number }[] = [];\n \n // Track bright regions that could be reflections\n const brightRegions: boolean[][] = Array(height).fill(null).map(() => Array(width).fill(false));\n \n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = (y * width + x) * 4;\n const brightness = (data[idx] + data[idx + 1] + data[idx + 2]) / 3;\n \n if (brightness > this.REFLECTION_THRESHOLD) {\n brightRegions[y][x] = true;\n reflectionPixels++;\n }\n }\n }\n\n // Find connected bright regions (potential reflections)\n const visited: boolean[][] = Array(height).fill(null).map(() => Array(width).fill(false));\n \n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n if (brightRegions[y][x] && !visited[y][x]) {\n const region = this.findConnectedRegion(brightRegions, visited, x, y, width, height);\n if (region.size > 100) { // Minimum size for a reflection\n reflectionAreas.push({\n x: region.minX,\n y: region.minY,\n width: region.maxX - region.minX,\n height: region.maxY - region.minY\n });\n }\n }\n }\n }\n\n const reflectionScore = (reflectionPixels / totalPixels) * 100;\n const hasReflection = reflectionScore > 5 || reflectionAreas.length > 0; // 5% threshold\n\n return {\n reflectionScore,\n hasReflection,\n threshold: 5,\n reflectionAreas\n };\n }\n\n measureFocus(imageData: ImageData): FocusMetrics {\n const { data, width, height } = imageData;\n let edgeStrength = 0;\n let edgeCount = 0;\n\n // Sobel edge detection for focus measurement\n for (let y = 1; y < height - 1; y++) {\n for (let x = 1; x < width - 1; x++) {\n const gx = this.sobelX(data, x, y, width);\n const gy = this.sobelY(data, x, y, width);\n const magnitude = Math.sqrt(gx * gx + gy * gy);\n \n edgeStrength += magnitude;\n edgeCount++;\n }\n }\n\n const focusScore = edgeCount > 0 ? edgeStrength / edgeCount : 0;\n const isFocused = focusScore > this.FOCUS_THRESHOLD;\n\n return {\n focusScore,\n isFocused,\n threshold: this.FOCUS_THRESHOLD,\n edgeStrength\n };\n }\n\n measureBrightness(imageData: ImageData): BrightnessMetrics {\n const { data } = imageData;\n let totalBrightness = 0;\n const pixelCount = data.length / 4;\n\n for (let i = 0; i < data.length; i += 4) {\n const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;\n totalBrightness += brightness;\n }\n\n const brightness = totalBrightness / pixelCount;\n const isAcceptable = brightness >= this.MIN_BRIGHTNESS && brightness <= this.MAX_BRIGHTNESS;\n\n return {\n brightness,\n isAcceptable,\n minThreshold: this.MIN_BRIGHTNESS,\n maxThreshold: this.MAX_BRIGHTNESS\n };\n }\n\n measureContrast(imageData: ImageData): ContrastMetrics {\n const { data } = imageData;\n let min = 255;\n let max = 0;\n\n for (let i = 0; i < data.length; i += 4) {\n const brightness = (data[i] + data[i + 1] + data[i + 2]) / 3;\n min = Math.min(min, brightness);\n max = Math.max(max, brightness);\n }\n\n const contrast = max - min;\n const isAcceptable = contrast > this.MIN_CONTRAST;\n\n return {\n contrast,\n isAcceptable,\n threshold: this.MIN_CONTRAST\n };\n }\n\n getQualityRecommendations(result: ImageQualityResult): string[] {\n const recommendations: string[] = [];\n\n if (!result.blur.isAcceptable) {\n recommendations.push('Mantenga el dispositivo estable para reducir el desenfoque');\n recommendations.push('Acérquese al documento para mejorar la nitidez');\n }\n\n if (result.reflection.hasReflection) {\n recommendations.push('Cambie el ángulo del dispositivo para evitar reflejos');\n recommendations.push('Mejore la iluminación indirecta del área');\n }\n\n if (!result.focus.isFocused) {\n recommendations.push('Permita que la cámara enfoque automáticamente');\n recommendations.push('Toque la pantalla sobre el documento para enfocar');\n }\n\n if (!result.brightness.isAcceptable) {\n if (result.brightness.brightness < result.brightness.minThreshold) {\n recommendations.push('Aumente la iluminación del área');\n recommendations.push('Muévase a un lugar con mejor luz');\n } else {\n recommendations.push('Reduzca la iluminación directa sobre el documento');\n recommendations.push('Evite la luz solar directa');\n }\n }\n\n if (!result.contrast.isAcceptable) {\n recommendations.push('Mejore la iluminación para aumentar el contraste');\n recommendations.push('Asegúrese de que el fondo contraste con el documento');\n }\n\n if (recommendations.length === 0) {\n recommendations.push('La calidad de la imagen es óptima para la captura');\n }\n\n return recommendations;\n }\n\n private calculateOverallQuality(\n blur: BlurMetrics, \n reflection: ReflectionMetrics, \n focus: FocusMetrics, \n brightness: BrightnessMetrics, \n contrast: ContrastMetrics\n ): number {\n let score = 0;\n\n // Blur contribution (25%)\n score += blur.isAcceptable ? 25 : Math.max(0, (blur.blurScore / this.BLUR_THRESHOLD) * 25);\n\n // Reflection contribution (20%)\n score += reflection.hasReflection ? Math.max(0, 20 - reflection.reflectionScore * 2) : 20;\n\n // Focus contribution (25%)\n score += focus.isFocused ? 25 : Math.max(0, (focus.focusScore / this.FOCUS_THRESHOLD) * 25);\n\n // Brightness contribution (15%)\n if (brightness.isAcceptable) {\n score += 15;\n } else {\n const brightnessPenalty = Math.abs(brightness.brightness - (brightness.minThreshold + brightness.maxThreshold) / 2);\n score += Math.max(0, 15 - brightnessPenalty / 10);\n }\n\n // Contrast contribution (15%)\n score += contrast.isAcceptable ? 15 : Math.max(0, (contrast.contrast / this.MIN_CONTRAST) * 15);\n\n return Math.round(Math.max(0, Math.min(100, score)));\n }\n\n private getQualityLevel(score: number): 'excellent' | 'good' | 'acceptable' | 'poor' {\n if (score >= 85) return 'excellent';\n if (score >= 70) return 'good';\n if (score >= 50) return 'acceptable';\n return 'poor';\n }\n\n private identifyIssues(\n blur: BlurMetrics, \n reflection: ReflectionMetrics, \n focus: FocusMetrics, \n brightness: BrightnessMetrics, \n contrast: ContrastMetrics\n ): string[] {\n const issues: string[] = [];\n\n if (!blur.isAcceptable) {\n issues.push('Imagen desenfocada por movimiento');\n }\n\n if (reflection.hasReflection) {\n issues.push('Reflejos detectados en el documento');\n }\n\n if (!focus.isFocused) {\n issues.push('Documento fuera de foco');\n }\n\n if (!brightness.isAcceptable) {\n if (brightness.brightness < brightness.minThreshold) {\n issues.push('Iluminación insuficiente');\n } else {\n issues.push('Imagen sobreexpuesta');\n }\n }\n\n if (!contrast.isAcceptable) {\n issues.push('Contraste insuficiente');\n }\n\n return issues;\n }\n\n private getGrayscale(data: Uint8ClampedArray, x: number, y: number, width: number): number {\n const idx = (y * width + x) * 4;\n return 0.299 * data[idx] + 0.587 * data[idx + 1] + 0.114 * data[idx + 2];\n }\n\n private findConnectedRegion(\n brightRegions: boolean[][], \n visited: boolean[][], \n startX: number, \n startY: number, \n width: number, \n height: number\n ) {\n const stack = [{ x: startX, y: startY }];\n let size = 0;\n let minX = startX, maxX = startX, minY = startY, maxY = startY;\n\n while (stack.length > 0) {\n const { x, y } = stack.pop()!;\n \n if (x < 0 || x >= width || y < 0 || y >= height || visited[y][x] || !brightRegions[y][x]) {\n continue;\n }\n\n visited[y][x] = true;\n size++;\n \n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n\n // Add adjacent pixels\n stack.push({ x: x + 1, y }, { x: x - 1, y }, { x, y: y + 1 }, { x, y: y - 1 });\n }\n\n return { size, minX, maxX, minY, maxY };\n }\n\n private sobelX(data: Uint8ClampedArray, x: number, y: number, width: number): number {\n const kernel = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]];\n let sum = 0;\n\n for (let ky = -1; ky <= 1; ky++) {\n for (let kx = -1; kx <= 1; kx++) {\n const gray = this.getGrayscale(data, x + kx, y + ky, width);\n sum += gray * kernel[ky + 1][kx + 1];\n }\n }\n\n return sum;\n }\n\n private sobelY(data: Uint8ClampedArray, x: number, y: number, width: number): number {\n const kernel = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];\n let sum = 0;\n\n for (let ky = -1; ky <= 1; ky++) {\n for (let kx = -1; kx <= 1; kx++) {\n const gray = this.getGrayscale(data, x + kx, y + ky, width);\n sum += gray * kernel[ky + 1][kx + 1];\n }\n }\n\n return sum;\n }\n}"]}
@@ -14,7 +14,12 @@ export class ServiceContainer {
14
14
  const logger = new LoggerService(config.debug);
15
15
  const stateManager = new StateManagerService(eventBus);
16
16
  const cameraService = new CameraService(logger, eventBus, config.preferredCamera);
17
- const detectionService = new DetectionService(logger, config.debug, config.useDocumentClassification);
17
+ const detectionService = new DetectionService(logger, config.debug, config.useDocumentClassification, {
18
+ minQualityScore: config.minQualityScore,
19
+ minFocusScore: config.minFocusScore,
20
+ minBlurScore: config.minBlurScore,
21
+ maxReflectionScore: config.maxReflectionScore
22
+ });
18
23
  // Register services
19
24
  this.services.set('eventBus', eventBus);
20
25
  this.services.set('logger', logger);
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceContainer.js","sourceRoot":"","sources":["../../src/services/ServiceContainer.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILogger } from './interfaces/ILogger';\nimport { ICameraService } from './interfaces/ICameraService';\nimport { IDetectionService } from './interfaces/IDetectionService';\nimport { IStateManager } from './interfaces/IStateManager';\nimport { IEventBus } from './interfaces/IEventBus';\n\nimport { LoggerService } from './LoggerService';\nimport { EventBusService } from './EventBusService';\nimport { StateManagerService } from './StateManagerService';\nimport { CameraService } from './CameraService';\nimport { DetectionService } from './DetectionService';\n\nexport interface ComponentConfig {\n debug: boolean;\n alignmentTolerance: number;\n maskSize: number;\n cropMargin: number;\n useDocumentClassification: boolean;\n preferredCamera: 'auto' | 'front' | 'back';\n}\n\nexport class ServiceContainer {\n private services = new Map<string, any>();\n\n constructor(config: ComponentConfig) {\n this.initializeServices(config);\n }\n\n private initializeServices(config: ComponentConfig): void {\n // Initialize services in dependency order\n const eventBus = new EventBusService();\n const logger = new LoggerService(config.debug);\n const stateManager = new StateManagerService(eventBus);\n const cameraService = new CameraService(logger as any, eventBus, config.preferredCamera);\n const detectionService = new DetectionService(\n logger as any, \n config.debug, \n config.useDocumentClassification\n );\n\n // Register services\n this.services.set('eventBus', eventBus);\n this.services.set('logger', logger);\n this.services.set('stateManager', stateManager);\n this.services.set('cameraService', cameraService);\n this.services.set('detectionService', detectionService);\n }\n\n get<T>(serviceName: string): T {\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`Service ${serviceName} not found`);\n }\n return service as T;\n }\n\n getLogger(): ILogger {\n return this.get<ILogger>('logger');\n }\n\n getEventBus(): IEventBus {\n return this.get<IEventBus>('eventBus');\n }\n\n getStateManager(): IStateManager {\n return this.get<IStateManager>('stateManager');\n }\n\n getCameraService(): ICameraService {\n return this.get<ICameraService>('cameraService');\n }\n\n getDetectionService(): IDetectionService {\n return this.get<IDetectionService>('detectionService');\n }\n\n updateConfig(config: Partial<ComponentConfig>): void {\n if (config.debug !== undefined) {\n const logger = this.services.get('logger') as LoggerService;\n logger.setDebugMode(config.debug);\n }\n\n // Reinitialize services that depend on configuration changes\n if (config.preferredCamera !== undefined || \n config.useDocumentClassification !== undefined) {\n // Would need to reinitialize specific services\n // For simplicity, this is omitted in this example\n }\n }\n\n cleanup(): void {\n // Cleanup services in reverse order\n this.getDetectionService().cleanup();\n this.getEventBus().clear();\n this.services.clear();\n }\n}"]}
1
+ {"version":3,"file":"ServiceContainer.js","sourceRoot":"","sources":["../../src/services/ServiceContainer.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILogger } from './interfaces/ILogger';\nimport { ICameraService } from './interfaces/ICameraService';\nimport { IDetectionService } from './interfaces/IDetectionService';\nimport { IStateManager } from './interfaces/IStateManager';\nimport { IEventBus } from './interfaces/IEventBus';\n\nimport { LoggerService } from './LoggerService';\nimport { EventBusService } from './EventBusService';\nimport { StateManagerService } from './StateManagerService';\nimport { CameraService } from './CameraService';\nimport { DetectionService } from './DetectionService';\n\nexport interface ComponentConfig {\n debug: boolean;\n alignmentTolerance: number;\n maskSize: number;\n cropMargin: number;\n useDocumentClassification: boolean;\n preferredCamera: 'auto' | 'front' | 'back';\n captureDelay: number;\n enableQualityValidation?: boolean;\n qualityThreshold?: number;\n minQualityScore?: number;\n minFocusScore?: number;\n minBlurScore?: number;\n maxReflectionScore?: number;\n}\n\nexport class ServiceContainer {\n private services = new Map<string, any>();\n\n constructor(config: ComponentConfig) {\n this.initializeServices(config);\n }\n\n private initializeServices(config: ComponentConfig): void {\n // Initialize services in dependency order\n const eventBus = new EventBusService();\n const logger = new LoggerService(config.debug);\n const stateManager = new StateManagerService(eventBus);\n const cameraService = new CameraService(logger as any, eventBus, config.preferredCamera);\n const detectionService = new DetectionService(\n logger as any, \n config.debug, \n config.useDocumentClassification,\n {\n minQualityScore: config.minQualityScore,\n minFocusScore: config.minFocusScore,\n minBlurScore: config.minBlurScore,\n maxReflectionScore: config.maxReflectionScore\n }\n );\n\n // Register services\n this.services.set('eventBus', eventBus);\n this.services.set('logger', logger);\n this.services.set('stateManager', stateManager);\n this.services.set('cameraService', cameraService);\n this.services.set('detectionService', detectionService);\n }\n\n get<T>(serviceName: string): T {\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`Service ${serviceName} not found`);\n }\n return service as T;\n }\n\n getLogger(): ILogger {\n return this.get<ILogger>('logger');\n }\n\n getEventBus(): IEventBus {\n return this.get<IEventBus>('eventBus');\n }\n\n getStateManager(): IStateManager {\n return this.get<IStateManager>('stateManager');\n }\n\n getCameraService(): ICameraService {\n return this.get<ICameraService>('cameraService');\n }\n\n getDetectionService(): IDetectionService {\n return this.get<IDetectionService>('detectionService');\n }\n\n updateConfig(config: Partial<ComponentConfig>): void {\n if (config.debug !== undefined) {\n const logger = this.services.get('logger') as LoggerService;\n logger.setDebugMode(config.debug);\n }\n\n // Reinitialize services that depend on configuration changes\n if (config.preferredCamera !== undefined || \n config.useDocumentClassification !== undefined) {\n // Would need to reinitialize specific services\n // For simplicity, this is omitted in this example\n }\n }\n\n cleanup(): void {\n // Cleanup services in reverse order\n this.getDetectionService().cleanup();\n this.getEventBus().clear();\n this.services.clear();\n }\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ICameraService.js","sourceRoot":"","sources":["../../../src/services/interfaces/ICameraService.ts"],"names":[],"mappings":"","sourcesContent":["export interface CameraInfo {\n id: string;\n label: string;\n selected: boolean;\n}\n\nexport interface CameraPreference {\n cameraId: string;\n facing: 'environment' | 'user' | null;\n timestamp: number;\n}\n\nexport interface ICameraService {\n detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'>;\n enumerateDevices(): Promise<MediaDeviceInfo[]>;\n getAvailableCameras(): MediaDeviceInfo[];\n isMultipleCamerasAvailable(): boolean;\n getSelectedCameraId(): string | null;\n setSelectedCamera(cameraId: string): Promise<void>;\n getPreferredFacing(): 'environment' | 'user' | null;\n setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream>;\n switchCamera(cameraId: string): Promise<void>;\n flipToNextCamera(): Promise<void>;\n savePreference(): void;\n loadPreference(): void;\n isRearCamera(stream: MediaStream): boolean;\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n };\n}"]}
1
+ {"version":3,"file":"ICameraService.js","sourceRoot":"","sources":["../../../src/services/interfaces/ICameraService.ts"],"names":[],"mappings":"","sourcesContent":["export interface CameraInfo {\n id: string;\n label: string;\n selected: boolean;\n}\n\nexport interface CameraPreference {\n cameraId: string;\n facing: 'environment' | 'user' | null;\n timestamp: number;\n}\n\nexport interface ICameraService {\n detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'>;\n enumerateDevices(): Promise<MediaDeviceInfo[]>;\n getAvailableCameras(): MediaDeviceInfo[];\n isMultipleCamerasAvailable(): boolean;\n getSelectedCameraId(): string | null;\n setSelectedCamera(cameraId: string): Promise<void>;\n getPreferredFacing(): 'environment' | 'user' | null;\n setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream>;\n switchCamera(cameraId: string): Promise<void>;\n flipToNextCamera(): Promise<void>;\n savePreference(): void;\n loadPreference(): void;\n isRearCamera(stream: MediaStream): boolean;\n setTorchEnabled(enabled: boolean, stream?: MediaStream): Promise<boolean>;\n focusAtPoint(x: number, y: number, stream?: MediaStream): Promise<boolean>;\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n };\n}"]}