@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
@@ -12,6 +12,7 @@ import {
12
12
  ActivityIndicator,
13
13
  PermissionsAndroid,
14
14
  Dimensions,
15
+ ScrollView,
15
16
  type NativeSyntheticEvent,
16
17
  type ViewStyle,
17
18
  } from 'react-native';
@@ -23,6 +24,7 @@ import {
23
24
  } from './TrustchexCamera';
24
25
  import { NativeModules } from 'react-native';
25
26
  import type { MRZFields } from '../Types/mrzFields';
27
+ import mrzUtils from '../Libs/mrz.utils';
26
28
  import { useKeepAwake } from '../Libs/native-keep-awake.utils';
27
29
  import { useIsFocused } from '@react-navigation/native';
28
30
  import { useTranslation } from 'react-i18next';
@@ -50,6 +52,7 @@ export type DocumentScannedData = {
50
52
  export type BlockText = {
51
53
  blocks: BlocksData[];
52
54
  resultText: string;
55
+ mrzOnlyText?: string; // MRZ-specific text from detected MRZ blocks only
53
56
  };
54
57
 
55
58
  type BlocksData = {
@@ -97,6 +100,7 @@ export type PhotoOptions = {
97
100
  export interface IdentityDocumentCameraProps {
98
101
  onlyMRZScan: boolean;
99
102
  onIdentityDocumentScanned: (scannedData: DocumentScannedData) => void;
103
+ testMode?: boolean;
100
104
  }
101
105
 
102
106
  interface Face {
@@ -122,12 +126,13 @@ const HOLOGRAM_IMAGE_COUNT = 12;
122
126
  const HOLOGRAM_DETECTION_THRESHOLD = 1000; // Lowered for better sensitivity while still filtering noise
123
127
  const HOLOGRAM_DETECTION_RETRY_COUNT = 3; // More attempts but faster each (~1s per attempt)
124
128
  const SECOND_FACE_DETECTION_RETRY_COUNT = 10;
125
- const MIN_BRIGHTNESS_THRESHOLD = 50;
129
+ const MIN_BRIGHTNESS_THRESHOLD = 45;
126
130
  const MAX_CONSECUTIVE_QUALITY_FAILURES = 30;
127
131
 
128
132
  const IdentityDocumentCamera = ({
129
133
  onlyMRZScan,
130
134
  onIdentityDocumentScanned,
135
+ testMode = false,
131
136
  }: IdentityDocumentCameraProps) => {
132
137
  useKeepAwake();
133
138
  const theme = useTheme();
@@ -201,6 +206,12 @@ const IdentityDocumentCamera = ({
201
206
  // Barcode caching - persist detected barcode across frames for reliability
202
207
  const cachedBarcode = useRef<Barcode | null>(null);
203
208
 
209
+ // Test mode tracking
210
+ const [testModeData, setTestModeData] = useState<{
211
+ mrzText: string;
212
+ timestamp: number;
213
+ } | null>(null);
214
+
204
215
  // Helper to compare MRZ field values (ignore raw text variations)
205
216
  const areMRZFieldsEqual = useCallback(
206
217
  (fields1: any, fields2: any): boolean => {
@@ -699,7 +710,7 @@ const IdentityDocumentCamera = ({
699
710
  barcode?: Barcode,
700
711
  image?: string,
701
712
  elementsOutside?: boolean,
702
- nativeMrzResult?: Frame['mrzResult']
713
+ scannedText?: BlockText
703
714
  ) => {
704
715
  const detectDocumentType = (
705
716
  facesParam: Face[],
@@ -970,13 +981,49 @@ const IdentityDocumentCamera = ({
970
981
  return;
971
982
  }
972
983
 
973
- const parsedMRZData =
974
- nativeMrzResult?.valid && nativeMrzResult.documentCode
975
- ? { valid: true, fields: nativeMrzResult as MRZFields }
976
- : nativeMrzResult?.documentCode
977
- ? { valid: false, fields: nativeMrzResult as MRZFields }
978
- : { valid: false, fields: null };
979
- const mrzText = parsedMRZData.valid ? nativeMrzResult?.rawLines : null;
984
+ // Use JavaScript MRZ validation with corrections
985
+ // Prefer MRZ-only text if available (from detected MRZ blocks),
986
+ // otherwise fall back to all text (for backward compatibility)
987
+ const textForValidation = scannedText?.mrzOnlyText || text;
988
+ const mrzValidationResult =
989
+ mrzUtils.validateMRZWithCorrections(textForValidation);
990
+ const parsedMRZData = {
991
+ valid: mrzValidationResult.valid,
992
+ fields: mrzValidationResult.fields || null,
993
+ };
994
+
995
+ // Capture test mode data
996
+ if (testMode && text && text.includes('<')) {
997
+ const mrzOnlyText = scannedText?.mrzOnlyText || text;
998
+ setTestModeData({
999
+ mrzText: mrzOnlyText,
1000
+ timestamp: Date.now(),
1001
+ });
1002
+ }
1003
+
1004
+ // Log MRZ validation details for debugging
1005
+ if (isDebugEnabled() && text && text.includes('<')) {
1006
+ const mrzLines = text
1007
+ .split('\n')
1008
+ .filter((line) => line.includes('<') && line.length > 20);
1009
+ if (mrzLines.length >= 2) {
1010
+ console.log(
1011
+ '[MRZ Debug] Raw OCR text lines:',
1012
+ mrzLines.map((l) => `"${l}"`)
1013
+ );
1014
+ console.log('[MRZ Debug] Validation result:', {
1015
+ valid: mrzValidationResult.valid,
1016
+ format: mrzValidationResult.format,
1017
+ documentCode: mrzValidationResult.fields?.documentCode,
1018
+ documentNumber: mrzValidationResult.fields?.documentNumber,
1019
+ optional1: mrzValidationResult.fields?.optional1,
1020
+ error: mrzValidationResult.error,
1021
+ });
1022
+ }
1023
+ }
1024
+
1025
+ // Extract raw MRZ lines from text if validation succeeded
1026
+ const mrzText = parsedMRZData.valid ? mrzUtils.fixMRZ(text) : null;
980
1027
 
981
1028
  // MRZ stability check - require consistent valid reads to avoid OCR noise
982
1029
  // Compare parsed field values instead of raw text to handle OCR variations in filler characters
@@ -1071,11 +1118,28 @@ const IdentityDocumentCamera = ({
1071
1118
  parsedMRZData?.valid === true &&
1072
1119
  hasRequiredFields &&
1073
1120
  mrzStableAndValid;
1121
+
1122
+ // For Turkish ID cards, barcode should match MRZ optional1 (serial number)
1123
+ // But some cards have encoding differences, so be lenient
1074
1124
  const barcodeMatchesMRZ =
1075
1125
  barcodeToUse?.rawValue?.trim() ===
1076
1126
  parsedMRZData?.fields?.optional1?.trim();
1127
+
1128
+ // If barcode doesn't match exactly, check if it contains the optional1 value
1129
+ const barcodeContainsMRZ =
1130
+ barcodeToUse?.rawValue?.includes(
1131
+ parsedMRZData?.fields?.optional1?.trim() || ''
1132
+ ) ||
1133
+ parsedMRZData?.fields?.optional1?.includes(
1134
+ barcodeToUse?.rawValue?.trim() || ''
1135
+ );
1136
+
1077
1137
  // Require barcode for all documents (no special card fallback)
1078
- const barcodeAccepted = onlyMRZScan || barcodeMatchesMRZ;
1138
+ // Accept if exact match OR if one contains the other (handles encoding differences)
1139
+ const barcodeAccepted =
1140
+ onlyMRZScan ||
1141
+ barcodeMatchesMRZ ||
1142
+ (!!barcodeToUse?.rawValue && barcodeContainsMRZ);
1079
1143
 
1080
1144
  // CRITICAL: Require all document elements to be in frame before accepting
1081
1145
  // For ID_BACK: MRZ + barcode (check directly, not via state to avoid timing issues)
@@ -1140,8 +1204,11 @@ const IdentityDocumentCamera = ({
1140
1204
  onlyMRZScan,
1141
1205
  hasBarcodeValue: !!barcodeToUse?.rawValue,
1142
1206
  barcodeMatchesMRZ,
1207
+ barcodeContainsMRZ,
1143
1208
  mrzOptional1: parsedMRZData?.fields?.optional1,
1144
1209
  barcodeValue: barcodeToUse?.rawValue,
1210
+ barcodeValueTrimmed: barcodeToUse?.rawValue?.trim(),
1211
+ optional1Trimmed: parsedMRZData?.fields?.optional1?.trim(),
1145
1212
  barcodeSource:
1146
1213
  barcodeToUse === cachedBarcode.current
1147
1214
  ? 'cached'
@@ -1864,6 +1931,7 @@ const IdentityDocumentCamera = ({
1864
1931
  logMRZValidationFailure,
1865
1932
  currentSecondaryFaceImage,
1866
1933
  detectHologramNative,
1934
+ mrzUtils,
1867
1935
  ]
1868
1936
  );
1869
1937
 
@@ -1897,7 +1965,22 @@ const IdentityDocumentCamera = ({
1897
1965
  brightnessHistory.current.length;
1898
1966
  const isOverallBright = avgBrightness >= MIN_BRIGHTNESS_THRESHOLD;
1899
1967
 
1900
- setIsBrightnessLow(!isOverallBright);
1968
+ // Check brightness in center region (area of interest)
1969
+ let isRegionBright = false;
1970
+ try {
1971
+ isRegionBright = await OpenCVModule.isRectangularRegionBright(
1972
+ base64Image,
1973
+ Math.round(frame.width * 0.2),
1974
+ Math.round(frame.height * 0.2),
1975
+ Math.round(frame.width * 0.6),
1976
+ Math.round(frame.height * 0.6),
1977
+ MIN_BRIGHTNESS_THRESHOLD
1978
+ );
1979
+ } catch (error) {
1980
+ isRegionBright = isOverallBright;
1981
+ }
1982
+
1983
+ setIsBrightnessLow(!isRegionBright);
1901
1984
 
1902
1985
  // Check blur only in center region (area of interest) to avoid false positives
1903
1986
  // from iOS depth-of-field background blur
@@ -1921,7 +2004,7 @@ const IdentityDocumentCamera = ({
1921
2004
  }
1922
2005
 
1923
2006
  // Only proceed if image quality is acceptable
1924
- const hasAcceptableQuality = isOverallBright && isNotBlurry;
2007
+ const hasAcceptableQuality = isRegionBright && isNotBlurry;
1925
2008
 
1926
2009
  // Store quality metrics in ref for access in handleFaceAndText callback
1927
2010
  lastFrameQuality.current = {
@@ -1967,6 +2050,7 @@ const IdentityDocumentCamera = ({
1967
2050
  const resultText = textBlocks.map((b) => b.text).join('\n');
1968
2051
  const scannedText: BlockText = {
1969
2052
  resultText,
2053
+ mrzOnlyText: undefined, // Will be set below if MRZ blocks detected
1970
2054
  blocks: textBlocks.map((block) => ({
1971
2055
  blockText: block.text || '',
1972
2056
  blockFrame: block.blockFrame ?? {
@@ -2171,6 +2255,20 @@ const IdentityDocumentCamera = ({
2171
2255
 
2172
2256
  console.log('[Debug] MRZ blocks found:', mrzBlocks.length);
2173
2257
  if (mrzBlocks.length > 0) {
2258
+ // Extract MRZ-only text from detected blocks (sorted by Y position for correct line order)
2259
+ const sortedMrzBlocks = [...mrzBlocks].sort(
2260
+ (a, b) => (a.blockFrame?.y || 0) - (b.blockFrame?.y || 0)
2261
+ );
2262
+ scannedText.mrzOnlyText = sortedMrzBlocks
2263
+ .map((b) => b.text)
2264
+ .join('\n');
2265
+ if (isDebugEnabled()) {
2266
+ console.log(
2267
+ '[MRZ Extraction] Using only MRZ blocks:',
2268
+ scannedText.mrzOnlyText.substring(0, 100)
2269
+ );
2270
+ }
2271
+
2174
2272
  const minX = Math.min(...mrzBlocks.map((b) => b.blockFrame!.x));
2175
2273
  const minY = Math.min(...mrzBlocks.map((b) => b.blockFrame!.y));
2176
2274
  const maxX = Math.max(
@@ -2505,7 +2603,7 @@ const IdentityDocumentCamera = ({
2505
2603
  barcodes.length ? barcodes[0] : undefined,
2506
2604
  base64Image,
2507
2605
  outsideElements.length > 0,
2508
- frame.mrzResult
2606
+ scannedText
2509
2607
  );
2510
2608
  } catch (error: any) {
2511
2609
  console.warn('Frame processing error:', error?.message);
@@ -2611,7 +2709,6 @@ const IdentityDocumentCamera = ({
2611
2709
  enableFrameProcessing={isActive}
2612
2710
  enableFaceDetection={isActive && faceDetectionEnabled}
2613
2711
  enableTextRecognition={isActive}
2614
- enableMrzValidation={isActive}
2615
2712
  enableBarcodeScanning={isActive && nextStep === 'SCAN_ID_BACK'}
2616
2713
  includeBase64={isActive}
2617
2714
  targetFps={10}
@@ -3257,43 +3354,6 @@ const IdentityDocumentCamera = ({
3257
3354
  </TextView>
3258
3355
  </View>
3259
3356
  )}
3260
- {isDebugEnabled() && (
3261
- <View style={styles.imageContainer}>
3262
- {_currentHologramMaskImage ? (
3263
- <Image
3264
- source={{
3265
- uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`,
3266
- }}
3267
- style={styles.faceImage}
3268
- />
3269
- ) : (
3270
- <View
3271
- style={[
3272
- styles.faceImage,
3273
- { backgroundColor: '#333', justifyContent: 'center' },
3274
- ]}
3275
- >
3276
- <TextView
3277
- style={{
3278
- color: '#666',
3279
- fontSize: 10,
3280
- textAlign: 'center',
3281
- }}
3282
- >
3283
- Waiting...
3284
- </TextView>
3285
- </View>
3286
- )}
3287
- <TextView
3288
- style={[
3289
- styles.imageContainerText,
3290
- _currentHologramMaskImage && { color: '#4CAF50' },
3291
- ]}
3292
- >
3293
- {`${_currentHologramMaskImage ? '✓ ' : ''}Mask`}
3294
- </TextView>
3295
- </View>
3296
- )}
3297
3357
  {isDebugEnabled() && (
3298
3358
  <View style={styles.imageContainer}>
3299
3359
  {currentHologramImage ? (
@@ -3364,30 +3424,39 @@ const IdentityDocumentCamera = ({
3364
3424
  </View>
3365
3425
  )}
3366
3426
  {isDebugEnabled() && (
3367
- <View style={styles.debugInfoContainer}>
3368
- <TextView style={styles.debugInfoText}>
3369
- {`Step: ${nextStep}`}
3370
- </TextView>
3371
- <TextView style={styles.debugInfoText}>
3372
- {`Status: ${status}`}
3373
- </TextView>
3374
- <TextView style={styles.debugInfoText}>
3375
- {`Face: ${currentFaceImage ? '✓ CAPTURED' : '✗ WAITING'} ${!faceDetectionEnabled ? '(DISABLED)' : ''}`}
3376
- </TextView>
3377
- <TextView style={styles.debugInfoText}>
3378
- {`Hologram: ${currentHologramImage ? '✓ CAPTURED' : `${hologramImageCount}/${HOLOGRAM_IMAGE_COUNT} imgs`} (retry ${hologramDetectionCurrentRetryCount.current}/${HOLOGRAM_DETECTION_RETRY_COUNT})`}
3379
- </TextView>
3380
- <TextView style={styles.debugInfoText}>
3381
- {`2nd Face: ${currentSecondaryFaceImage ? '✓ CAPTURED' : '✗ WAITING'} (retry ${secondaryFaceDetectionCurrentRetryCount.current}/${SECOND_FACE_DETECTION_RETRY_COUNT})`}
3382
- </TextView>
3383
- <TextView style={styles.debugInfoText}>
3384
- {`Flash: ${isTorchOn ? '🔦 ON' : '🔦 OFF'}`}
3385
- </TextView>
3386
- <TextView style={styles.debugInfoText}>
3387
- {`Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓ OK'}`}
3388
- </TextView>
3389
- <TextView style={styles.debugInfoText}>
3390
- {`Blur: ${isFrameBlurry ? '⚠️ BLURRY' : '✓ OK'}`}
3427
+ <View style={styles.imageContainer}>
3428
+ {_currentHologramMaskImage ? (
3429
+ <Image
3430
+ source={{
3431
+ uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`,
3432
+ }}
3433
+ style={styles.faceImage}
3434
+ />
3435
+ ) : (
3436
+ <View
3437
+ style={[
3438
+ styles.faceImage,
3439
+ { backgroundColor: '#333', justifyContent: 'center' },
3440
+ ]}
3441
+ >
3442
+ <TextView
3443
+ style={{
3444
+ color: '#666',
3445
+ fontSize: 10,
3446
+ textAlign: 'center',
3447
+ }}
3448
+ >
3449
+ Waiting...
3450
+ </TextView>
3451
+ </View>
3452
+ )}
3453
+ <TextView
3454
+ style={[
3455
+ styles.imageContainerText,
3456
+ _currentHologramMaskImage && { color: '#4CAF50' },
3457
+ ]}
3458
+ >
3459
+ {`${_currentHologramMaskImage ? '✓ ' : ''}Mask`}
3391
3460
  </TextView>
3392
3461
  </View>
3393
3462
  )}
@@ -3442,82 +3511,120 @@ const IdentityDocumentCamera = ({
3442
3511
  ) : null}
3443
3512
  </View>
3444
3513
  {isDebugEnabled() && (
3445
- <View
3514
+ <SafeAreaView
3446
3515
  style={{
3447
3516
  position: 'absolute',
3448
- top: 10,
3449
- right: 10,
3450
- backgroundColor: 'rgba(0, 0, 0, 0.85)',
3451
- padding: 10,
3452
- borderRadius: 8,
3453
- borderWidth: 1,
3454
- borderColor: '#FF6B6B',
3455
- maxWidth: 200,
3517
+ top: 0,
3518
+ left: 0,
3519
+ right: 0,
3520
+ alignItems: 'center',
3521
+ pointerEvents: 'none',
3456
3522
  }}
3457
3523
  >
3458
- <TextView
3524
+ <View
3459
3525
  style={{
3460
- color: '#FF6B6B',
3461
- fontSize: 11,
3462
- fontWeight: 'bold',
3463
- marginBottom: 6,
3526
+ marginTop: 10,
3527
+ backgroundColor: 'rgba(0, 0, 0, 0.85)',
3528
+ padding: 10,
3529
+ borderRadius: 8,
3530
+ borderWidth: 1,
3531
+ borderColor: '#FF6B6B',
3532
+ minWidth: 200,
3464
3533
  }}
3465
3534
  >
3466
- 🐛 DEBUG MODE
3467
- </TextView>
3468
- <TextView
3469
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3470
- >
3471
- {`Step: ${nextStep}`}
3472
- </TextView>
3473
- <TextView
3474
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3475
- >
3476
- {`Status: ${status}`}
3477
- </TextView>
3478
- <TextView
3479
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3480
- >
3481
- {`Doc Type: ${detectedDocumentType}`}
3482
- </TextView>
3483
- <TextView
3484
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3485
- >
3486
- {`Face: ${currentFaceImage ? '✓' : '✗'}`}
3487
- </TextView>
3488
- {!onlyMRZScan && (
3489
- <>
3535
+ <TextView
3536
+ style={{
3537
+ color: '#FF6B6B',
3538
+ fontSize: 11,
3539
+ fontWeight: 'bold',
3540
+ marginBottom: 6,
3541
+ textAlign: 'center',
3542
+ }}
3543
+ >
3544
+ DEBUG MODE
3545
+ </TextView>
3546
+ <TextView
3547
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3548
+ >
3549
+ {`Step: ${nextStep}`}
3550
+ </TextView>
3551
+ <TextView
3552
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3553
+ >
3554
+ {`Status: ${status}`}
3555
+ </TextView>
3556
+ <TextView
3557
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3558
+ >
3559
+ {`Doc Type: ${detectedDocumentType}`}
3560
+ </TextView>
3561
+ <TextView
3562
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3563
+ >
3564
+ {`Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓'}`}
3565
+ </TextView>
3566
+ <TextView
3567
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3568
+ >
3569
+ {`Blur: ${isFrameBlurry ? '⚠️' : '✓'}`}
3570
+ </TextView>
3571
+ <TextView
3572
+ style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3573
+ >
3574
+ {`Flash: ${isTorchOn ? '🔦' : '○'}`}
3575
+ </TextView>
3576
+ <TextView style={{ color: '#88D8B0', fontSize: 9 }}>
3577
+ {`Face Detection: ${faceDetectionEnabled ? '✓' : '✗'}`}
3578
+ </TextView>
3579
+ </View>
3580
+ </SafeAreaView>
3581
+ )}
3582
+ {testMode && testModeData && (
3583
+ <SafeAreaView
3584
+ style={{
3585
+ position: 'absolute',
3586
+ bottom: 0,
3587
+ left: 0,
3588
+ right: 0,
3589
+ maxHeight: '40%',
3590
+ backgroundColor: 'rgba(0, 0, 0, 0.95)',
3591
+ borderTopWidth: 2,
3592
+ borderTopColor: '#FFA500',
3593
+ }}
3594
+ >
3595
+ <ScrollView style={{ flex: 1 }}>
3596
+ <View style={{ padding: 10 }}>
3490
3597
  <TextView
3491
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3598
+ style={{
3599
+ color: '#FFA500',
3600
+ fontSize: 12,
3601
+ fontWeight: 'bold',
3602
+ marginBottom: 8,
3603
+ textAlign: 'center',
3604
+ }}
3492
3605
  >
3493
- {`2nd Face: ${currentSecondaryFaceImage ? '✓' : '✗'}`}
3606
+ MRZ Text Read
3494
3607
  </TextView>
3608
+
3495
3609
  <TextView
3496
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3610
+ style={{
3611
+ color: '#FFFFFF',
3612
+ fontSize: 9,
3613
+ fontFamily: 'monospace',
3614
+ lineHeight: 16,
3615
+ }}
3497
3616
  >
3498
- {`Hologram: ${hologramImageCount}/${HOLOGRAM_IMAGE_COUNT}`}
3617
+ {testModeData.mrzText
3618
+ .split('\n')
3619
+ .map(
3620
+ (line, i) =>
3621
+ `Line ${i + 1}: ${line} (${line.length} chars)`
3622
+ )
3623
+ .join('\n')}
3499
3624
  </TextView>
3500
- </>
3501
- )}
3502
- <TextView
3503
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3504
- >
3505
- {`Brightness: ${isBrightnessLow ? '⚠️ LOW' : '✓'}`}
3506
- </TextView>
3507
- <TextView
3508
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3509
- >
3510
- {`Blur: ${isFrameBlurry ? '⚠️' : '✓'}`}
3511
- </TextView>
3512
- <TextView
3513
- style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}
3514
- >
3515
- {`Flash: ${isTorchOn ? '🔦' : '○'}`}
3516
- </TextView>
3517
- <TextView style={{ color: '#88D8B0', fontSize: 9 }}>
3518
- {`Face Detection: ${faceDetectionEnabled ? '✓' : '✗'}`}
3519
- </TextView>
3520
- </View>
3625
+ </View>
3626
+ </ScrollView>
3627
+ </SafeAreaView>
3521
3628
  )}
3522
3629
  </>
3523
3630
  )}
@@ -3629,7 +3736,7 @@ const styles = StyleSheet.create({
3629
3736
  display: 'flex',
3630
3737
  flexDirection: 'row',
3631
3738
  gap: 10,
3632
- justifyContent: 'flex-start',
3739
+ justifyContent: 'center',
3633
3740
  flexWrap: 'wrap',
3634
3741
  },
3635
3742
  cardDetectionRow: {
@@ -3669,16 +3776,6 @@ const styles = StyleSheet.create({
3669
3776
  flexDirection: 'column',
3670
3777
  alignItems: 'center',
3671
3778
  },
3672
- debugInfoContainer: {
3673
- flex: 1,
3674
- paddingLeft: 10,
3675
- },
3676
- debugInfoText: {
3677
- color: 'white',
3678
- fontSize: 8,
3679
- fontWeight: 'bold',
3680
- marginBottom: 2,
3681
- },
3682
3779
  guide: {
3683
3780
  flex: 1,
3684
3781
  display: 'flex',
@@ -61,13 +61,6 @@ const QrCodeScannerCamera = ({
61
61
  bottom: height * (0.65 - marginBuffer),
62
62
  };
63
63
 
64
- console.log(
65
- `[QR Frame Check] Frame: ${width}x${height}, Scanning: left=${scanningFrame.left}, top=${scanningFrame.top}, right=${scanningFrame.right}, bottom=${scanningFrame.bottom}`
66
- );
67
- console.log(
68
- `[QR Frame Check] Code bbox: left=${boundingBox.left}, top=${boundingBox.top}, right=${boundingBox.right}, bottom=${boundingBox.bottom}`
69
- );
70
-
71
64
  // Check if entire bounding box is within scanning frame (with margin buffer)
72
65
  const isInFrame =
73
66
  boundingBox.left >= scanningFrame.left &&
@@ -75,8 +68,6 @@ const QrCodeScannerCamera = ({
75
68
  boundingBox.right <= scanningFrame.right &&
76
69
  boundingBox.bottom <= scanningFrame.bottom;
77
70
 
78
- console.log(`[QR Frame Check] Is in frame: ${isInFrame}`);
79
-
80
71
  return isInFrame;
81
72
  };
82
73
 
@@ -63,7 +63,6 @@ export interface Frame {
63
63
  textBlocks?: NativeTextBlock[];
64
64
  resultText?: string;
65
65
  barcodes?: NativeBarcode[];
66
- mrzResult?: NativeMRZResult;
67
66
  }
68
67
 
69
68
  export interface NativeFace {
@@ -97,24 +96,6 @@ export interface NativeBarcode {
97
96
  cornerPoints?: Array<{ x: number; y: number }>;
98
97
  }
99
98
 
100
- export interface NativeMRZResult {
101
- valid: boolean;
102
- format: string;
103
- error?: string;
104
- documentCode?: string;
105
- issuingState?: string;
106
- documentNumber?: string;
107
- lastName?: string;
108
- firstName?: string;
109
- birthDate?: string;
110
- sex?: string;
111
- expirationDate?: string;
112
- nationality?: string;
113
- optional1?: string;
114
- optional2?: string;
115
- rawLines?: string;
116
- }
117
-
118
99
  interface TrustchexCameraProps {
119
100
  style?: StyleProp<ViewStyle>;
120
101
  cameraType?: 'front' | 'back';
@@ -125,7 +106,6 @@ interface TrustchexCameraProps {
125
106
  enableFaceDetection?: boolean;
126
107
  enableTextRecognition?: boolean;
127
108
  enableBarcodeScanning?: boolean;
128
- enableMrzValidation?: boolean;
129
109
  includeBase64?: boolean;
130
110
  onFrameAvailable?: (event: NativeSyntheticEvent<{ frame: Frame }>) => void;
131
111
  onCameraReady?: (
@@ -12,19 +12,19 @@ export const ENHANCEMENT_CONFIG = {
12
12
 
13
13
  brightness: {
14
14
  thresholds: {
15
- general: { low: 40, high: 120, target: 80 },
16
- faceDetection: { low: 50, high: 110, target: 85 },
17
- mrzScanning: { low: 45, high: 130, target: 80 },
15
+ general: { low: 60, high: 140, target: 100 },
16
+ faceDetection: { low: 70, high: 140, target: 105 },
17
+ mrzScanning: { low: 65, high: 150, target: 100 },
18
18
  },
19
19
  adaptiveStep: true,
20
- maxStepSize: 2, // Reduced from 3 for smoother transitions
21
- hysteresis: 5, // Dead zone to prevent oscillation
20
+ maxStepSize: 2,
21
+ hysteresis: 5,
22
22
  },
23
23
 
24
24
  contrast: {
25
25
  enabled: true,
26
26
  clahe: {
27
- clipLimit: 2.0,
27
+ clipLimit: 1.5,
28
28
  tileGridSize: [8, 8] as [number, number],
29
29
  },
30
30
  applyWhen: {