@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.
- package/TrustchexSDK.podspec +3 -1
- package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKPackage.kt +0 -13
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraManager.kt +0 -8
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +59 -39
- package/android/src/main/java/com/trustchex/reactnativesdk/opencv/OpenCVModule.kt +94 -13
- package/ios/Camera/TrustchexCameraManager.m +0 -2
- package/ios/Camera/TrustchexCameraManager.swift +0 -7
- package/ios/Camera/TrustchexCameraView.swift +16 -47
- package/ios/OpenCV/OpenCVHelper.h +17 -0
- package/ios/OpenCV/OpenCVHelper.mm +128 -0
- package/ios/OpenCV/OpenCVModule.h +6 -0
- package/ios/OpenCV/OpenCVModule.mm +141 -0
- package/ios/TrustchexSDK-Bridging-Header.h +8 -0
- package/lib/module/Screens/Debug/MRZTestScreen.js +175 -0
- package/lib/module/Shared/Components/DebugNavigationPanel.js +4 -0
- package/lib/module/Shared/Components/EIDScanner.js +0 -78
- package/lib/module/Shared/Components/FaceCamera.js +6 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +199 -153
- package/lib/module/Shared/Components/QrCodeScannerCamera.js +0 -3
- package/lib/module/Shared/Config/camera-enhancement.config.js +11 -12
- package/lib/module/Shared/Libs/mrz.utils.js +265 -0
- package/lib/module/Trustchex.js +4 -0
- package/lib/module/index.js +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts +3 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/QrCodeScannerCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts +0 -19
- package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Config/camera-enhancement.config.d.ts +10 -10
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts +18 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Trustchex.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/Screens/Debug/MRZTestScreen.tsx +209 -0
- package/src/Shared/Components/DebugNavigationPanel.tsx +5 -0
- package/src/Shared/Components/EIDScanner.tsx +0 -53
- package/src/Shared/Components/FaceCamera.tsx +6 -3
- package/src/Shared/Components/IdentityDocumentCamera.tsx +246 -149
- package/src/Shared/Components/QrCodeScannerCamera.tsx +0 -9
- package/src/Shared/Components/TrustchexCamera.tsx +0 -20
- package/src/Shared/Config/camera-enhancement.config.ts +6 -6
- package/src/Shared/Libs/mrz.utils.ts +289 -1
- package/src/Trustchex.tsx +5 -0
- package/src/index.tsx +3 -0
- package/src/version.ts +1 -1
- package/android/src/main/java/com/trustchex/reactnativesdk/mrz/MRZValidationModule.kt +0 -785
- package/android/src/main/java/com/trustchex/reactnativesdk/mrz/MRZValidator.kt +0 -419
- package/ios/MRZValidation.m +0 -39
- package/ios/MRZValidation.swift +0 -802
- 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 =
|
|
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
|
-
|
|
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
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
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
|
-
<
|
|
3514
|
+
<SafeAreaView
|
|
3446
3515
|
style={{
|
|
3447
3516
|
position: 'absolute',
|
|
3448
|
-
top:
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
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
|
-
<
|
|
3524
|
+
<View
|
|
3459
3525
|
style={{
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
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
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
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={{
|
|
3598
|
+
style={{
|
|
3599
|
+
color: '#FFA500',
|
|
3600
|
+
fontSize: 12,
|
|
3601
|
+
fontWeight: 'bold',
|
|
3602
|
+
marginBottom: 8,
|
|
3603
|
+
textAlign: 'center',
|
|
3604
|
+
}}
|
|
3492
3605
|
>
|
|
3493
|
-
|
|
3606
|
+
MRZ Text Read
|
|
3494
3607
|
</TextView>
|
|
3608
|
+
|
|
3495
3609
|
<TextView
|
|
3496
|
-
style={{
|
|
3610
|
+
style={{
|
|
3611
|
+
color: '#FFFFFF',
|
|
3612
|
+
fontSize: 9,
|
|
3613
|
+
fontFamily: 'monospace',
|
|
3614
|
+
lineHeight: 16,
|
|
3615
|
+
}}
|
|
3497
3616
|
>
|
|
3498
|
-
{
|
|
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
|
-
|
|
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: '
|
|
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:
|
|
16
|
-
faceDetection: { low:
|
|
17
|
-
mrzScanning: { low:
|
|
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,
|
|
21
|
-
hysteresis: 5,
|
|
20
|
+
maxStepSize: 2,
|
|
21
|
+
hysteresis: 5,
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
contrast: {
|
|
25
25
|
enabled: true,
|
|
26
26
|
clahe: {
|
|
27
|
-
clipLimit:
|
|
27
|
+
clipLimit: 1.5,
|
|
28
28
|
tileGridSize: [8, 8] as [number, number],
|
|
29
29
|
},
|
|
30
30
|
applyWhen: {
|