@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
@@ -0,0 +1,209 @@
1
+ import React, { useState, useRef, useCallback } from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ Text,
6
+ ScrollView,
7
+ StatusBar,
8
+ TouchableOpacity,
9
+ type NativeSyntheticEvent,
10
+ } from 'react-native';
11
+ import { SafeAreaView } from 'react-native-safe-area-context';
12
+ import {
13
+ TrustchexCamera,
14
+ type TrustchexCameraHandle,
15
+ type Frame,
16
+ } from '../../Shared/Components/TrustchexCamera';
17
+ import mrzUtils from '../../Shared/Libs/mrz.utils';
18
+
19
+ const MRZTestScreen = () => {
20
+ const cameraRef = useRef<TrustchexCameraHandle>(null);
21
+ const [mrzText, setMrzText] = useState<string>('Waiting for MRZ...');
22
+ const [mrzRawText, setMrzRawText] = useState<string>('');
23
+ const [mrzValid, setMrzValid] = useState<boolean>(false);
24
+ const [rawHistory, setRawHistory] = useState<string[]>([]);
25
+ const [isPaused, setIsPaused] = useState<boolean>(false);
26
+
27
+ const handleFrame = useCallback(
28
+ (event: NativeSyntheticEvent<{ frame: Frame }>) => {
29
+ if (isPaused) {
30
+ return;
31
+ }
32
+
33
+ const frame = event.nativeEvent.frame;
34
+
35
+ if (frame.resultText) {
36
+ setRawHistory((prev) => {
37
+ if (prev[0] === frame.resultText) {
38
+ return prev;
39
+ }
40
+ const next = [frame.resultText, ...prev];
41
+ return next.slice(0, 20);
42
+ });
43
+ }
44
+
45
+ if (frame.resultText && frame.resultText.includes('<')) {
46
+ // Extract MRZ-only text from detected blocks
47
+ let mrzOnlyText = '';
48
+ if (frame.textBlocks && frame.textBlocks.length > 0) {
49
+ // Filter blocks that look like MRZ (contain < and are in bottom half of frame)
50
+ const frameHeight = frame.height;
51
+ const bottomThreshold = frameHeight * 0.5;
52
+
53
+ const mrzBlocks = frame.textBlocks.filter((block) => {
54
+ const blockText = block.text || '';
55
+ const hasFillers = blockText.includes('<');
56
+ const isInBottomArea = block.blockFrame
57
+ ? block.blockFrame.y > bottomThreshold
58
+ : false;
59
+ const isLongEnough = blockText.length >= 12;
60
+ return hasFillers && isInBottomArea && isLongEnough;
61
+ });
62
+
63
+ if (mrzBlocks.length > 0) {
64
+ mrzOnlyText = mrzBlocks.map((b) => b.text).join('\n');
65
+ }
66
+ }
67
+
68
+ // Fallback to full text if no MRZ blocks detected
69
+ if (!mrzOnlyText) {
70
+ mrzOnlyText = frame.resultText;
71
+ }
72
+
73
+ const fixedMrz = mrzUtils.fixMRZ(mrzOnlyText);
74
+ setMrzRawText(mrzOnlyText);
75
+ setMrzText(fixedMrz);
76
+ setMrzValid(mrzUtils.validateMRZWithCorrections(fixedMrz).valid);
77
+ }
78
+ },
79
+ [isPaused]
80
+ );
81
+
82
+ return (
83
+ <View style={styles.container}>
84
+ <StatusBar
85
+ barStyle="light-content"
86
+ backgroundColor="transparent"
87
+ translucent
88
+ />
89
+ <TrustchexCamera
90
+ ref={cameraRef}
91
+ style={styles.camera}
92
+ cameraType="back"
93
+ enableFrameProcessing={true}
94
+ enableFaceDetection={false}
95
+ enableTextRecognition={true}
96
+ enableBarcodeScanning={false}
97
+ includeBase64={false}
98
+ targetFps={10}
99
+ onFrameAvailable={handleFrame}
100
+ />
101
+
102
+ <SafeAreaView style={styles.mrzPanel} edges={['bottom']}>
103
+ <ScrollView style={styles.scrollView}>
104
+ <View style={styles.panelContent}>
105
+ <TouchableOpacity
106
+ style={styles.pauseButton}
107
+ onPress={() => setIsPaused(!isPaused)}
108
+ >
109
+ <Text style={styles.pauseButtonText}>
110
+ {isPaused ? 'Resume Processing' : 'Pause Processing'}
111
+ </Text>
112
+ </TouchableOpacity>
113
+ <Text style={styles.title}>MRZ Text Read</Text>
114
+ <Text style={styles.sectionTitle}>MRZ Raw Text</Text>
115
+ <Text style={styles.mrzText}>
116
+ {mrzRawText
117
+ ? mrzRawText
118
+ .split('\n')
119
+ .map(
120
+ (line, i) =>
121
+ `Line ${i + 1}: ${line} (${line.length} chars)`
122
+ )
123
+ .join('\n')
124
+ : 'No MRZ raw text'}
125
+ </Text>
126
+ <Text style={styles.sectionTitle}>MRZ Corrected Text</Text>
127
+ <Text style={[styles.mrzText, mrzValid ? styles.mrzValid : null]}>
128
+ {mrzText
129
+ .split('\n')
130
+ .map(
131
+ (line, i) => `Line ${i + 1}: ${line} (${line.length} chars)`
132
+ )
133
+ .join('\n')}
134
+ </Text>
135
+ <Text style={styles.sectionTitle}>Raw Text History</Text>
136
+ <Text style={styles.mrzText}>
137
+ {rawHistory.length > 0
138
+ ? rawHistory
139
+ .map((text, i) => `#${i + 1}: ${text.replace(/\n/g, ' ')}`)
140
+ .join('\n')
141
+ : 'No history'}
142
+ </Text>
143
+ </View>
144
+ </ScrollView>
145
+ </SafeAreaView>
146
+ </View>
147
+ );
148
+ };
149
+
150
+ const styles = StyleSheet.create({
151
+ container: {
152
+ flex: 1,
153
+ backgroundColor: '#000000',
154
+ },
155
+ camera: {
156
+ flex: 2,
157
+ },
158
+ mrzPanel: {
159
+ flex: 1,
160
+ backgroundColor: 'rgba(0, 0, 0, 0.95)',
161
+ borderTopWidth: 2,
162
+ borderTopColor: '#FFA500',
163
+ },
164
+ scrollView: {
165
+ flex: 1,
166
+ },
167
+ panelContent: {
168
+ padding: 10,
169
+ },
170
+ pauseButton: {
171
+ alignSelf: 'center',
172
+ borderWidth: 1,
173
+ borderColor: '#FFA500',
174
+ borderRadius: 4,
175
+ paddingVertical: 6,
176
+ paddingHorizontal: 12,
177
+ marginBottom: 8,
178
+ },
179
+ pauseButtonText: {
180
+ color: '#FFA500',
181
+ fontSize: 10,
182
+ fontWeight: 'bold',
183
+ },
184
+ title: {
185
+ color: '#FFA500',
186
+ fontSize: 12,
187
+ fontWeight: 'bold',
188
+ marginBottom: 8,
189
+ textAlign: 'center',
190
+ },
191
+ sectionTitle: {
192
+ color: '#FFA500',
193
+ fontSize: 10,
194
+ fontWeight: 'bold',
195
+ marginTop: 6,
196
+ marginBottom: 4,
197
+ },
198
+ mrzText: {
199
+ color: '#FFFFFF',
200
+ fontSize: 9,
201
+ fontFamily: 'monospace',
202
+ lineHeight: 16,
203
+ },
204
+ mrzValid: {
205
+ color: '#00C853',
206
+ },
207
+ });
208
+
209
+ export default MRZTestScreen;
@@ -190,6 +190,11 @@ const DebugNavigationPanel = () => {
190
190
  setupDemoSession();
191
191
  },
