11package com .reactnativedocumentscanner ;
22
33import android .app .Activity ;
4- import android .content .Intent ;
4+ import android .graphics .Bitmap ;
5+ import android .graphics .BitmapFactory ;
6+ import android .net .Uri ;
7+ import android .util .Base64 ;
58import androidx .activity .ComponentActivity ;
6- import androidx .activity .result .ActivityResult ;
9+ import androidx .activity .result .ActivityResultLauncher ;
10+ import androidx .activity .result .IntentSenderRequest ;
11+ import androidx .activity .result .contract .ActivityResultContracts ;
712import androidx .annotation .NonNull ;
8- import com .facebook .react .bridge .ActivityEventListener ;
9- import com .facebook .react .bridge .BaseActivityEventListener ;
1013import com .facebook .react .bridge .Promise ;
1114import com .facebook .react .bridge .ReactApplicationContext ;
1215import com .facebook .react .bridge .ReactContextBaseJavaModule ;
1720import com .facebook .react .bridge .WritableNativeArray ;
1821import com .facebook .react .bridge .WritableNativeMap ;
1922import com .facebook .react .module .annotations .ReactModule ;
20- import com .websitebeaver .documentscanner .DocumentScanner ;
21- import com .websitebeaver .documentscanner .constants .DocumentScannerExtra ;
22- import java .util .ArrayList ;
23+ import com .google .mlkit .vision .documentscanner .GmsDocumentScanner ;
24+ import com .google .mlkit .vision .documentscanner .GmsDocumentScannerOptions ;
25+ import com .google .mlkit .vision .documentscanner .GmsDocumentScanning ;
26+ import com .google .mlkit .vision .documentscanner .GmsDocumentScanningResult ;
27+ import com .google .mlkit .vision .documentscanner .GmsDocumentScanningResult .Page ;
28+ import java .io .ByteArrayOutputStream ;
29+ import java .io .FileNotFoundException ;
30+ import java .util .List ;
31+ import java .util .Objects ;
2332
2433@ ReactModule (name = DocumentScannerModule .NAME )
2534public class DocumentScannerModule extends ReactContextBaseJavaModule {
2635 public static final String NAME = "DocumentScanner" ;
2736
28- private static final int DOCUMENT_SCAN_REQUEST = 938 ;
29-
30- DocumentScanner documentScanner ;
31-
32- private ActivityEventListener activityEventListener = new BaseActivityEventListener () {
33- @ Override
34- public void onActivityResult (
35- final Activity activity ,
36- final int requestCode ,
37- final int resultCode ,
38- final Intent intent ) {
39- // trigger callbacks (success, cancel, error)
40- if (requestCode == DOCUMENT_SCAN_REQUEST && documentScanner != null ) {
41- documentScanner .handleDocumentScanIntentResult (
42- new ActivityResult (resultCode , intent )
43- );
44- }
45- }
46- };
47-
4837 public DocumentScannerModule (ReactApplicationContext reactContext ) {
4938 super (reactContext );
50- reactContext .addActivityEventListener (activityEventListener );
5139 }
5240
5341 @ Override
@@ -56,56 +44,89 @@ public String getName() {
5644 return NAME ;
5745 }
5846
47+ public String getImageInBase64 (Activity currentActivity , Uri croppedImageUri , int quality ) throws FileNotFoundException {
48+ Bitmap bitmap = BitmapFactory .decodeStream (
49+ currentActivity .getContentResolver ().openInputStream (croppedImageUri )
50+ );
51+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream ();
52+ bitmap .compress (Bitmap .CompressFormat .JPEG , quality , byteArrayOutputStream );
53+ byte [] byteArray = byteArrayOutputStream .toByteArray ();
54+ return Base64 .encodeToString (byteArray , Base64 .DEFAULT );
55+ }
56+
5957 @ ReactMethod
6058 public void scanDocument (ReadableMap options , Promise promise ) {
6159 Activity currentActivity = getCurrentActivity ();
6260 WritableMap response = new WritableNativeMap ();
6361
64- // create a document scanner
65- documentScanner = new DocumentScanner (
66- (ComponentActivity ) currentActivity ,
67- (ArrayList <String > documentScanResults ) -> {
68- // document scan success
69- WritableArray docScanResults = new WritableNativeArray ();
70- documentScanResults .forEach (
71- documentScanResult -> docScanResults .pushString (documentScanResult )
72- );
73- response .putArray (
62+ GmsDocumentScannerOptions .Builder documentScannerOptionsBuilder = new GmsDocumentScannerOptions .Builder ()
63+ .setResultFormats (GmsDocumentScannerOptions .RESULT_FORMAT_JPEG )
64+ .setScannerMode (GmsDocumentScannerOptions .SCANNER_MODE_FULL );
65+
66+ if (options .hasKey ("maxNumDocuments" )) {
67+ documentScannerOptionsBuilder .setPageLimit (
68+ options .getInt ("maxNumDocuments" )
69+ );
70+ }
71+
72+ int croppedImageQuality ;
73+ if (options .hasKey ("croppedImageQuality" )) {
74+ croppedImageQuality = options .getInt ("croppedImageQuality" );
75+ } else {
76+ croppedImageQuality = 100 ;
77+ }
78+
79+ GmsDocumentScanner scanner = GmsDocumentScanning .getClient (documentScannerOptionsBuilder .build ());
80+ ActivityResultLauncher <IntentSenderRequest > scannerLauncher = ((ComponentActivity ) currentActivity ).getActivityResultRegistry ().register (
81+ "document-scanner" ,
82+ new ActivityResultContracts .StartIntentSenderForResult (),
83+ result -> {
84+ if (result .getResultCode () == Activity .RESULT_OK ) {
85+ GmsDocumentScanningResult documentScanningResult = GmsDocumentScanningResult .fromActivityResultIntent (
86+ result .getData ()
87+ );
88+ WritableArray docScanResults = new WritableNativeArray ();
89+
90+ if (documentScanningResult != null ) {
91+ List <Page > pages = documentScanningResult .getPages ();
92+ if (pages != null ) {
93+ for (Page page : pages ) {
94+ Uri croppedImageUri = page .getImageUri ();
95+ String croppedImageResults = croppedImageUri .toString ();
96+
97+ if (options .hasKey ("responseType" ) && Objects .equals (options .getString ("responseType" ), "base64" )) {
98+ try {
99+ croppedImageResults = this .getImageInBase64 (currentActivity , croppedImageUri , croppedImageQuality );
100+ } catch (FileNotFoundException error ) {
101+ promise .reject ("document scan error" , error .getMessage ());
102+ }
103+ }
104+
105+ docScanResults .pushString (croppedImageResults );
106+ }
107+ }
108+ }
109+
110+ response .putArray (
74111 "scannedImages" ,
75112 docScanResults
76- );
77- response .putString ("status" , "success" );
78- promise .resolve (response );
79- return null ;
80- },
81- (String errorMessage ) -> {
82- // document scan error
83- promise .reject ("document scan error" , errorMessage );
84- return null ;
85- },
86- () -> {
87- // when user cancels document scan
88- response .putString ("status" , "cancel" );
89- promise .resolve (response );
90- return null ;
91- },
92- options .hasKey ("responseType" )
93- ? options .getString ("responseType" ) : null ,
94- options .hasKey (DocumentScannerExtra .EXTRA_LET_USER_ADJUST_CROP )
95- ? options .getBoolean (DocumentScannerExtra .EXTRA_LET_USER_ADJUST_CROP )
96- : null ,
97- options .hasKey (DocumentScannerExtra .EXTRA_MAX_NUM_DOCUMENTS )
98- ? options .getInt (DocumentScannerExtra .EXTRA_MAX_NUM_DOCUMENTS )
99- : null ,
100- options .hasKey (DocumentScannerExtra .EXTRA_CROPPED_IMAGE_QUALITY )
101- ? options .getInt (DocumentScannerExtra .EXTRA_CROPPED_IMAGE_QUALITY )
102- : null
113+ );
114+ response .putString ("status" , "success" );
115+ promise .resolve (response );
116+ } else if (result .getResultCode () == Activity .RESULT_CANCELED ) {
117+ // when user cancels document scan
118+ response .putString ("status" , "cancel" );
119+ promise .resolve (response );
120+ }
121+ }
103122 );
104123
105- // launch the document scanner
106- currentActivity .startActivityForResult (
107- documentScanner .createDocumentScanIntent (),
108- DOCUMENT_SCAN_REQUEST
109- );
124+ scanner .getStartScanIntent (currentActivity )
125+ .addOnSuccessListener (intentSender ->
126+ scannerLauncher .launch (new IntentSenderRequest .Builder (intentSender ).build ()))
127+ .addOnFailureListener (error -> {
128+ // document scan error
129+ promise .reject ("document scan error" , error .getMessage ());
130+ });
110131 }
111132}
0 commit comments