@trustchex/react-native-sdk 1.360.0 → 1.362.0

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 (59) hide show
  1. package/TrustchexSDK.podspec +3 -1
  2. package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKPackage.kt +0 -13
  3. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraManager.kt +0 -8
  4. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +59 -39
  5. package/android/src/main/java/com/trustchex/reactnativesdk/opencv/OpenCVModule.kt +94 -13
  6. package/ios/Camera/TrustchexCameraManager.m +0 -2
  7. package/ios/Camera/TrustchexCameraManager.swift +0 -7
  8. package/ios/Camera/TrustchexCameraView.swift +16 -47
  9. package/ios/OpenCV/OpenCVHelper.h +17 -0
  10. package/ios/OpenCV/OpenCVHelper.mm +128 -0
  11. package/ios/OpenCV/OpenCVModule.h +6 -0
  12. package/ios/OpenCV/OpenCVModule.mm +141 -0
  13. package/ios/TrustchexSDK-Bridging-Header.h +8 -0
  14. package/lib/module/Screens/Debug/MRZTestScreen.js +175 -0
  15. package/lib/module/Shared/Components/DebugNavigationPanel.js +4 -0
  16. package/lib/module/Shared/Components/EIDScanner.js +0 -78
  17. package/lib/module/Shared/Components/FaceCamera.js +6 -3
  18. package/lib/module/Shared/Components/IdentityDocumentCamera.js +199 -153
  19. package/lib/module/Shared/Components/QrCodeScannerCamera.js +0 -3
  20. package/lib/module/Shared/Config/camera-enhancement.config.js +11 -12
  21. package/lib/module/Shared/Libs/mrz.utils.js +265 -0
  22. package/lib/module/Trustchex.js +4 -0
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/version.js +1 -1
  25. package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts +3 -0
  26. package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts.map +1 -0
  27. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  28. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  29. package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
  30. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts +3 -1
  31. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  32. package/lib/typescript/src/Shared/Components/QrCodeScannerCamera.d.ts.map +1 -1
  33. package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts +0 -19
  34. package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts.map +1 -1
  35. package/lib/typescript/src/Shared/Config/camera-enhancement.config.d.ts +10 -10
  36. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts +18 -1
  37. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  38. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  39. package/lib/typescript/src/index.d.ts +3 -0
  40. package/lib/typescript/src/index.d.ts.map +1 -1
  41. package/lib/typescript/src/version.d.ts +1 -1
  42. package/package.json +2 -1
  43. package/src/Screens/Debug/MRZTestScreen.tsx +209 -0
  44. package/src/Shared/Components/DebugNavigationPanel.tsx +5 -0
  45. package/src/Shared/Components/EIDScanner.tsx +0 -53
  46. package/src/Shared/Components/FaceCamera.tsx +6 -3
  47. package/src/Shared/Components/IdentityDocumentCamera.tsx +246 -149
  48. package/src/Shared/Components/QrCodeScannerCamera.tsx +0 -9
  49. package/src/Shared/Components/TrustchexCamera.tsx +0 -20
  50. package/src/Shared/Config/camera-enhancement.config.ts +6 -6
  51. package/src/Shared/Libs/mrz.utils.ts +289 -1
  52. package/src/Trustchex.tsx +5 -0
  53. package/src/index.tsx +3 -0
  54. package/src/version.ts +1 -1
  55. package/android/src/main/java/com/trustchex/reactnativesdk/mrz/MRZValidationModule.kt +0 -785
  56. package/android/src/main/java/com/trustchex/reactnativesdk/mrz/MRZValidator.kt +0 -419
  57. package/ios/MRZValidation.m +0 -39
  58. package/ios/MRZValidation.swift +0 -802
  59. package/ios/MRZValidator.swift +0 -466
@@ -2,10 +2,11 @@
2
2
 
3
3
  /* eslint-disable react-native/no-inline-styles */
4
4
  import React, { useEffect, useState, useRef, useCallback } from 'react';
5
- import { View, StyleSheet, Text as TextView, Platform, StatusBar, Vibration, Linking, Image, ActivityIndicator, PermissionsAndroid, Dimensions } from 'react-native';
5
+ import { View, StyleSheet, Text as TextView, Platform, StatusBar, Vibration, Linking, Image, ActivityIndicator, PermissionsAndroid, Dimensions, ScrollView } from 'react-native';
6
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
7
  import { TrustchexCamera } from "./TrustchexCamera.js";