192
192
  },
193
+ {
194
+ screen: 'MRZTestScreen',
195
+ label: 'MRZ Test',
196
+ icon: ICONS.BUG_REPORT,
197
+ },
193
198
  ];
194
199
 
195
200
  const selectScreen = useCallback(
@@ -13,7 +13,6 @@ import StyledButton from './StyledButton';
13
13
  import LottieView from 'lottie-react-native';
14
14
  import { useKeepAwake } from '../Libs/native-keep-awake.utils';
15
15
  import { speak, resetLastMessage } from '../Libs/tts.utils';
16
- import { isDebugEnabled } from '../Libs/debug.utils';
17
16
  import {
18
17
  trackEIDScanStart,
19
18
  trackEIDScanComplete,
@@ -618,58 +617,6 @@ const EIDScanner = ({
618
617
  </StyledButton>
619
618
  </View>
620
619
  )}
621
-
622
- {isDebugEnabled() && (
623
- <View
624
- style={{
625
- position: 'absolute',
626
- top: insets.top + 10,
627
- right: 10,
628
- backgroundColor: 'rgba(0, 0, 0, 0.85)',
629
- padding: 10,
630
- borderRadius: 8,
631
- borderWidth: 1,
632
- borderColor: '#FF6B6B',
633
- maxWidth: 200,
634
- zIndex: 1001,
635
- }}
636
- >
637
- <Text
638
- style={{
639
- color: '#FF6B6B',
640
- fontSize: 11,
641
- fontWeight: 'bold',
642
- marginBottom: 6,
643
- }}
644
- >
645
- 🐛 DEBUG MODE
646
- </Text>
647
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
648
- {`NFC: ${hasNfc ? '✓' : '✗'}`}
649
- </Text>
650
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
651
- {`Enabled: ${isEnabled ? '✓' : '✗'}`}
652
- </Text>
653
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
654
- {`Scanning: ${isScanning ? '✓' : '○'}`}
655
- </Text>
656
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
657
- {`Scanned: ${isScanned ? '✓' : '○'}`}
658
- </Text>
659
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
660
- {`Progress: ${Math.round(progress)}%`}
661
- </Text>
662
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
663
- {`Face Image: ${documentFaceImage ? '✓' : '✗'}`}
664
- </Text>
665
- <Text style={{ color: '#88D8B0', fontSize: 9, marginBottom: 2 }}>
666
- {`MRZ Info: ${documentMRZInfo ? '✓' : '✗'}`}
667
- </Text>
668
- <Text style={{ color: '#88D8B0', fontSize: 9 }}>
669
- {`Doc Type: ${documentType}`}
670
- </Text>
671
- </View>
672
- )}
673
620
  </>
674
621
  )}
