@trustchex/react-native-sdk 1.512.1 → 1.513.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 (58) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +9 -2
  2. package/android/src/main/java/com/trustchex/reactnativesdk/opencv/OpenCVModule.kt +54 -0
  3. package/ios/Camera/TrustchexCameraView.swift +6 -2
  4. package/ios/OpenCV/OpenCVModule.mm +59 -0
  5. package/lib/module/Screens/Dynamic/AddressCaptureScreen.js +427 -112
  6. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +9 -4
  7. package/lib/module/Screens/Static/ResultScreen.js +46 -0
  8. package/lib/module/Shared/Animations/address-scan.json +1 -0
  9. package/lib/module/Shared/Components/DebugNavigationPanel.js +10 -0
  10. package/lib/module/Shared/Components/EIDScanner.js +16 -4
  11. package/lib/module/Shared/Components/IdentityDocumentCamera.js +100 -19
  12. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +47 -0
  13. package/lib/module/Shared/Libs/addressProofHeuristic.js +130 -0
  14. package/lib/module/Shared/Libs/demo.utils.js +4 -0
  15. package/lib/module/Shared/Libs/sendDiagnosticReport.js +47 -1
  16. package/lib/module/Shared/Libs/vizName.js +138 -16
  17. package/lib/module/Translation/Resources/en.js +16 -3
  18. package/lib/module/Translation/Resources/tr.js +16 -3
  19. package/lib/module/version.js +1 -1
  20. package/lib/typescript/src/Screens/Dynamic/AddressCaptureScreen.d.ts.map +1 -1
  21. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  22. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  23. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  24. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts +8 -3
  25. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  26. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  27. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +25 -0
  28. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  29. package/lib/typescript/src/Shared/Libs/addressProofHeuristic.d.ts +34 -0
  30. package/lib/typescript/src/Shared/Libs/addressProofHeuristic.d.ts.map +1 -0
  31. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  32. package/lib/typescript/src/Shared/Libs/sendDiagnosticReport.d.ts.map +1 -1
  33. package/lib/typescript/src/Shared/Libs/vizName.d.ts +31 -6
  34. package/lib/typescript/src/Shared/Libs/vizName.d.ts.map +1 -1
  35. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +0 -5
  36. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  37. package/lib/typescript/src/Translation/Resources/en.d.ts +13 -0
  38. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  39. package/lib/typescript/src/Translation/Resources/tr.d.ts +13 -0
  40. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  41. package/lib/typescript/src/version.d.ts +1 -1
  42. package/package.json +1 -1
  43. package/src/Screens/Dynamic/AddressCaptureScreen.tsx +434 -75
  44. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +14 -4
  45. package/src/Screens/Static/ResultScreen.tsx +59 -0
  46. package/src/Shared/Animations/address-scan.json +1 -0
  47. package/src/Shared/Components/DebugNavigationPanel.tsx +13 -0
  48. package/src/Shared/Components/EIDScanner.tsx +38 -12
  49. package/src/Shared/Components/IdentityDocumentCamera.tsx +109 -17
  50. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +53 -0
  51. package/src/Shared/Libs/addressProofHeuristic.ts +197 -0
  52. package/src/Shared/Libs/demo.utils.ts +5 -0
  53. package/src/Shared/Libs/sendDiagnosticReport.ts +65 -7
  54. package/src/Shared/Libs/vizName.ts +158 -20
  55. package/src/Shared/Types/identificationInfo.ts +0 -5
  56. package/src/Translation/Resources/en.ts +28 -3
  57. package/src/Translation/Resources/tr.ts +28 -3
  58. package/src/version.ts +1 -1