8
8
  import { NativeModules } from 'react-native';
9
+ import mrzUtils from "../Libs/mrz.utils.js";
9
10
  import { useKeepAwake } from "../Libs/native-keep-awake.utils.js";
10
11
  import { useIsFocused } from '@react-navigation/native';
11
12
  import { useTranslation } from 'react-i18next';
@@ -24,11 +25,12 @@ const HOLOGRAM_IMAGE_COUNT = 12;
24
25
  const HOLOGRAM_DETECTION_THRESHOLD = 1000; // Lowered for better sensitivity while still filtering noise
25
26
  const HOLOGRAM_DETECTION_RETRY_COUNT = 3; // More attempts but faster each (~1s per attempt)
26
27
  const SECOND_FACE_DETECTION_RETRY_COUNT = 10;
27
- const MIN_BRIGHTNESS_THRESHOLD = 50;
28
+ const MIN_BRIGHTNESS_THRESHOLD = 45;
28
29
  const MAX_CONSECUTIVE_QUALITY_FAILURES = 30;
29
30
  const IdentityDocumentCamera = ({
30
31
  onlyMRZScan,
31
- onIdentityDocumentScanned
32
+ onIdentityDocumentScanned,
33
+ testMode = false
32
34
  }) => {
33
35
  useKeepAwake();
34
36
  const theme = useTheme();
@@ -84,6 +86,9 @@ const IdentityDocumentCamera = ({
84
86
  // Barcode caching - persist detected barcode across frames for reliability
85
87
  const cachedBarcode = useRef(null);
86
88
 
89
+ // Test mode tracking
90
+ const [testModeData, setTestModeData] = useState(null);
91
+
87
92
  // Helper to compare MRZ field values (ignore raw text variations)
88
93
  const areMRZFieldsEqual = useCallback((fields1, fields2) => {
89
94
  if (!fields1 || !fields2) return false;
@@ -355,7 +360,7 @@ const IdentityDocumentCamera = ({
355
360
  }, 1000);
356
361
  }
357
362
  }, [setIsTorchOn]);
358
- const handleFaceAndText = useCallback(async (text, faces, frameWidth, frameHeight, barcode, image, elementsOutside, nativeMrzResult) => {
363
+ const handleFaceAndText = useCallback(async (text, faces, frameWidth, frameHeight, barcode, image, elementsOutside, scannedText) => {
359
364
  const detectDocumentType = (facesParam, ocrText, mrzFields, frameWidthParam, mrzTextParam) => {
360
365
  // Relaxed signature detection: matches signature/imza variants and OCR errors
361
366
  const hasSignatureMatch = /s[gi]g?n[au]?t[u]?r|imz[a]s?/i.test(ocrText);
@@ -530,17 +535,44 @@ const IdentityDocumentCamera = ({
530
535
  setStatus('SEARCHING');
531
536
  return;
532
537
  }
533
- const parsedMRZData = nativeMrzResult?.valid && nativeMrzResult.documentCode ? {
534
- valid: true,
535
- fields: nativeMrzResult
536
- } : nativeMrzResult?.documentCode ? {
537
- valid: false,
538
- fields: nativeMrzResult
539
- } : {
540
- valid: false,
541
- fields: null
538
+
539
+ // Use JavaScript MRZ validation with corrections
540
+ // Prefer MRZ-only text if available (from detected MRZ blocks),
541
+ // otherwise fall back to all text (for backward compatibility)
542
+ const textForValidation = scannedText?.mrzOnlyText || text;
543
+ const mrzValidationResult = mrzUtils.validateMRZWithCorrections(textForValidation);
544
+ const parsedMRZData = {
545
+ valid: mrzValidationResult.valid,
546
+ fields: mrzValidationResult.fields || null
542
547
  };
543
- const mrzText = parsedMRZData.valid ? nativeMrzResult?.rawLines : null;
548
+
549
+ // Capture test mode data
550
+ if (testMode && text && text.includes('<')) {
551
+ const mrzOnlyText = scannedText?.mrzOnlyText || text;
552
+ setTestModeData({
553
+ mrzText: mrzOnlyText,
554
+ timestamp: Date.now()
555
+ });
556
+ }
557
+
558
+ // Log MRZ validation details for debugging
559
+ if (isDebugEnabled() && text && text.includes('<')) {
560
+ const mrzLines = text.split('\n').filter(line => line.includes('<') && line.length > 20);
561
+ if (mrzLines.length >= 2) {
562
+ console.log('[MRZ Debug] Raw OCR text lines:', mrzLines.map(l => `"${l}"`));
563
+ console.log('[MRZ Debug] Validation result:', {
564
+ valid: mrzValidationResult.valid,
565
+ format: mrzValidationResult.format,
566
+ documentCode: mrzValidationResult.fields?.documentCode,
567
+ documentNumber: mrzValidationResult.fields?.documentNumber,
568
+ optional1: mrzValidationResult.fields?.optional1,
569
+ error: mrzValidationResult.error
570
+ });
571
+ }
572
+ }
573
+
574
+ // Extract raw MRZ lines from text if validation succeeded
575
+ const mrzText = parsedMRZData.valid ? mrzUtils.fixMRZ(text) : null;
544
576
 
545
577
  // MRZ stability check - require consistent valid reads to avoid OCR noise
546
578
  // Compare parsed field values instead of raw text to handle OCR variations in filler characters
@@ -609,9 +641,17 @@ const IdentityDocumentCamera = ({
609
641
  // CRITICAL: Only accept MRZ with valid checksums AND consistent reads
610
642
  // AND ensure all required fields are present
611
643
  const mrzAccepted = parsedMRZData?.valid === true && hasRequiredFields && mrzStableAndValid;
644
+
645
+ // For Turkish ID cards, barcode should match MRZ optional1 (serial number)
646
+ // But some cards have encoding differences, so be lenient
612
647
  const barcodeMatchesMRZ = barcodeToUse?.rawValue?.trim() === parsedMRZData?.fields?.optional1?.trim();
648
+
649
+ // If barcode doesn't match exactly, check if it contains the optional1 value
650
+ const barcodeContainsMRZ = barcodeToUse?.rawValue?.includes(parsedMRZData?.fields?.optional1?.trim() || '') || parsedMRZData?.fields?.optional1?.includes(barcodeToUse?.rawValue?.trim() || '');
651
+
613
652
  // Require barcode for all documents (no special card fallback)
614
- const barcodeAccepted = onlyMRZScan || barcodeMatchesMRZ;
653
+ // Accept if exact match OR if one contains the other (handles encoding differences)
654
+ const barcodeAccepted = onlyMRZScan || barcodeMatchesMRZ || !!barcodeToUse?.rawValue && barcodeContainsMRZ;
615
655
 
616
656
  // CRITICAL: Require all document elements to be in frame before accepting
617
657
  // For ID_BACK: MRZ + barcode (check directly, not via state to avoid timing issues)
@@ -652,8 +692,11 @@ const IdentityDocumentCamera = ({
652
692
  onlyMRZScan,
653
693
  hasBarcodeValue: !!barcodeToUse?.rawValue,
654
694
  barcodeMatchesMRZ,
695
+ barcodeContainsMRZ,
655
696
  mrzOptional1: parsedMRZData?.fields?.optional1,
656
697
  barcodeValue: barcodeToUse?.rawValue,
698
+ barcodeValueTrimmed: barcodeToUse?.rawValue?.trim(),
699
+ optional1Trimmed: parsedMRZData?.fields?.optional1?.trim(),
657
700
  barcodeSource: barcodeToUse === cachedBarcode.current ? 'cached' : 'current'
658
701
  });
659
702
  }
@@ -1158,7 +1201,7 @@ const IdentityDocumentCamera = ({
1158
1201
  }
1159
1202
  setStatus('SCANNING');
1160
1203
  }
1161
- }, [nextStep, frameDimensions, currentHologramImage, currentFaceImage, hasRequiredMRZFields, areMRZFieldsEqual, detectedDocumentType, onlyMRZScan, isTorchOn, setIsTorchOn, setNextStepAndVibrate, onIdentityDocumentScanned, logMRZDetails, logMRZValidationFailure, currentSecondaryFaceImage, detectHologramNative]);
1204
+ }, [nextStep, frameDimensions, currentHologramImage, currentFaceImage, hasRequiredMRZFields, areMRZFieldsEqual, detectedDocumentType, onlyMRZScan, isTorchOn, setIsTorchOn, setNextStepAndVibrate, onIdentityDocumentScanned, logMRZDetails, logMRZValidationFailure, currentSecondaryFaceImage, detectHologramNative, mrzUtils]);
1162
1205
  const handleFrame = useCallback(async event => {
1163
1206
  if (!isCameraInitialized.current) {
1164
1207
  return;
@@ -1178,7 +1221,15 @@ const IdentityDocumentCamera = ({
1178
1221
  }
1179
1222
  const avgBrightness = brightnessHistory.current.reduce((a, b) => a + b, 0) / brightnessHistory.current.length;
1180
1223
  const isOverallBright = avgBrightness >= MIN_BRIGHTNESS_THRESHOLD;
1181
- setIsBrightnessLow(!isOverallBright);
1224
+
1225
+ // Check brightness in center region (area of interest)
1226
+ let isRegionBright = false;
1227
+ try {
1228
+ isRegionBright = await OpenCVModule.isRectangularRegionBright(base64Image, Math.round(frame.width * 0.2), Math.round(frame.height * 0.2), Math.round(frame.width * 0.6), Math.round(frame.height * 0.6), MIN_BRIGHTNESS_THRESHOLD);
1229
+ } catch (error) {
1230
+ isRegionBright = isOverallBright;
1231
+ }
1232
+ setIsBrightnessLow(!isRegionBright);
1182
1233
 
1183
1234
  // Check blur only in center region (area of interest) to avoid false positives
1184
1235
  // from iOS depth-of-field background blur
@@ -1204,7 +1255,7 @@ const IdentityDocumentCamera = ({
1204
1255
  }
1205
1256
 
1206
1257
  // Only proceed if image quality is acceptable
1207
- const hasAcceptableQuality = isOverallBright && isNotBlurry;
1258
+ const hasAcceptableQuality = isRegionBright && isNotBlurry;
1208
1259
 
1209
1260
  // Store quality metrics in ref for access in handleFaceAndText callback
1210
1261
  lastFrameQuality.current = {
@@ -1245,6 +1296,8 @@ const IdentityDocumentCamera = ({
1245
1296
  const resultText = textBlocks.map(b => b.text).join('\n');
1246
1297
  const scannedText = {
1247
1298
  resultText,
1299
+ mrzOnlyText: undefined,
1300
+ // Will be set below if MRZ blocks detected
1248
1301
  blocks: textBlocks.map(block => ({
1249
1302
  blockText: block.text || '',
1250
1303
  blockFrame: block.blockFrame ?? {
@@ -1415,6 +1468,12 @@ const IdentityDocumentCamera = ({
1415
1468
  const mrzBlocks = textBlocks.filter(block => block.blockFrame && block.blockFrame.y > bottomHalf && mrzPattern.test(block.text));
1416
1469
  console.log('[Debug] MRZ blocks found:', mrzBlocks.length);
1417
1470
  if (mrzBlocks.length > 0) {
1471
+ // Extract MRZ-only text from detected blocks (sorted by Y position for correct line order)
1472
+ const sortedMrzBlocks = [...mrzBlocks].sort((a, b) => (a.blockFrame?.y || 0) - (b.blockFrame?.y || 0));
1473
+ scannedText.mrzOnlyText = sortedMrzBlocks.map(b => b.text).join('\n');
1474
+ if (isDebugEnabled()) {
1475
+ console.log('[MRZ Extraction] Using only MRZ blocks:', scannedText.mrzOnlyText.substring(0, 100));
1476
+ }
1418
1477
  const minX = Math.min(...mrzBlocks.map(b => b.blockFrame.x));
1419
1478
  const minY = Math.min(...mrzBlocks.map(b => b.blockFrame.y));
1420
1479
  const maxX = Math.max(...mrzBlocks.map(b => b.blockFrame.x + b.blockFrame.width));
@@ -1652,7 +1711,7 @@ const IdentityDocumentCamera = ({
1652
1711
  }
1653
1712
  }
1654
1713
  setElementsOutsideScanArea(outsideElements);
1655
- handleFaceAndText(scannedText.resultText ?? '', detectedFaces, frame.width, frame.height, barcodes.length ? barcodes[0] : undefined, base64Image, outsideElements.length > 0, frame.mrzResult);
1714
+ handleFaceAndText(scannedText.resultText ?? '', detectedFaces, frame.width, frame.height, barcodes.length ? barcodes[0] : undefined, base64Image, outsideElements.length > 0, scannedText);
1656
1715
  } catch (error) {
1657
1716
  console.warn('Frame processing error:', error?.message);
1658
1717
  }
@@ -1737,7 +1796,6 @@ const IdentityDocumentCamera = ({
1737
1796
  enableFrameProcessing: isActive,
1738
1797
  enableFaceDetection: isActive && faceDetectionEnabled,
1739
1798
  enableTextRecognition: isActive,
1740
- enableMrzValidation: isActive,
1741
1799
  enableBarcodeScanning: isActive && nextStep === 'SCAN_ID_BACK',
1742
1800
  includeBase64: isActive,
1743
1801
  targetFps: 10,
@@ -2176,32 +2234,6 @@ const IdentityDocumentCamera = ({
2176
2234
  }],
2177
2235
  children: `${currentSecondaryFaceImage ? '✓ ' : ''}2nd Face`
2178
2236
  })]
2179
- }), isDebugEnabled() && /*#__PURE__*/_jsxs(View, {
2180
- style: styles.imageContainer,
2181
- children: [_currentHologramMaskImage ? /*#__PURE__*/_jsx(Image, {
2182
- source: {
2183
- uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`
2184
- },
2185
- style: styles.faceImage
2186
- }) : /*#__PURE__*/_jsx(View, {
2187
- style: [styles.faceImage, {
2188
- backgroundColor: '#333',
2189
- justifyContent: 'center'
2190
- }],
2191
- children: /*#__PURE__*/_jsx(TextView, {
2192
- style: {
2193
- color: '#666',
2194
- fontSize: 10,
2195
- textAlign: 'center'
2196
- },
2197
- children: "Waiting..."
2198
- })
2199
- }), /*#__PURE__*/_jsx(TextView, {
2200
- style: [styles.imageContainerText, _currentHologramMaskImage && {
2201
- color: '#4CAF50'
2202
- }],
2203
- children: `${_currentHologramMaskImage ? '✓ ' : ''}Mask`
2204
- })]
2205
2237
  }), isDebugEnabled() && /*#__PURE__*/_jsxs(View, {
2206
2238
  style: styles.imageContainer,
2207
2239
  children: [currentHologramImage ? /*#__PURE__*/_jsx(Image, {
@@ -2261,31 +2293,30 @@ const IdentityDocumentCamera = ({
2261
2293
  children: `${currentHologramImage ? '✓ ' : latestHologramFaceImage ? '⏳ ' : ''}Hologram`
2262
2294
  })]
2263
2295
  }), isDebugEnabled() && /*#__PURE__*/_jsxs(View, {
2264
- style: styles.debugInfoContainer,
2265
- children: [/*#__PURE__*/_jsx(TextView, {
2266
- style: styles.debugInfoText,
2267
- children: `Step: ${nextStep}`
2268
- }), /*#__PURE__*/_jsx(TextView, {
2269
- style: styles.debugInfoText,
2270
- children: `Status: ${status}`
2271
- }), /*#__PURE__*/_jsx(TextView, {
2272
- style: styles.debugInfoText,
2273
- children: `Face: ${currentFaceImage ? '✓ CAPTURED' : '✗ WAITING'} ${!faceDetectionEnabled ? '(DISABLED)' : ''}`
2274
- }), /*#__PURE__*/_jsx(TextView, {
2275
- style: styles.debugInfoText,
2276
- children: `Hologram: ${currentHologramImage ? '✓ CAPTURED' : `${hologramImageCount}/${HOLOGRAM_IMAGE_COUNT} imgs`} (retry ${hologramDetectionCurrentRetryCount.current}/${HOLOGRAM_DETECTION_RETRY_COUNT})`
2277
- }), /*#__PURE__*/_jsx(TextView, {
2278
- style: styles.debugInfoText,
2279
- children: `2nd Face: ${currentSecondaryFaceImage ? '✓ CAPTURED' : '✗ WAITING'} (retry ${secondaryFaceDetectionCurrentRetryCount.current}/${SECOND_FACE_DETECTION_RETRY_COUNT})`
2280
- }), /*#__PURE__*/_jsx(TextView, {
2281
- style: styles.debugInfoText,
2282
- children: `Flash: ${isTorchOn ? '🔦 ON' : '🔦 OFF'}`
2283
- }), /*#__PURE__*/_jsx(TextView, {
2284
- style: styles.debugInfoText,
2285
- children: `Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓ OK'}`
2296
+ style: styles.imageContainer,
2297
+ children: [_currentHologramMaskImage ? /*#__PURE__*/_jsx(Image, {
2298
+ source: {
2299
+ uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`
2300
+ },
2301
+ style: styles.faceImage
2302
+ }) : /*#__PURE__*/_jsx(View, {
2303
+ style: [styles.faceImage, {
2304
+ backgroundColor: '#333',
2305
+ justifyContent: 'center'
2306
+ }],
2307
+ children: /*#__PURE__*/_jsx(TextView, {
2308
+ style: {
2309
+ color: '#666',
2310
+ fontSize: 10,
2311
+ textAlign: 'center'
2312
+ },
2313
+ children: "Waiting..."
2314
+ })
2286
2315
  }), /*#__PURE__*/_jsx(TextView, {
2287
- style: styles.debugInfoText,
2288
- children: `Blur: ${isFrameBlurry ? '⚠️ BLURRY' : '✓ OK'}`
2316
+ style: [styles.imageContainerText, _currentHologramMaskImage && {
2317
+ color: '#4CAF50'
2318
+ }],
2319
+ children: `${_currentHologramMaskImage ? '✓ ' : ''}Mask`
2289
2320
  })]
2290
2321
  })]
2291
2322
  })
@@ -2315,98 +2346,123 @@ const IdentityDocumentCamera = ({
2315
2346
  loop: true,
2316
2347
  autoPlay: true
2317
2348
  }) : null
2318
- }), isDebugEnabled() && /*#__PURE__*/_jsxs(View, {
2349
+ }), isDebugEnabled() && /*#__PURE__*/_jsx(SafeAreaView, {
2319
2350
  style: {
2320
2351
  position: 'absolute',
2321
- top: 10,
2322
- right: 10,
2323
- backgroundColor: 'rgba(0, 0, 0, 0.85)',
2324
- padding: 10,
2325
- borderRadius: 8,
2326
- borderWidth: 1,
2327
- borderColor: '#FF6B6B',
2328
- maxWidth: 200
2352
+ top: 0,
2353
+ left: 0,
2354
+ right: 0,
2355
+ alignItems: 'center',
2356
+ pointerEvents: 'none'
2329
2357
  },
2330
- children: [/*#__PURE__*/_jsx(TextView, {
2331
- style: {
2332
- color: '#FF6B6B',
2333
- fontSize: 11,
2334
- fontWeight: 'bold',
2335
- marginBottom: 6
2336
- },
2337
- children: "\uD83D\uDC1B DEBUG MODE"
2338
- }), /*#__PURE__*/_jsx(TextView, {
2339
- style: {
2340
- color: '#88D8B0',
2341
- fontSize: 9,
2342
- marginBottom: 2
2343
- },
2344
- children: `Step: ${nextStep}`
2345
- }), /*#__PURE__*/_jsx(TextView, {
2346
- style: {
2347
- color: '#88D8B0',
2348
- fontSize: 9,
2349
- marginBottom: 2
2350
- },
2351
- children: `Status: ${status}`
2352
- }), /*#__PURE__*/_jsx(TextView, {
2353
- style: {
2354
- color: '#88D8B0',
2355
- fontSize: 9,
2356
- marginBottom: 2
2357
- },
2358
- children: `Doc Type: ${detectedDocumentType}`
2359
- }), /*#__PURE__*/_jsx(TextView, {
2358
+ children: /*#__PURE__*/_jsxs(View, {
2360
2359
  style: {
2361
- color: '#88D8B0',
2362
- fontSize: 9,
2363
- marginBottom: 2
2360
+ marginTop: 10,
2361
+ backgroundColor: 'rgba(0, 0, 0, 0.85)',
2362
+ padding: 10,
2363
+ borderRadius: 8,
2364
+ borderWidth: 1,
2365
+ borderColor: '#FF6B6B',
2366
+ minWidth: 200
2364
2367
  },
2365
- children: `Face: ${currentFaceImage ? '✓' : '✗'}`
2366
- }), !onlyMRZScan && /*#__PURE__*/_jsxs(_Fragment, {
2367
2368
  children: [/*#__PURE__*/_jsx(TextView, {
2369
+ style: {
2370
+ color: '#FF6B6B',
2371
+ fontSize: 11,
2372
+ fontWeight: 'bold',
2373
+ marginBottom: 6,
2374
+ textAlign: 'center'
2375
+ },
2376
+ children: "DEBUG MODE"
2377
+ }), /*#__PURE__*/_jsx(TextView, {
2368
2378
  style: {
2369
2379
  color: '#88D8B0',
2370
2380
  fontSize: 9,
2371
2381
  marginBottom: 2
2372
2382
  },
2373
- children: `2nd Face: ${currentSecondaryFaceImage ? '✓' : '✗'}`
2383
+ children: `Step: ${nextStep}`
2374
2384
  }), /*#__PURE__*/_jsx(TextView, {
2375
2385
  style: {
2376
2386
  color: '#88D8B0',
2377
2387
  fontSize: 9,
2378
2388
  marginBottom: 2
2379
2389
  },
2380
- children: `Hologram: ${hologramImageCount}/${HOLOGRAM_IMAGE_COUNT}`
2390
+ children: `Status: ${status}`
2391
+ }), /*#__PURE__*/_jsx(TextView, {
2392
+ style: {
2393
+ color: '#88D8B0',
2394
+ fontSize: 9,
2395
+ marginBottom: 2
2396
+ },
2397
+ children: `Doc Type: ${detectedDocumentType}`
2398
+ }), /*#__PURE__*/_jsx(TextView, {
2399
+ style: {
2400
+ color: '#88D8B0',
2401
+ fontSize: 9,
2402
+ marginBottom: 2
2403
+ },
2404
+ children: `Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓'}`
2405
+ }), /*#__PURE__*/_jsx(TextView, {
2406
+ style: {
2407
+ color: '#88D8B0',
2408
+ fontSize: 9,
2409
+ marginBottom: 2
2410
+ },
2411
+ children: `Blur: ${isFrameBlurry ? '⚠️' : '✓'}`
2412
+ }), /*#__PURE__*/_jsx(TextView, {
2413
+ style: {
2414
+ color: '#88D8B0',
2415
+ fontSize: 9,
2416
+ marginBottom: 2
2417
+ },
2418
+ children: `Flash: ${isTorchOn ? '🔦' : '○'}`
2419
+ }), /*#__PURE__*/_jsx(TextView, {
2420
+ style: {
2421
+ color: '#88D8B0',
2422
+ fontSize: 9
2423
+ },
2424
+ children: `Face Detection: ${faceDetectionEnabled ? '✓' : '✗'}`
2381
2425
  })]
2382
- }), /*#__PURE__*/_jsx(TextView, {
2383
- style: {
2384
- color: '#88D8B0',
2385
- fontSize: 9,
2386
- marginBottom: 2
2387
- },
2388
- children: `Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓'}`
2389
- }), /*#__PURE__*/_jsx(TextView, {
2390
- style: {
2391
- color: '#88D8B0',
2392
- fontSize: 9,
2393
- marginBottom: 2
2394
- },
2395
- children: `Blur: ${isFrameBlurry ? '⚠️' : '✓'}`
2396
- }), /*#__PURE__*/_jsx(TextView, {
2397
- style: {
2398
- color: '#88D8B0',
2399
- fontSize: 9,
2400
- marginBottom: 2
2401
- },
2402
- children: `Flash: ${isTorchOn ? '🔦' : '○'}`
2403
- }), /*#__PURE__*/_jsx(TextView, {
2426
+ })
2427
+ }), testMode && testModeData && /*#__PURE__*/_jsx(SafeAreaView, {
2428
+ style: {
2429
+ position: 'absolute',
2430
+ bottom: 0,
2431
+ left: 0,
2432
+ right: 0,
2433
+ maxHeight: '40%',
2434
+ backgroundColor: 'rgba(0, 0, 0, 0.95)',
2435
+ borderTopWidth: 2,
2436
+ borderTopColor: '#FFA500'
2437
+ },
2438
+ children: /*#__PURE__*/_jsx(ScrollView, {
2404
2439
  style: {
2405
- color: '#88D8B0',
2406
- fontSize: 9
2440
+ flex: 1
2407
2441
  },
2408
- children: `Face Detection: ${faceDetectionEnabled ? '✓' : '✗'}`
2409
- })]
2442
+ children: /*#__PURE__*/_jsxs(View, {
2443
+ style: {
2444
+ padding: 10
2445
+ },
2446
+ children: [/*#__PURE__*/_jsx(TextView, {
2447
+ style: {
2448
+ color: '#FFA500',
2449
+ fontSize: 12,
2450
+ fontWeight: 'bold',
2451
+ marginBottom: 8,
2452
+ textAlign: 'center'
2453
+ },
2454
+ children: "MRZ Text Read"
2455
+ }), /*#__PURE__*/_jsx(TextView, {
2456
+ style: {
2457
+ color: '#FFFFFF',
2458
+ fontSize: 9,
2459
+ fontFamily: 'monospace',
2460
+ lineHeight: 16
2461
+ },
2462
+ children: testModeData.mrzText.split('\n').map((line, i) => `Line ${i + 1}: ${line} (${line.length} chars)`).join('\n')
2463
+ })]
2464
+ })
2465
+ })
2410
2466
  })]
2411
2467
  })]
2412
2468
  });
@@ -2515,7 +2571,7 @@ const styles = StyleSheet.create({
2515
2571
  display: 'flex',
2516
2572
  flexDirection: 'row',
2517
2573
  gap: 10,
2518
- justifyContent: 'flex-start',
2574
+ justifyContent: 'center',
2519
2575
  flexWrap: 'wrap'
2520
2576
  },
2521
2577
  cardDetectionRow: {
@@ -2555,16 +2611,6 @@ const styles = StyleSheet.create({
2555
2611
  flexDirection: 'column',
2556
2612
  alignItems: 'center'
2557
2613
  },
2558
- debugInfoContainer: {
2559
- flex: 1,
2560
- paddingLeft: 10
2561
- },
2562
- debugInfoText: {
2563
- color: 'white',
2564
- fontSize: 8,
2565
- fontWeight: 'bold',
2566
- marginBottom: 2
2567
- },
2568
2614
  guide: {
2569
2615
  flex: 1,
2570
2616
  display: 'flex',
@@ -39,12 +39,9 @@ const QrCodeScannerCamera = ({
39
39
  right: width * (0.97 - marginBuffer),
40
40
  bottom: height * (0.65 - marginBuffer)
41
41
  };
42
- console.log(`[QR Frame Check] Frame: ${width}x${height}, Scanning: left=${scanningFrame.left}, top=${scanningFrame.top}, right=${scanningFrame.right}, bottom=${scanningFrame.bottom}`);
43
- console.log(`[QR Frame Check] Code bbox: left=${boundingBox.left}, top=${boundingBox.top}, right=${boundingBox.right}, bottom=${boundingBox.bottom}`);
44
42
 
45
43
  // Check if entire bounding box is within scanning frame (with margin buffer)
46
44
  const isInFrame = boundingBox.left >= scanningFrame.left && boundingBox.top >= scanningFrame.top && boundingBox.right <= scanningFrame.right && boundingBox.bottom <= scanningFrame.bottom;
47
- console.log(`[QR Frame Check] Is in frame: ${isInFrame}`);
48
45
  return isInFrame;
49
46
  };
50
47
  const handleFrame = useCallback(async event => {
@@ -14,30 +14,29 @@ export const ENHANCEMENT_CONFIG = {
14
14
  brightness: {
15
15
  thresholds: {
16
16
  general: {
17
- low: 40,
18
- high: 120,
19
- target: 80
17
+ low: 60,
18
+ high: 140,
19
+ target: 100
20
20
  },
21
21
  faceDetection: {
22
- low: 50,
23
- high: 110,
24
- target: 85
22
+ low: 70,
23
+ high: 140,
24
+ target: 105
25
25
  },
26
26
  mrzScanning: {
27
- low: 45,
28
- high: 130,
29
- target: 80
27
+ low: 65,
28
+ high: 150,
29
+ target: 100
30
30
  }
31
31
  },
32
32
  adaptiveStep: true,
33
33
  maxStepSize: 2,
34
- // Reduced from 3 for smoother transitions
35
- hysteresis: 5 // Dead zone to prevent oscillation
34
+ hysteresis: 5
36
35
  },
37
36
  contrast: {
38
37
  enabled: true,
39
38
  clahe: {
40
- clipLimit: 2.0,
39
+ clipLimit: 1.5,
41
40
  tileGridSize: [8, 8]
42
41
  },
43
42
  applyWhen: {