675
622
  </View>
@@ -26,9 +26,9 @@ import { Dimensions } from 'react-native';
26
26
 
27
27
  const { width: windowWidth, height: windowHeight } = Dimensions.get('window');
28
28
  const { OpenCVModule } = NativeModules;
29
- const MIN_BRIGHTNESS_THRESHOLD = 80;
29
+ const MIN_BRIGHTNESS_THRESHOLD = 60;
30
30
  const BLUR_VARIANCE_THRESHOLD = 60;
31
- const REGION_BRIGHTNESS_THRESHOLD = 70;
31
+ const REGION_BRIGHTNESS_THRESHOLD = 50;
32
32
 
33
33
  export type Face = {
34
34
  bounds: {
@@ -222,7 +222,7 @@ const FaceCamera = ({
222
222
  const isBright = avgBrightness >= MIN_BRIGHTNESS_THRESHOLD;
223
223
 
224
224
  // Check brightness in the region of interest (circular preview area)
225
- let isRegionBright = isBright; // Default to overall brightness
225
+ let isRegionBright = false;
226
226
  if (previewRect && base64Image && OpenCVModule) {
227
227
  try {
228
228
  // Scale preview rect from screen coordinates to frame coordinates
@@ -243,7 +243,10 @@ const FaceCamera = ({
243
243
  );
244
244
  } catch (error) {
245
245
  debugWarn('FaceCamera', 'Region brightness check failed:', error);
246
+ isRegionBright = isBright;
246
247
  }
248
+ } else {
249
+ isRegionBright = isBright;
247
250
  }
248
251
 
249
252
  // Check for blur using OpenCV Laplacian variance