@@ -414,8 +414,15 @@ class TrustchexCameraView(context: ThemedReactContext) : FrameLayout(context) {
414
414
  // 3. Process at lower resolution (720x1280 portrait) for real-time detection
415
415
  // 4. Use ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST for frame dropping
416
416
  // 5. Close ImageProxy immediately after ML Kit processing completes
417
- val hasAnyDetection = frameProcessingEnabled && (faceDetectionEnabled || textRecognitionEnabled || barcodeScanningEnabled)
418
- if (!hasAnyDetection) {
417
+ // Emit a frame when EITHER a detector is enabled OR the JS side just
418
+ // wants the image (includeBase64). The latter lets a screen do a
419
+ // manual still capture without paying for a per-frame ML Kit pass it
420
+ // never reads. With no detector the `tasks` list below is empty and
421
+ // the frame event carries brightness + base64 only.
422
+ val wantsFrame = frameProcessingEnabled &&
423
+ (faceDetectionEnabled || textRecognitionEnabled ||
424
+ barcodeScanningEnabled || includeBase64)
425
+ if (!wantsFrame) {
419
426
  isProcessing.set(false)
420
427
  imageProxy.close()
421
428
  return
@@ -1022,6 +1022,60 @@ class OpenCVModule(reactContext: ReactApplicationContext) : ReactContextBaseJava
1022
1022
  }
1023
1023
  }
1024
1024
 
1025
+ /**
1026
+ * Downscale + JPEG-recompress an image, for shrinking diagnostic uploads.
1027
+ *
1028
+ * The scan captures full-resolution frames; bundling several of them as
1029
+ * base64 into one diagnostic POST produces a multi-MB body that is slow to
1030
+ * JSON-stringify on the JS thread and slow to upload. These images are only
1031
+ * for a support inbox, so full resolution is wasteful. This scales the image
1032
+ * down so its longest edge is at most `maxDim` (never upscales) and re-encodes
1033
+ * JPEG at `quality` (0-100), typically cutting the payload 5-20x.
1034
+ *
1035
+ * Runs on a background thread (decode/encode of a large bitmap is heavy).
1036
+ * Best-effort: on any failure it resolves the ORIGINAL base64 so the report
1037
+ * still sends — a slower upload is better than a dropped diagnostic.
1038
+ *
1039
+ * @param base64Image Base64 JPEG/PNG (no data-URI prefix)
1040
+ * @param maxDim Longest-edge cap in pixels (e.g. 1024)
1041
+ * @param quality JPEG quality 0-100 (e.g. 70)
1042
+ * @param promise Returns the shrunk base64 JPEG (or the original on failure)
1043
+ */
1044
+ @ReactMethod
1045
+ fun resizeAndCompress(base64Image: String, maxDim: Int, quality: Int, promise: Promise) {
1046
+ Thread {
1047
+ try {
1048
+ val bytes = Base64.decode(base64Image, Base64.NO_WRAP)
1049
+ val src = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
1050
+ if (src == null) {
1051
+ promise.resolve(base64Image)
1052
+ return@Thread
1053
+ }
1054
+
1055
+ val longest = maxOf(src.width, src.height)
1056
+ // Only downscale; never enlarge a small image.
1057
+ val scale = if (maxDim > 0 && longest > maxDim) maxDim.toDouble() / longest else 1.0
1058
+ val scaled = if (scale < 1.0) {
1059
+ val w = (src.width * scale).toInt().coerceAtLeast(1)
1060
+ val h = (src.height * scale).toInt().coerceAtLeast(1)
1061
+ Bitmap.createScaledBitmap(src, w, h, true)
1062
+ } else {
1063
+ src
1064
+ }
1065
+
1066
+ val stream = ByteArrayOutputStream()
1067
+ scaled.compress(Bitmap.CompressFormat.JPEG, quality.coerceIn(1, 100), stream)
1068
+ if (scaled !== src) scaled.recycle()
1069
+ src.recycle()
1070
+
1071
+ promise.resolve(Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP))
1072
+ } catch (e: Exception) {
1073
+ // Fall back to the original so the report still uploads.
1074
+ promise.resolve(base64Image)
1075
+ }
1076
+ }.start()
1077
+ }
1078
+
1025
1079
  private fun base64ToMat(base64: String): Mat? {
1026
1080
  return try {
1027
1081
  val bytes = Base64.decode(base64, Base64.NO_WRAP)
@@ -808,8 +808,12 @@ extension TrustchexCameraView: AVCaptureVideoDataOutputSampleBufferDelegate {
808
808
 
809
809
  func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
810
810
  autoreleasepool {
811
- let hasAnyDetection = _frameProcessingEnabled && (enableFaceDetection || enableTextRecognition || enableBarcodeScanning)
812
- guard hasAnyDetection else { return }
811
+ // Emit a frame when EITHER a detector is enabled OR the JS side just
812
+ // wants the image (includeBase64). The latter lets a screen do a
813
+ // manual still capture without paying for a per-frame ML Kit pass it
814
+ // never reads.
815
+ let wantsFrame = _frameProcessingEnabled && (enableFaceDetection || enableTextRecognition || enableBarcodeScanning || includeBase64)
816
+ guard wantsFrame else { return }
813
817
 
814
818
  // Check flag on videoQueue (serial) to prevent re-entry
815
819
  guard !isProcessing else { return }
@@ -88,6 +88,65 @@ RCT_EXPORT_MODULE();
88
88
  return image;
89
89
  }
90
90
 
91
+ /**
92
+ * Downscale + JPEG-recompress an image, for shrinking diagnostic uploads.
93
+ *
94
+ * The scan captures full-resolution frames; bundling several as base64 into one
95
+ * diagnostic POST produces a multi-MB body that is slow to JSON-stringify on the
96
+ * JS thread and slow to upload. These images are only for a support inbox, so
97
+ * full resolution is wasteful. This scales the image down so its longest edge is
98
+ * at most `maxDim` (never upscales) and re-encodes JPEG at `quality` (0-100),
99
+ * typically cutting the payload 5-20x.
100
+ *
101
+ * Runs on a background queue (decode/encode of a large image is heavy).
102
+ * Best-effort: on any failure it resolves the ORIGINAL base64 so the report
103
+ * still sends — a slower upload beats a dropped diagnostic.
104
+ */
105
+ RCT_EXPORT_METHOD(resizeAndCompress:(NSString *)base64Image
106
+ maxDim:(NSInteger)maxDim
107
+ quality:(NSInteger)quality
108
+ resolver:(RCTPromiseResolveBlock)resolve
109
+ rejecter:(RCTPromiseRejectBlock)reject) {
110
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
111
+ @try {
112
+ UIImage *src = [self base64ToImage:base64Image];
113
+ if (!src) {
114
+ resolve(base64Image);
115
+ return;
116
+ }
117
+
118
+ CGFloat w = src.size.width;
119
+ CGFloat h = src.size.height;
120
+ CGFloat longest = MAX(w, h);
121
+ // Only downscale; never enlarge a small image.
122
+ CGFloat scale = (maxDim > 0 && longest > maxDim) ? (CGFloat)maxDim / longest : 1.0;
123
+
124
+ UIImage *scaled = src;
125
+ if (scale < 1.0) {
126
+ CGSize newSize = CGSizeMake(MAX(1.0, w * scale), MAX(1.0, h * scale));
127
+ UIGraphicsImageRendererFormat *fmt = [UIGraphicsImageRendererFormat defaultFormat];
128
+ fmt.scale = 1.0; // pixels, not points — avoid Retina 2x/3x inflation
129
+ fmt.opaque = YES;
130
+ UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize format:fmt];
131
+ scaled = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull ctx) {
132
+ [src drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
133
+ }];
134
+ }
135
+
136
+ CGFloat q = MIN(1.0, MAX(0.01, (CGFloat)quality / 100.0));
137
+ NSData *jpeg = UIImageJPEGRepresentation(scaled, q);
138
+ if (!jpeg) {
139
+ resolve(base64Image);
140
+ return;
141
+ }
142
+ resolve([jpeg base64EncodedStringWithOptions:0]);
143
+ } @catch (NSException *exception) {
144
+ // Fall back to the original so the report still uploads.
145
+ resolve(base64Image);
146
+ }
147
+ });
148
+ }
149
+
91
150
  RCT_EXPORT_METHOD(cropFaceImages:(NSString *)base64Image
92
151
  faceBounds:(NSArray *)faceBounds
93
152
  imageWidth:(NSInteger)imageWidth