diff --git a/README.md b/README.md
index 19906f8..929d8a8 100644
--- a/README.md
+++ b/README.md
@@ -183,11 +183,30 @@ Opens the camera, and starts the document scan
| ----------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| **`croppedImageQuality`** | number | The quality of the cropped image from 0 - 100. 100 is the best quality. | : 100 |
| **`maxNumDocuments`** | number | Android only: The maximum number of photos an user can take (not counting photo retakes) | : undefined |
+| **`scannerMode`** | ScannerMode | Android only: The scanner feature set to enable. `ScannerMode.BASE` provides basic scanning and editing features, `ScannerMode.BASE_WITH_FILTER` adds image filters, and `ScannerMode.FULL` adds ML-enabled image cleaning. | : ScannerMode.FULL |
| **`responseType`** | ResponseType | The response comes back in this format on success. It can be the document scan image file paths or base64 images. | : ResponseType.ImageFilePath |
### Enums
+#### ScannerMode
+
+Android-only scanner modes. `ScannerMode.FULL` remains the default for backwards compatibility.
+
+| Member | Value | Description |
+| --- | --- | --- |
+| **`BASE`** | 'base' | Basic scanning features such as capture, auto rotation, crop, and page reordering. |
+| **`BASE_WITH_FILTER`** | 'base_with_filter' | Basic scanning features plus image filters. |
+| **`FULL`** | 'full' | The full feature set, including ML-enabled image cleaning. |
+
+```tsx
+import DocumentScanner, { ScannerMode } from 'react-native-document-scanner-plugin'
+
+const { scannedImages } = await DocumentScanner.scanDocument({
+ scannerMode: ScannerMode.BASE,
+})
+```
+
#### ScanDocumentResponseStatus
@@ -291,4 +310,4 @@ export default () => {
)
}
```
-
\ No newline at end of file
+
diff --git a/android/src/main/java/com/documentscanner/DocumentScannerModule.kt b/android/src/main/java/com/documentscanner/DocumentScannerModule.kt
index fbb6836..bc79804 100644
--- a/android/src/main/java/com/documentscanner/DocumentScannerModule.kt
+++ b/android/src/main/java/com/documentscanner/DocumentScannerModule.kt
@@ -51,7 +51,7 @@ class DocumentScannerModule(reactContext: ReactApplicationContext) :
val documentScannerOptionsBuilder = GmsDocumentScannerOptions.Builder()
.setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_JPEG)
- .setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL)
+ .setScannerMode(getScannerMode(options))
if (options.hasKey("maxNumDocuments")) {
documentScannerOptionsBuilder.setPageLimit(
@@ -132,6 +132,23 @@ class DocumentScannerModule(reactContext: ReactApplicationContext) :
})
}
+ private fun getScannerMode(options: ReadableMap): Int {
+ return try {
+ if (!options.hasKey("scannerMode") || options.isNull("scannerMode")) {
+ return GmsDocumentScannerOptions.SCANNER_MODE_FULL
+ }
+
+ when (options.getString("scannerMode")) {
+ "base" -> GmsDocumentScannerOptions.SCANNER_MODE_BASE
+ "base_with_filter" -> GmsDocumentScannerOptions.SCANNER_MODE_BASE_WITH_FILTER
+ "full" -> GmsDocumentScannerOptions.SCANNER_MODE_FULL
+ else -> GmsDocumentScannerOptions.SCANNER_MODE_FULL
+ }
+ } catch (_: RuntimeException) {
+ GmsDocumentScannerOptions.SCANNER_MODE_FULL
+ }
+ }
+
companion object {
const val NAME = "DocumentScanner"
}
diff --git a/example/src/App.tsx b/example/src/App.tsx
index 84ba72e..5dab220 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -1,33 +1,127 @@
-import { useState, useEffect } from 'react';
-import { Image } from 'react-native';
-import DocumentScanner from 'react-native-document-scanner-plugin';
+import { useState } from 'react';
+import {
+ Image,
+ Platform,
+ Pressable,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+import DocumentScanner, {
+ ScannerMode,
+} from 'react-native-document-scanner-plugin';
+
+const scannerModes = [
+ { mode: ScannerMode.BASE, label: 'Base' },
+ { mode: ScannerMode.BASE_WITH_FILTER, label: 'Base with filter' },
+ { mode: ScannerMode.FULL, label: 'Full' },
+];
export default () => {
- const [scannedImage, setScannedImage] = useState();
+ const [scannedImage, setScannedImage] = useState();
+ const [scannerMode, setScannerMode] = useState(ScannerMode.FULL);
const scanDocument = async () => {
- // start the document scanner
- const { scannedImages } = await DocumentScanner.scanDocument();
-
- // check if undefined
- if (scannedImages) {
- // get back an array with scanned image file paths
- if (scannedImages.length > 0) {
- // set the img src, so we can view the first scanned image
- setScannedImage(scannedImages[0]);
- }
+ const options = Platform.OS === 'android' ? { scannerMode } : undefined;
+ const { scannedImages } = await DocumentScanner.scanDocument(options);
+
+ if (scannedImages && scannedImages.length > 0) {
+ setScannedImage(scannedImages[0]);
}
};
- useEffect(() => {
- // call scanDocument on load
- scanDocument();
- }, []);
-
return (
-
+
+ {Platform.OS === 'android' && (
+
+ Scanner mode
+
+ {scannerModes.map(({ mode, label }) => (
+ setScannerMode(mode)}
+ style={[
+ styles.modeButton,
+ scannerMode === mode && styles.selectedModeButton,
+ ]}
+ >
+
+ {label}
+
+
+ ))}
+
+
+ )}
+
+
+ Scan document
+
+
+ {scannedImage && (
+
+ )}
+
);
};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 24,
+ backgroundColor: '#fff',
+ },
+ controls: {
+ marginTop: 24,
+ },
+ title: {
+ marginBottom: 8,
+ fontSize: 18,
+ fontWeight: '600',
+ },
+ modeSelector: {
+ gap: 8,
+ },
+ modeButton: {
+ padding: 12,
+ borderWidth: 1,
+ borderColor: '#777',
+ borderRadius: 6,
+ },
+ selectedModeButton: {
+ backgroundColor: '#222',
+ borderColor: '#222',
+ },
+ modeButtonText: {
+ textAlign: 'center',
+ color: '#222',
+ },
+ selectedModeButtonText: {
+ color: '#fff',
+ },
+ scanButton: {
+ marginTop: 16,
+ padding: 14,
+ borderRadius: 6,
+ backgroundColor: '#1976d2',
+ },
+ scanButtonText: {
+ textAlign: 'center',
+ color: '#fff',
+ fontWeight: '600',
+ },
+ image: {
+ flex: 1,
+ width: '100%',
+ marginTop: 24,
+ },
+});
diff --git a/src/NativeDocumentScanner.ts b/src/NativeDocumentScanner.ts
index 449eeb0..4f6a66e 100644
--- a/src/NativeDocumentScanner.ts
+++ b/src/NativeDocumentScanner.ts
@@ -4,6 +4,25 @@ export interface Spec extends TurboModule {
scanDocument(options: ScanDocumentOptions): Promise;
}
+export enum ScannerMode {
+ /**
+ * Basic scanning features such as capture, auto rotation, crop, and page
+ * reordering. Android only.
+ */
+ BASE = 'base',
+
+ /**
+ * Basic scanning features plus image filters. Android only.
+ */
+ BASE_WITH_FILTER = 'base_with_filter',
+
+ /**
+ * The full scanner feature set, including ML-enabled image cleaning.
+ * Android only and the default mode.
+ */
+ FULL = 'full',
+}
+
export interface ScanDocumentOptions {
/**
* The quality of the cropped image from 0 - 100. 100 is the best quality.
@@ -17,6 +36,12 @@ export interface ScanDocumentOptions {
*/
maxNumDocuments?: number;
+ /**
+ * Android only: The scanner feature set to enable.
+ * @default: ScannerMode.FULL
+ */
+ scannerMode?: ScannerMode;
+
/**
* The response comes back in this format on success. It can be the document
* scan image file paths or base64 images.
diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx
index bf84291..cded953 100644
--- a/src/__tests__/index.test.tsx
+++ b/src/__tests__/index.test.tsx
@@ -1 +1,24 @@
-it.todo('write a test');
+jest.mock('react-native', () => ({
+ TurboModuleRegistry: {
+ getEnforcing: jest.fn(),
+ },
+}));
+
+import {
+ ResponseType,
+ ScannerMode,
+ ScanDocumentResponseStatus,
+} from '../index';
+
+describe('public API constants', () => {
+ it('exposes the supported scanner modes', () => {
+ expect(ScannerMode.BASE).toBe('base');
+ expect(ScannerMode.BASE_WITH_FILTER).toBe('base_with_filter');
+ expect(ScannerMode.FULL).toBe('full');
+ });
+
+ it('preserves existing exported constants', () => {
+ expect(ResponseType.ImageFilePath).toBe('imageFilePath');
+ expect(ScanDocumentResponseStatus.Success).toBe('success');
+ });
+});
diff --git a/src/index.tsx b/src/index.tsx
index d7176a2..2a043af 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -10,6 +10,7 @@ export type {
export {
ResponseType,
+ ScannerMode,
ScanDocumentResponseStatus,
} from './NativeDocumentScanner';