@dariyd/react-native-document-scanner 2.0.13

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.
@@ -0,0 +1,182 @@
1
+ // android/build.gradle
2
+
3
+ // based on:
4
+ //
5
+ // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle
6
+ // previous location:
7
+ // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle
8
+ //
9
+ // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle
10
+ // previous location:
11
+ // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle
12
+
13
+ // These defaults should reflect the SDK versions used by
14
+ // the minimum React Native version supported.
15
+ def DEFAULT_COMPILE_SDK_VERSION = 35
16
+ def DEFAULT_BUILD_TOOLS_VERSION = '35.0.0'
17
+ def DEFAULT_MIN_SDK_VERSION = 21
18
+ def DEFAULT_TARGET_SDK_VERSION = 35
19
+
20
+ def safeExtGet(prop, fallback) {
21
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
22
+ }
23
+
24
+ apply plugin: 'com.android.library'
25
+ apply plugin: 'maven-publish'
26
+ // Needed so RN Gradle plugin can run codegen for this library when newArchEnabled=true in the app
27
+ apply plugin: 'com.facebook.react'
28
+
29
+ buildscript {
30
+ // The Android Gradle plugin is only required when opening the android folder stand-alone.
31
+ // This avoids unnecessary downloads and potential conflicts when the library is included as a
32
+ // module dependency in an application project.
33
+ // ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
34
+ if (project == rootProject) {
35
+ repositories {
36
+ google()
37
+ }
38
+ dependencies {
39
+ // This should reflect the Gradle plugin version used by
40
+ // the minimum React Native version supported.
41
+ classpath 'com.android.tools.build:gradle:3.4.1'
42
+ }
43
+ }
44
+ }
45
+
46
+ android {
47
+ namespace "com.docscanner"
48
+ compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
49
+ buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)
50
+ defaultConfig {
51
+ minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
52
+ targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
53
+ versionCode 1
54
+ versionName "1.0"
55
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", (findProperty("newArchEnabled") ?: "false")
56
+ }
57
+
58
+ lintOptions {
59
+ abortOnError false
60
+ }
61
+ }
62
+
63
+ // Configure React Native codegen for this library
64
+ react {
65
+ libraryName = "RNDocumentScannerSpec"
66
+ codegenJavaPackageName = "com.docscanner"
67
+ }
68
+
69
+ repositories {
70
+ // ref: https://www.baeldung.com/maven-local-repository
71
+ mavenLocal()
72
+ maven {
73
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
74
+ url "$rootDir/../node_modules/react-native/android"
75
+ }
76
+ maven {
77
+ // Android JSC is installed from npm
78
+ url "$rootDir/../node_modules/jsc-android/dist"
79
+ }
80
+ google()
81
+ }
82
+
83
+ dependencies {
84
+ //noinspection GradleDynamicVersion
85
+ implementation 'com.facebook.react:react-native:+' // From node_modules
86
+ implementation 'com.google.android.gms:play-services-mlkit-document-scanner:16.0.0-beta1'
87
+ }
88
+
89
+ afterEvaluate { project ->
90
+ // some Gradle build hooks ref:
91
+ // https://www.oreilly.com/library/view/gradle-beyond-the/9781449373801/ch03.html
92
+ task androidJavadoc(type: Javadoc) {
93
+ source = android.sourceSets.main.java.srcDirs
94
+ classpath += files(android.bootClasspath)
95
+ // Use a resolvable configuration when available; on some AGP setups
96
+ // (when this library is consumed from node_modules), a top-level
97
+ // 'compileClasspath' config may not exist. In that case, skip adding it.
98
+ def cc = project.configurations.findByName('compileClasspath')
99
+ if (cc != null) {
100
+ classpath += files(cc.asList())
101
+ } else {
102
+ logger.lifecycle("react-native-document-scanner: 'compileClasspath' not found; skipping extra Javadoc classpath setup.")
103
+ }
104
+ include '**/*.java'
105
+
106
+ // Suppress warnings for missing documentation
107
+ options.addStringOption('Xdoclint:none', '-quiet')
108
+ }
109
+
110
+ task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {
111
+ archiveClassifier.set('javadoc')
112
+ from androidJavadoc.destinationDir
113
+ }
114
+
115
+ task androidSourcesJar(type: Jar) {
116
+ archiveClassifier.set('sources')
117
+ from android.sourceSets.main.java.srcDirs
118
+ include '**/*.java'
119
+ }
120
+
121
+ android.libraryVariants.all { variant ->
122
+ def name = variant.name.capitalize()
123
+ def javaCompileTask = variant.javaCompileProvider.get()
124
+
125
+ task "jar${name}"(type: Jar, dependsOn: javaCompileTask) {
126
+ from javaCompileTask.destinationDir
127
+ }
128
+ }
129
+ }
130
+
131
+ // Modern maven-publish plugin configuration
132
+ def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text)
133
+
134
+ afterEvaluate {
135
+ // Only configure publishing if the Android components expose a 'release' variant
136
+ def releaseComponent = components.findByName("release")
137
+ if (releaseComponent != null) {
138
+ publishing {
139
+ publications {
140
+ release(MavenPublication) {
141
+ from releaseComponent
142
+
143
+ groupId = 'com.docscanner'
144
+ artifactId = packageJson.name
145
+ version = packageJson.version
146
+
147
+ artifact androidSourcesJar
148
+ artifact androidJavadocJar
149
+
150
+ pom {
151
+ name = packageJson.title
152
+ description = packageJson.description
153
+ url = packageJson.repository.baseUrl
154
+
155
+ licenses {
156
+ license {
157
+ name = packageJson.license
158
+ url = packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename
159
+ distribution = 'repo'
160
+ }
161
+ }
162
+
163
+ developers {
164
+ developer {
165
+ id = packageJson.author.name
166
+ name = packageJson.author.name
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ repositories {
173
+ maven {
174
+ // Deploy to react-native-document-scanner/android/maven, ready to publish to npm
175
+ url = uri("file://${projectDir}/../android/maven")
176
+ }
177
+ }
178
+ }
179
+ } else {
180
+ logger.lifecycle("react-native-document-scanner: Skipping maven-publish because no 'release' component is available (AGP too old or not applied).")
181
+ }
182
+ }
@@ -0,0 +1,9 @@
1
+ <!-- AndroidManifest.xml -->
2
+
3
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
4
+ package="com.docscanner">
5
+
6
+ <!-- Required for ML Kit Document Scanner -->
7
+ <uses-permission android:name="android.permission.CAMERA" />
8
+
9
+ </manifest>
@@ -0,0 +1,261 @@
1
+ // DocumentScannerModule.java
2
+
3
+ package com.docscanner;
4
+
5
+ import android.app.Activity;
6
+ import android.content.Intent;
7
+ import android.graphics.Bitmap;
8
+ import android.net.Uri;
9
+ import android.util.Base64;
10
+ import android.util.Log;
11
+
12
+ import androidx.activity.result.ActivityResult;
13
+ import androidx.activity.result.ActivityResultLauncher;
14
+ import androidx.activity.result.IntentSenderRequest;
15
+ import androidx.activity.result.contract.ActivityResultContracts;
16
+
17
+ import com.facebook.react.bridge.ActivityEventListener;
18
+ import com.facebook.react.bridge.BaseActivityEventListener;
19
+ import com.facebook.react.bridge.Callback;
20
+ import com.facebook.react.bridge.ReactApplicationContext;
21
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
22
+ import com.facebook.react.bridge.ReactMethod;
23
+ import com.facebook.react.bridge.ReadableMap;
24
+ import com.facebook.react.bridge.WritableArray;
25
+ import com.facebook.react.bridge.WritableMap;
26
+ import com.facebook.react.bridge.WritableNativeArray;
27
+ import com.facebook.react.bridge.WritableNativeMap;
28
+
29
+ import com.google.mlkit.vision.documentscanner.GmsDocumentScanner;
30
+ import com.google.mlkit.vision.documentscanner.GmsDocumentScannerOptions;
31
+ import com.google.mlkit.vision.documentscanner.GmsDocumentScanning;
32
+ import com.google.mlkit.vision.documentscanner.GmsDocumentScanningResult;
33
+
34
+ import java.io.ByteArrayOutputStream;
35
+ import java.io.File;
36
+ import java.io.FileOutputStream;
37
+ import java.io.IOException;
38
+ import java.io.InputStream;
39
+ import java.util.UUID;
40
+
41
+ // For New Architecture: extend the generated spec base class
42
+ // This class is generated by React Native Codegen based on src/NativeDocumentScanner.ts
43
+ // and will be available when newArchEnabled=true
44
+ @SuppressWarnings("KotlinInternalInJava")
45
+ public class DocumentScannerModule extends com.docscanner.NativeDocumentScannerSpec {
46
+
47
+ public static final String NAME = "DocumentScanner";
48
+ private static final String TAG = "DocumentScannerModule";
49
+ private static final int DOCUMENT_SCAN_REQUEST = 1001;
50
+
51
+ private final ReactApplicationContext reactContext;
52
+ private Callback scannerCallback;
53
+ private ReadableMap scannerOptions;
54
+
55
+ private final ActivityEventListener activityEventListener = new BaseActivityEventListener() {
56
+ @Override
57
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
58
+ if (requestCode == DOCUMENT_SCAN_REQUEST) {
59
+ handleScanResult(resultCode, data);
60
+ }
61
+ }
62
+ };
63
+
64
+ public DocumentScannerModule(ReactApplicationContext reactContext) {
65
+ super(reactContext);
66
+ this.reactContext = reactContext;
67
+ reactContext.addActivityEventListener(activityEventListener);
68
+ }
69
+
70
+ @Override
71
+ public String getName() {
72
+ return NAME;
73
+ }
74
+
75
+ @ReactMethod
76
+ @Override
77
+ public void launchScanner(ReadableMap options, Callback callback) {
78
+ Activity currentActivity = getCurrentActivity();
79
+
80
+ if (currentActivity == null) {
81
+ WritableMap errorResponse = new WritableNativeMap();
82
+ errorResponse.putBoolean("error", true);
83
+ errorResponse.putString("errorMessage", "Activity doesn't exist");
84
+ callback.invoke(errorResponse);
85
+ return;
86
+ }
87
+
88
+ scannerCallback = callback;
89
+ scannerOptions = options;
90
+
91
+ // Configure the scanner
92
+ GmsDocumentScannerOptions.Builder optionsBuilder = new GmsDocumentScannerOptions.Builder()
93
+ .setGalleryImportAllowed(false)
94
+ .setPageLimit(10)
95
+ .setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_JPEG, GmsDocumentScannerOptions.RESULT_FORMAT_PDF)
96
+ .setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL);
97
+
98
+ GmsDocumentScannerOptions scannerOptions = optionsBuilder.build();
99
+ GmsDocumentScanner scanner = GmsDocumentScanning.getClient(scannerOptions);
100
+
101
+ scanner.getStartScanIntent(currentActivity)
102
+ .addOnSuccessListener(intentSender -> {
103
+ try {
104
+ currentActivity.startIntentSenderForResult(
105
+ intentSender,
106
+ DOCUMENT_SCAN_REQUEST,
107
+ null,
108
+ 0,
109
+ 0,
110
+ 0
111
+ );
112
+ } catch (Exception e) {
113
+ Log.e(TAG, "Error starting scanner", e);
114
+ WritableMap errorResponse = new WritableNativeMap();
115
+ errorResponse.putBoolean("error", true);
116
+ errorResponse.putString("errorMessage", e.getMessage());
117
+ callback.invoke(errorResponse);
118
+ }
119
+ })
120
+ .addOnFailureListener(e -> {
121
+ Log.e(TAG, "Error getting scan intent", e);
122
+ WritableMap errorResponse = new WritableNativeMap();
123
+ errorResponse.putBoolean("error", true);
124
+ errorResponse.putString("errorMessage", e.getMessage());
125
+ callback.invoke(errorResponse);
126
+ });
127
+ }
128
+
129
+ private void handleScanResult(int resultCode, Intent data) {
130
+ if (scannerCallback == null) {
131
+ return;
132
+ }
133
+
134
+ if (resultCode == Activity.RESULT_CANCELED) {
135
+ WritableMap response = new WritableNativeMap();
136
+ response.putBoolean("didCancel", true);
137
+ scannerCallback.invoke(response);
138
+ scannerCallback = null;
139
+ return;
140
+ }
141
+
142
+ if (resultCode != Activity.RESULT_OK || data == null) {
143
+ WritableMap errorResponse = new WritableNativeMap();
144
+ errorResponse.putBoolean("error", true);
145
+ errorResponse.putString("errorMessage", "Scan failed");
146
+ scannerCallback.invoke(errorResponse);
147
+ scannerCallback = null;
148
+ return;
149
+ }
150
+
151
+ GmsDocumentScanningResult result = GmsDocumentScanningResult.fromActivityResultIntent(data);
152
+ if (result == null) {
153
+ WritableMap errorResponse = new WritableNativeMap();
154
+ errorResponse.putBoolean("error", true);
155
+ errorResponse.putString("errorMessage", "Failed to get scan result");
156
+ scannerCallback.invoke(errorResponse);
157
+ scannerCallback = null;
158
+ return;
159
+ }
160
+
161
+ WritableArray imagesArray = new WritableNativeArray();
162
+
163
+ // Process each scanned page
164
+ GmsDocumentScanningResult.Page[] pages = result.getPages().toArray(new GmsDocumentScanningResult.Page[0]);
165
+ for (GmsDocumentScanningResult.Page page : pages) {
166
+ Uri imageUri = page.getImageUri();
167
+ try {
168
+ WritableMap imageObject = processImage(imageUri);
169
+ if (imageObject != null) {
170
+ imagesArray.pushMap(imageObject);
171
+ }
172
+ } catch (Exception e) {
173
+ Log.e(TAG, "Error processing image", e);
174
+ }
175
+ }
176
+
177
+ WritableMap response = new WritableNativeMap();
178
+ response.putArray("images", imagesArray);
179
+ scannerCallback.invoke(response);
180
+ scannerCallback = null;
181
+ }
182
+
183
+ private WritableMap processImage(Uri imageUri) throws IOException {
184
+ WritableMap imageObject = new WritableNativeMap();
185
+
186
+ Activity currentActivity = getCurrentActivity();
187
+ if (currentActivity == null) {
188
+ return null;
189
+ }
190
+
191
+ // Read the image
192
+ InputStream inputStream = currentActivity.getContentResolver().openInputStream(imageUri);
193
+ if (inputStream == null) {
194
+ return null;
195
+ }
196
+
197
+ byte[] imageBytes = readBytes(inputStream);
198
+ inputStream.close();
199
+
200
+ // Decode bitmap to get dimensions
201
+ android.graphics.BitmapFactory.Options options = new android.graphics.BitmapFactory.Options();
202
+ options.inJustDecodeBounds = false;
203
+ Bitmap bitmap = android.graphics.BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
204
+
205
+ if (bitmap == null) {
206
+ return null;
207
+ }
208
+
209
+ // Apply quality compression if needed
210
+ double quality = 1.0;
211
+ if (scannerOptions != null && scannerOptions.hasKey("quality")) {
212
+ quality = scannerOptions.getDouble("quality");
213
+ }
214
+
215
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
216
+ int qualityPercent = (int) (quality * 100);
217
+ bitmap.compress(Bitmap.CompressFormat.JPEG, qualityPercent, outputStream);
218
+ byte[] processedImageBytes = outputStream.toByteArray();
219
+ outputStream.close();
220
+
221
+ // Save to cache directory
222
+ String fileName = UUID.randomUUID().toString() + ".jpg";
223
+ File cacheDir = currentActivity.getCacheDir();
224
+ File imageFile = new File(cacheDir, fileName);
225
+
226
+ FileOutputStream fileOutputStream = new FileOutputStream(imageFile);
227
+ fileOutputStream.write(processedImageBytes);
228
+ fileOutputStream.close();
229
+
230
+ // Build response
231
+ imageObject.putString("uri", Uri.fromFile(imageFile).toString());
232
+ imageObject.putString("fileName", fileName);
233
+ imageObject.putString("type", "image/jpeg");
234
+ imageObject.putInt("width", bitmap.getWidth());
235
+ imageObject.putInt("height", bitmap.getHeight());
236
+ imageObject.putInt("fileSize", processedImageBytes.length);
237
+
238
+ // Add base64 if requested
239
+ if (scannerOptions != null && scannerOptions.hasKey("includeBase64") &&
240
+ scannerOptions.getBoolean("includeBase64")) {
241
+ String base64 = Base64.encodeToString(processedImageBytes, Base64.NO_WRAP);
242
+ imageObject.putString("base64", base64);
243
+ }
244
+
245
+ bitmap.recycle();
246
+
247
+ return imageObject;
248
+ }
249
+
250
+ private byte[] readBytes(InputStream inputStream) throws IOException {
251
+ ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
252
+ byte[] buffer = new byte[16384];
253
+ int len;
254
+ while ((len = inputStream.read(buffer)) != -1) {
255
+ byteBuffer.write(buffer, 0, len);
256
+ }
257
+ return byteBuffer.toByteArray();
258
+ }
259
+ }
260
+
261
+
@@ -0,0 +1,49 @@
1
+ // DocumentScannerPackage.java
2
+
3
+ package com.docscanner;
4
+
5
+ import androidx.annotation.Nullable;
6
+
7
+ import java.util.HashMap;
8
+ import java.util.Map;
9
+
10
+ import com.facebook.react.bridge.NativeModule;
11
+ import com.facebook.react.bridge.ReactApplicationContext;
12
+ import com.facebook.react.TurboReactPackage;
13
+ import com.facebook.react.module.model.ReactModuleInfo;
14
+ import com.facebook.react.module.model.ReactModuleInfoProvider;
15
+
16
+ public class DocumentScannerPackage extends TurboReactPackage {
17
+
18
+ @Nullable
19
+ @Override
20
+ public NativeModule getModule(String name, ReactApplicationContext reactContext) {
21
+ if (name.equals(DocumentScannerModule.NAME)) {
22
+ return new DocumentScannerModule(reactContext);
23
+ } else {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ @Override
29
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
30
+ return () -> {
31
+ final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
32
+ boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
33
+ moduleInfos.put(
34
+ DocumentScannerModule.NAME,
35
+ new ReactModuleInfo(
36
+ DocumentScannerModule.NAME,
37
+ DocumentScannerModule.NAME,
38
+ false, // canOverrideExistingModule
39
+ false, // needsEagerInit
40
+ true, // hasConstants
41
+ false, // isCxxModule
42
+ isTurboModule // isTurboModule
43
+ ));
44
+ return moduleInfos;
45
+ };
46
+ }
47
+ }
48
+
49
+
@@ -0,0 +1,2 @@
1
+ # This directory contains media assets for documentation (README screenshots, videos, etc.)
2
+
Binary file
Binary file
package/index.d.ts ADDED
@@ -0,0 +1,126 @@
1
+ // Type definitions for react-native-document-scanner
2
+ // Project: https://github.com/dariyd/react-native-document-scanner
3
+
4
+ export interface ImageObject {
5
+ /**
6
+ * The base64 string of the image (only if includeBase64 option is true)
7
+ */
8
+ base64?: string;
9
+
10
+ /**
11
+ * The file URI in app specific cache storage
12
+ */
13
+ uri: string;
14
+
15
+ /**
16
+ * Image width in pixels
17
+ */
18
+ width: number;
19
+
20
+ /**
21
+ * Image height in pixels
22
+ */
23
+ height: number;
24
+
25
+ /**
26
+ * The file size in bytes
27
+ */
28
+ fileSize: number;
29
+
30
+ /**
31
+ * The file MIME type (e.g., "image/jpeg")
32
+ */
33
+ type: string;
34
+
35
+ /**
36
+ * The file name
37
+ */
38
+ fileName: string;
39
+ }
40
+
41
+ export interface ScanResult {
42
+ /**
43
+ * True if the user cancelled the scanning process
44
+ */
45
+ didCancel?: boolean;
46
+
47
+ /**
48
+ * True if an error occurred
49
+ */
50
+ error?: boolean;
51
+
52
+ /**
53
+ * Description of the error (for debug purposes only)
54
+ */
55
+ errorMessage?: string;
56
+
57
+ /**
58
+ * Array of scanned images
59
+ */
60
+ images?: ImageObject[];
61
+ }
62
+
63
+ export interface ScanOptions {
64
+ /**
65
+ * Image quality from 0 to 1 (default: 1)
66
+ * Lower values reduce file size
67
+ *
68
+ * @default 1
69
+ */
70
+ quality?: number;
71
+
72
+ /**
73
+ * If true, includes base64 string of the image in the result
74
+ * Avoid using on large image files due to performance impact
75
+ *
76
+ * @default false
77
+ */
78
+ includeBase64?: boolean;
79
+ }
80
+
81
+ /**
82
+ * Launch the document scanner
83
+ *
84
+ * @param options - Scanner options
85
+ * @param callback - Optional callback function
86
+ * @returns Promise that resolves with the scan result
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * import { launchScanner } from 'react-native-document-scanner';
91
+ *
92
+ * // Basic usage
93
+ * const result = await launchScanner();
94
+ *
95
+ * // With options
96
+ * const result = await launchScanner({
97
+ * quality: 0.8,
98
+ * includeBase64: false,
99
+ * });
100
+ *
101
+ * // With callback
102
+ * launchScanner({ quality: 0.9 }, (result) => {
103
+ * if (result.didCancel) {
104
+ * console.log('User cancelled');
105
+ * } else if (result.error) {
106
+ * console.log('Error:', result.errorMessage);
107
+ * } else {
108
+ * console.log('Scanned images:', result.images);
109
+ * }
110
+ * });
111
+ * ```
112
+ */
113
+ export function launchScanner(
114
+ options?: ScanOptions,
115
+ callback?: (result: ScanResult) => void
116
+ ): Promise<ScanResult>;
117
+
118
+ declare const DocumentScanner: {
119
+ launchScanner: (
120
+ options: ScanOptions,
121
+ callback: (result: ScanResult) => void
122
+ ) => void;
123
+ };
124
+
125
+ export default DocumentScanner;
126
+
package/index.js ADDED
@@ -0,0 +1,46 @@
1
+ // main index.js
2
+
3
+ import { NativeModules, Platform } from 'react-native';
4
+
5
+ // Try to get the TurboModule (new architecture)
6
+ let DocumentScannerModule;
7
+ try {
8
+ DocumentScannerModule = require('./src/NativeDocumentScanner').default;
9
+ } catch (e) {
10
+ // Fall back to old architecture
11
+ DocumentScannerModule = NativeModules.DocumentScanner;
12
+ }
13
+
14
+ // If still not available, try the old way
15
+ if (!DocumentScannerModule) {
16
+ DocumentScannerModule = NativeModules.DocumentScanner;
17
+ }
18
+
19
+ export default DocumentScannerModule;
20
+
21
+ const DEFAULT_OPTIONS = {
22
+ quality: 1,
23
+ includeBase64: false,
24
+ };
25
+
26
+ export function launchScanner(options = {}, callback) {
27
+ return new Promise((resolve, reject) => {
28
+ if (!DocumentScannerModule) {
29
+ const error = {
30
+ error: true,
31
+ errorMessage: 'DocumentScanner module is not available',
32
+ };
33
+ if (callback) callback(error);
34
+ reject(error);
35
+ return;
36
+ }
37
+
38
+ DocumentScannerModule.launchScanner(
39
+ {...DEFAULT_OPTIONS, ...options},
40
+ (result) => {
41
+ if (callback) callback(result);
42
+ resolve(result);
43
+ },
44
+ );
45
+ });
46
+ }