Browse Source

compdfkit(rn) - 新增密码、水印、界面等交互接口

liuxiaolong 2 months ago
parent
commit
19bf67b123
33 changed files with 3431 additions and 178 deletions
  1. 1 4
      android/build.gradle
  2. BIN
      android/libs/ComPDFKit-UI.aar
  3. BIN
      android/libs/ComPDFKit.aar
  4. BIN
      android/libs/ComPDFKit_Tools-release.aar
  5. 4 5
      android/src/main/java/com/compdfkitpdf/reactnative/CompdfkitPdfModule.java
  6. 341 0
      android/src/main/java/com/compdfkitpdf/reactnative/modules/CPDFViewModule.java
  7. 1 2
      android/src/main/java/com/compdfkitpdf/reactnative/view/CPDFView.java
  8. 371 11
      android/src/main/java/com/compdfkitpdf/reactnative/viewmanager/CPDFViewManager.java
  9. 17 1
      example/App.tsx
  10. 0 1
      example/android/app/build.gradle
  11. BIN
      example/android/app/libs/ComPDFKit-UI.aar
  12. BIN
      example/android/app/libs/ComPDFKit.aar
  13. BIN
      example/android/app/libs/ComPDFKit_Tools-release.aar
  14. BIN
      example/android/app/src/main/assets/User guide.pdf
  15. 0 7
      example/android/build.gradle
  16. 1 0
      example/android/settings.gradle
  17. BIN
      example/assets/right.png
  18. 2 2
      example/ios/CompdfkitPdfExample.xcodeproj/project.pbxproj
  19. 192 0
      example/src/CPDFAnnotationsExample.tsx
  20. 100 61
      example/src/CPDFReaderViewControllerExample.tsx
  21. 167 0
      example/src/CPDFSecurityExample.tsx
  22. 30 3
      example/src/examples.tsx
  23. 260 0
      example/src/screens/CPDFDisplaySettingsScreen.tsx
  24. 126 0
      example/src/screens/CPDFPreviewModeListScreen.tsx
  25. 20 16
      example/src/screens/HomeScreen.tsx
  26. 251 8
      ios/RCTCPDFView.swift
  27. 144 0
      ios/RCTCPDFViewManager.swift
  28. 163 0
      ios/RCTDocumentManager.m
  29. 243 0
      ios/RCTDocumentManager.swift
  30. 70 21
      src/configuration/CPDFOptions.ts
  31. 6 0
      src/index.tsx
  32. 324 0
      src/view/CPDFDocument.tsx
  33. 597 36
      src/view/CPDFReaderView.tsx

+ 1 - 4
android/build.gradle

@@ -78,9 +78,6 @@ repositories {
 
   mavenCentral()
   google()
-  maven {
-    url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
-  }
   mavenLocal()
 }
 
@@ -89,7 +86,7 @@ dependencies {
   compileOnly fileTree(include: ['*.jar','*.aar'], dir: 'libs')
   implementation "com.facebook.react:react-native:+"
 
-  api "com.compdf:compdfkit-tools:2.2.0"
+//  api "com.compdf:compdfkit-ui:2.2.1-SNAPSHOT"
   api 'com.github.bumptech.glide:glide:4.15.1'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
   api 'androidx.documentfile:documentfile:1.0.1'

BIN
android/libs/ComPDFKit-UI.aar


BIN
android/libs/ComPDFKit.aar


BIN
android/libs/ComPDFKit_Tools-release.aar


+ 4 - 5
android/src/main/java/com/compdfkitpdf/reactnative/CompdfkitPdfModule.java

@@ -9,6 +9,10 @@
 
 package com.compdfkitpdf.reactnative;
 
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.ASSETS_SCHEME;
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.CONTENT_SCHEME;
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.FILE_SCHEME;
+
 import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
@@ -42,11 +46,6 @@ public class CompdfkitPdfModule extends ReactContextBaseJavaModule {
 
   public static final String NAME = "ComPDFKit";
 
-  public static final String ASSETS_SCHEME = "file:///android_asset";
-
-  public static final String CONTENT_SCHEME = "content://";
-  public static final String FILE_SCHEME = "file://";
-
   public static final int PICK_PDF_FILE_REQUEST_CODE = 90;
 
   private Promise promise;

+ 341 - 0
android/src/main/java/com/compdfkitpdf/reactnative/modules/CPDFViewModule.java

@@ -18,6 +18,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.uimanager.UIBlock;
 import com.facebook.react.uimanager.UIManagerModule;
 
@@ -58,6 +59,7 @@ public class CPDFViewModule extends ReactContextBaseJavaModule {
     });
   }
 
+  @Deprecated
   @ReactMethod
   public void setMargins(int tag, ReadableArray margins) {
     UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
@@ -129,6 +131,345 @@ public class CPDFViewModule extends ReactContextBaseJavaModule {
     });
   }
 
+  @ReactMethod
+  public void setScale(int tag, float scale){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setScale(tag, scale);
+    });
+  }
+
+  @ReactMethod
+  public void getScale(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getScale(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setCanScale(int tag, boolean canScale){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setCanScale(tag, canScale);
+    });
+  }
+
+  @ReactMethod
+  public void setReadBackgroundColor(int tag, ReadableMap array){
+    uiBlock(nativeViewHierarchyManager -> {
+      String color = array.getString("color");
+      mPDFViewInstance.setReadBackgroundColor(tag, color);
+    });
+  }
+
+  @ReactMethod
+  public void getReadBackgroundColor(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getReadBackgroundColor(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setFormFieldHighlight(int tag, boolean isFormFieldHighlight){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setFormFieldHighlight(tag, isFormFieldHighlight);
+    });
+  }
+
+  @ReactMethod
+  public void isFormFieldHighlight(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isFormFieldHighlight(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setLinkHighlight(int tag, boolean isLinkHighlight){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setLinkHighlight(tag, isLinkHighlight);
+    });
+  }
+
+  @ReactMethod
+  public void isLinkHighlight(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isLinkHighlight(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setVerticalMode(int tag,boolean isVerticalMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setVerticalMode(tag, isVerticalMode);
+    });
+  }
+
+  @ReactMethod
+  public void isVerticalMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isVerticalMode(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setPageSpacing(int tag, int pageSpacing){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setPageSpacing(tag, pageSpacing);
+    });
+  }
+
+  @ReactMethod
+  public void setContinueMode(int tag,boolean isContinueMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setContinueMode(tag, isContinueMode);
+    });
+  }
+
+  @ReactMethod
+  public  void isContinueMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isContinueMode(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setDoublePageMode(int tag,boolean isDoublePageMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setDoublePageMode(tag, isDoublePageMode);
+    });
+  }
+
+  @ReactMethod
+  public  void isDoublePageMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isDoublePageMode(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setCoverPageMode(int tag,boolean coverPageMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setCoverPageMode(tag, coverPageMode);
+    });
+  }
+
+  @ReactMethod
+  public  void isCoverPageMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isCoverPageMode(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setCropMode(int tag,boolean isCropMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setCropMode(tag, isCropMode);
+    });
+  }
+
+  @ReactMethod
+  public  void isCropMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isCropMode(tag));
+    });
+  }
+
+  @ReactMethod
+  public void setPageSameWidth(int tag,boolean isSame){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setPageSameWidth(tag, isSame);
+    });
+  }
+
+  @ReactMethod
+  public void isPageInScreen(int tag, int pageIndex, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isPageInScreen(tag, pageIndex));
+    });
+  }
+
+  @ReactMethod
+  public void setFixedScroll(int tag,boolean isFixedScroll){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setFixedScroll(tag, isFixedScroll);
+    });
+  }
+
+  @ReactMethod
+  public void setPreviewMode(int tag, String previewMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.setPreviewMode(tag, previewMode);
+    });
+  }
+
+  @ReactMethod
+  public void getPreviewMode(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getPreviewMode(tag).alias);
+    });
+  }
+
+  @ReactMethod
+  public void showThumbnailView(int tag, boolean editMode){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.showThumbnailView(tag, editMode);
+    });
+  }
+
+  @ReactMethod
+  public void showBotaView(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.showBotaView(tag);
+    });
+  }
+
+  @ReactMethod
+  public void showAddWatermarkView(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.showAddWatermarkView(tag);
+    });
+  }
+
+  @ReactMethod
+  public void showSecurityView(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.showSecurityView(tag);
+    });
+  }
+
+  @ReactMethod
+  public void showDisplaySettingView(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.showDisplaySettingView(tag);
+    });
+  }
+
+  @ReactMethod
+  public void enterSnipMode(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.enterSnipMode(tag);
+    });
+  }
+
+  @ReactMethod
+  public void exitSnipMode(int tag){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.exitSnipMode(tag);
+    });
+  }
+
+  @ReactMethod
+  public void open(int tag, String filePath, String password, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.open(tag, filePath, password, promise);
+    });
+  }
+
+  @ReactMethod
+  public void getFileName(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getFileName(tag));
+    });
+  }
+
+  @ReactMethod
+  public void isEncrypted(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isEncrypted(tag));
+    });
+  }
+
+  @ReactMethod
+  public void isImageDoc(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.isImageDoc(tag));
+    });
+  }
+
+  @ReactMethod
+  public void getPermissions(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getPermissions(tag).id);
+    });
+  }
+
+  @ReactMethod
+  public void checkOwnerUnlocked(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.checkOwnerUnlocked(tag));
+    });
+  }
+
+  @ReactMethod
+  public void checkOwnerPassword(int tag, String password, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.checkOwnerPassword(tag, password));
+    });
+  }
+
+  @ReactMethod
+  public void getPageCount(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getPageCount(tag));
+    });
+  }
+
+//  @ReactMethod
+//  public void saveAs(int tag,  ReadableMap array, Promise promise){
+//    uiBlock(nativeViewHierarchyManager -> {
+//      String savePath = array.getString("save_path");
+//      boolean removeSecurity = array.getBoolean("remove_security");
+//      boolean fontSubSet = array.getBoolean("font_sub_set");
+//      mPDFViewInstance.saveAs(tag, savePath, removeSecurity, fontSubSet, promise);
+//    });
+//  }
+//
+//  @ReactMethod
+//  public void printDocument(int tag){
+//    uiBlock(nativeViewHierarchyManager -> {
+//      mPDFViewInstance.print(tag);
+//    });
+//  }
+
+  @ReactMethod
+  public void removePassword(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      mPDFViewInstance.removePassword(tag, promise);
+    });
+  }
+
+  @ReactMethod
+  public void setPassword(int tag, ReadableMap array, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      String userPassword = array.getString("user_password");
+      String ownerPassword = array.getString("owner_password");
+      boolean allowsPrinting = array.getBoolean("allows_printing");
+      boolean allowsCopying = array.getBoolean("allows_copying");
+      String encryptAlgo = array.getString("encrypt_algo");
+      mPDFViewInstance.setPassword(tag, userPassword, ownerPassword, allowsPrinting, allowsCopying, encryptAlgo, promise);
+    });
+  }
+
+  @ReactMethod
+  public void getEncryptAlgo(int tag, Promise promise){
+    uiBlock(nativeViewHierarchyManager -> {
+      promise.resolve(mPDFViewInstance.getEncryptAlgo(tag));
+    });
+  }
+
+//  @ReactMethod
+//  public void createWatermark(int tag, ReadableMap array, Promise promise){
+//    uiBlock(nativeViewHierarchyManager -> {
+//
+//    });
+//  }
+//
+//  @ReactMethod
+//  public void removeAllWatermark(int tag,  Promise promise){
+//    uiBlock(nativeViewHierarchyManager -> {
+//
+//    });
+//  }
+
+
   private void uiBlock(UIBlock uiBlock){
     UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
     if (uiManager != null) {

+ 1 - 2
android/src/main/java/com/compdfkitpdf/reactnative/view/CPDFView.java

@@ -113,12 +113,11 @@ public class CPDFView extends FrameLayout {
       View fragmentView = documentFragment.getView();
       addView(fragmentView, ViewGroup.LayoutParams.MATCH_PARENT,
         ViewGroup.LayoutParams.MATCH_PARENT);
-      documentFragment.initDocument(()->{
+      documentFragment.setInitListener((pdfView)->{
         try {
           documentFragment.pdfView.indicatorView.setRNMeasureLayout(true);
         }catch (Exception e){
         }
-
         documentFragment.pdfView.addReaderViewCallback(new CPDFIReaderViewCallback() {
           @Override
           public void onMoveToChild(int pageIndex) {

+ 371 - 11
android/src/main/java/com/compdfkitpdf/reactnative/viewmanager/CPDFViewManager.java

@@ -10,28 +10,41 @@
 package com.compdfkitpdf.reactnative.viewmanager;
 
 
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.ASSETS_SCHEME;
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.CONTENT_SCHEME;
+import static com.compdfkitpdf.reactnative.util.CPDFDocumentUtil.FILE_SCHEME;
+
 import android.app.Activity;
 
+import android.graphics.Color;
 import android.net.Uri;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.fragment.app.FragmentActivity;
 
+import com.compdfkit.core.common.CPDFDocumentException;
 import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.core.document.CPDFDocument.PDFDocumentEncryptAlgo;
+import com.compdfkit.core.document.CPDFDocument.PDFDocumentPermissions;
+import com.compdfkit.core.document.CPDFDocument.PDFDocumentSaveType;
+import com.compdfkit.core.document.CPDFDocumentPermissionInfo;
 import com.compdfkit.tools.common.pdf.CPDFConfigurationUtils;
 import com.compdfkit.tools.common.pdf.config.CPDFConfiguration;
 import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
+import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
+import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl.COnSaveCallback;
 import com.compdfkit.tools.common.views.pdfview.CPDFViewCtrl.COnSaveError;
+import com.compdfkit.tools.common.views.pdfview.CPreviewMode;
 import com.compdfkit.ui.reader.CPDFReaderView;
 import com.compdfkitpdf.reactnative.util.CPDFDocumentUtil;
 import com.compdfkitpdf.reactnative.view.CPDFView;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.uimanager.annotations.ReactProp;
@@ -66,7 +79,7 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
         if (readerView.getPDFDocument() != null) {
           readerView.reloadPages();
         }
-      }catch (Exception e){
+      } catch (Exception e) {
         e.printStackTrace();
       }
     }
@@ -105,13 +118,11 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
 
   @ReactProp(name = "password")
   public void setPassword(CPDFView pdfView, String password) {
-    Log.d(TAG, "CPDFViewManager-setPassword(password: " + password + ")");
     pdfView.setPassword(password);
   }
 
   @ReactProp(name = "configuration")
   public void setConfiguration(CPDFView pdfView, String configurationJson) {
-    Log.d(TAG, "CPDFViewManager-setConfiguration()");
     CPDFConfiguration configuration = CPDFConfigurationUtils.fromJson(configurationJson);
     pdfView.setConfiguration(configuration);
   }
@@ -137,24 +148,24 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
     }
   }
 
-  public boolean removeAllAnnotations(int tag){
+  public boolean removeAllAnnotations(int tag) {
     try {
       CPDFView pdfView = mDocumentViews.get(tag);
       if (pdfView != null) {
         CPDFReaderView readerView = pdfView.documentFragment.pdfView.getCPdfReaderView();
         boolean result = readerView.getPDFDocument().removeAllAnnotations();
-        if (result){
+        if (result) {
           readerView.invalidateAllChildren();
         }
         return result;
       }
       return false;
-    }catch (Exception e){
+    } catch (Exception e) {
       return false;
     }
   }
 
-  public boolean importAnnotations(int tag, String xfdfFilePath) throws Exception{
+  public boolean importAnnotations(int tag, String xfdfFilePath) throws Exception {
     String xfdf = CPDFDocumentUtil.getImportAnnotationPath(reactContext, xfdfFilePath);
     Log.i("ComPDFKitRN", "xfdf:" + xfdf);
     CPDFView pdfView = mDocumentViews.get(tag);
@@ -209,9 +220,358 @@ public class CPDFViewManager extends ViewGroupManager<CPDFView> {
     return pdfView.getCPDFReaderView().getPageNum();
   }
 
-  public boolean hasChange(int tag){
+  public boolean hasChange(int tag) {
     CPDFView pdfView = mDocumentViews.get(tag);
     return pdfView.getCPDFReaderView().getPDFDocument().hasChanges();
   }
 
+  public void setScale(int tag, float scale) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setScale(scale);
+  }
+
+  public float getScale(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getScale();
+  }
+
+  public void setCanScale(int tag, boolean canScale) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setCanScale(canScale);
+  }
+
+  public void setReadBackgroundColor(int tag, String color) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setReadBackgroundColor(Color.parseColor(color));
+    pdfView.getCPDFReaderView().setBackgroundColor(
+      CViewUtils.getColor(Color.parseColor(color), 190));
+  }
+
+  public String getReadBackgroundColor(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    String readBgColor =
+      "#" + Integer.toHexString(pdfView.getCPDFReaderView().getReadBackgroundColor()).toUpperCase();
+    return readBgColor;
+  }
+
+  public void setFormFieldHighlight(int tag, boolean isFormFieldHighlight) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setFormFieldHighlight(isFormFieldHighlight);
+  }
+
+  public boolean isFormFieldHighlight(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isFormFieldHighlight();
+  }
+
+  public void setLinkHighlight(int tag, boolean isLinkHighlight) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setLinkHighlight(isLinkHighlight);
+  }
+
+  public boolean isLinkHighlight(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isLinkHighlight();
+  }
+
+  public void setVerticalMode(int tag, boolean isVerticalMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setVerticalMode(isVerticalMode);
+  }
+
+  public boolean isVerticalMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isVerticalMode();
+  }
+
+  public void setPageSpacing(int tag, int spacing) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setPageSpacing(spacing);
+    pdfView.getCPDFReaderView().reloadPages();
+  }
+
+  public void setContinueMode(int tag, boolean isContinueMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setContinueMode(isContinueMode);
+  }
+
+  public boolean isContinueMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isContinueMode();
+  }
+
+  public void setDoublePageMode(int tag, boolean isDoublePageMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setDoublePageMode(isDoublePageMode);
+    pdfView.getCPDFReaderView().setCoverPageMode(false);
+  }
+
+  public boolean isDoublePageMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isDoublePageMode();
+  }
+
+  public void setCoverPageMode(int tag, boolean isCoverPageMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setDoublePageMode(isCoverPageMode);
+    pdfView.getCPDFReaderView().setCoverPageMode(isCoverPageMode);
+  }
+
+  public boolean isCoverPageMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isCoverPageMode();
+  }
+
+  public void setCropMode(int tag, boolean isCropMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setCropMode(isCropMode);
+  }
+
+  public boolean isCropMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isCropMode();
+  }
+
+  public void setPageSameWidth(int tag, boolean isPageSameWidth) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setPageSameWidth(isPageSameWidth);
+    pdfView.getCPDFReaderView().reloadPages();
+  }
+
+  public boolean isPageInScreen(int tag, int pageIndex) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().isPageInScreen(pageIndex);
+  }
+
+  public void setFixedScroll(int tag, boolean isFixedScroll) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.getCPDFReaderView().setFixedScroll(isFixedScroll);
+  }
+
+  public void setPreviewMode(int tag, String previewMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.setPreviewMode(CPreviewMode.fromAlias(previewMode));
+  }
+
+  public CPreviewMode getPreviewMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.documentFragment.pdfToolBar.getMode();
+  }
+
+  public void showThumbnailView(int tag, boolean editMode) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.showPageEdit(editMode);
+  }
+
+  public void showBotaView(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.showBOTA();
+  }
+
+  public void showAddWatermarkView(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.showAddWatermarkDialog();
+  }
+
+  public void showSecurityView(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.showSecurityDialog();
+  }
+
+  public void showDisplaySettingView(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.showDisplaySettings(pdfView.documentFragment.pdfView);
+  }
+
+  public void enterSnipMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.enterSnipMode();
+  }
+
+  public void exitSnipMode(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    pdfView.documentFragment.exitSnipMode();
+  }
+
+  public void open(int tag, String filePath, String password, Promise promise) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    CPDFViewCtrl viewCtrl = pdfView.documentFragment.pdfView;
+    if (filePath.startsWith(ASSETS_SCHEME)) {
+      String assetsPath = filePath.replace(ASSETS_SCHEME + "/","");
+      String[] strs = filePath.split("/");
+      String fileName = strs[strs.length -1];
+      String samplePDFPath = CFileUtils.getAssetsTempFile(reactContext, assetsPath, fileName);
+      viewCtrl.openPDF(samplePDFPath, password, () -> {
+        promise.resolve(true);
+      });
+    } else if (filePath.startsWith(CONTENT_SCHEME) || filePath.startsWith(FILE_SCHEME)) {
+      Uri uri = Uri.parse(filePath);
+      viewCtrl.openPDF(uri, password, () -> {
+        promise.resolve(true);
+      });
+    } else {
+      viewCtrl.openPDF(filePath, password, () -> {
+        promise.resolve(true);
+      });
+    }
+  }
+
+  public String getFileName(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().getFileName();
+  }
+
+  public boolean isEncrypted(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().isEncrypted();
+  }
+
+  public boolean isImageDoc(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().isImageDoc();
+  }
+
+  public PDFDocumentPermissions getPermissions(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().getPermissions();
+  }
+
+  public boolean checkOwnerUnlocked(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().checkOwnerUnlocked();
+  }
+
+  public boolean checkOwnerPassword(int tag, String password) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().checkOwnerPassword(password);
+  }
+
+  public int getPageCount(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    return pdfView.getCPDFReaderView().getPDFDocument().getPageCount();
+  }
+
+  public void saveAs(int tag, String savePath, boolean removeSecurity, boolean fontSubSet,
+    Promise result) {
+    CThreadPoolUtils.getInstance().executeIO(() -> {
+      try {
+        CPDFView pdfView = mDocumentViews.get(tag);
+        CPDFDocument document = pdfView.getCPDFReaderView().getPDFDocument();
+        boolean saveResult;
+        if (savePath.startsWith(CONTENT_SCHEME)) {
+          saveResult = document.saveAs(Uri.parse(savePath), removeSecurity, fontSubSet);
+        } else {
+          saveResult = document.saveAs(savePath, removeSecurity, false, fontSubSet);
+        }
+        if (document.shouleReloadDocument()) {
+          document.reload();
+        }
+        result.resolve(saveResult);
+      } catch (CPDFDocumentException e) {
+        e.printStackTrace();
+        result.reject("SAVE_FAIL",
+          "The current saved directory is: " + savePath
+            + ", please make sure you have write permission to this directory");
+      }
+    });
+  }
+
+  public void print(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    CPDFReaderView readerView = pdfView.getCPDFReaderView();
+    String path = readerView.getPDFDocument().getAbsolutePath();
+    Uri uri = readerView.getPDFDocument().getUri();
+    CFileUtils.startPrint(reactContext, path, uri);
+  }
+
+  public void removePassword(int tag, Promise promise) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    CPDFReaderView readerView = pdfView.getCPDFReaderView();
+    try {
+      CPDFDocument document = readerView.getPDFDocument();
+      boolean saveResult = document.save(PDFDocumentSaveType.PDFDocumentSaveRemoveSecurity,
+        true);
+      if (document.shouleReloadDocument()) {
+        document.reload();
+      }
+      promise.resolve(saveResult);
+    } catch (Exception e) {
+      promise.reject("SAVE_FAIL",
+        "An exception occurs when remove document opening password and saving it.,"
+          + e.getMessage());
+    }
+  }
+
+  public void setPassword(int tag,
+    String userPassword,
+    String ownerPassword,
+    boolean allowsPrinting,
+    boolean allowsCopying,
+    String encryptAlgo,
+    Promise promise) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    CPDFDocument document = pdfView.getCPDFReaderView().getPDFDocument();
+    ;
+    CThreadPoolUtils.getInstance().executeIO(() -> {
+      try {
+        if (!TextUtils.isEmpty(userPassword)) {
+          document.setUserPassword(userPassword);
+        }
+        if (!TextUtils.isEmpty(ownerPassword)) {
+          document.setOwnerPassword(ownerPassword);
+          CPDFDocumentPermissionInfo permissionInfo = document.getPermissionsInfo();
+          permissionInfo.setAllowsPrinting(allowsPrinting);
+          permissionInfo.setAllowsCopying(allowsCopying);
+          document.setPermissionsInfo(permissionInfo);
+        }
+
+        switch (encryptAlgo) {
+          case "rc4":
+            document.setEncryptAlgorithm(PDFDocumentEncryptAlgo.PDFDocumentRC4);
+            break;
+          case "aes128":
+            document.setEncryptAlgorithm(PDFDocumentEncryptAlgo.PDFDocumentAES128);
+            break;
+          case "aes256":
+            document.setEncryptAlgorithm(PDFDocumentEncryptAlgo.PDFDocumentAES256);
+            break;
+          case "noEncryptAlgo":
+            document.setEncryptAlgorithm(PDFDocumentEncryptAlgo.PDFDocumentNoEncryptAlgo);
+            break;
+          default:
+            break;
+        }
+
+        boolean saveResult = document.save(
+          CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveIncremental, true);
+
+        if (document.shouleReloadDocument()) {
+          if (!TextUtils.isEmpty(userPassword)) {
+            document.reload(userPassword);
+          } else if (!TextUtils.isEmpty(ownerPassword)) {
+            document.reload(ownerPassword);
+          } else {
+            document.reload();
+          }
+        }
+        promise.resolve(saveResult);
+      } catch (Exception e) {
+        promise.reject("SAVE_FAIL",
+          "An exception occurs when setting a document opening password and saving it.,"
+            + e.getMessage());
+      }
+    });
+  }
+
+  public String getEncryptAlgo(int tag) {
+    CPDFView pdfView = mDocumentViews.get(tag);
+    PDFDocumentEncryptAlgo encryptAlgo = pdfView.getCPDFReaderView().getPDFDocument()
+      .getEncryptAlgorithm();
+    return switch (encryptAlgo) {
+      case PDFDocumentRC4 -> "rc4";
+      case PDFDocumentAES128 -> "aes128";
+      case PDFDocumentAES256 -> "aes256";
+      case PDFDocumentNoEncryptAlgo -> "noEncryptAlgo";
+    };
+  }
 }

File diff suppressed because it is too large
+ 17 - 1
example/App.tsx


+ 0 - 1
example/android/app/build.gradle

@@ -123,7 +123,6 @@ android {
 
 dependencies {
   implementation fileTree(include: ['*.jar','*.aar'], dir: 'libs')
-  api "com.compdf:compdfkit:2.2.0-SNAPSHOT"
 
     // The version of react-native is set by the React Native Gradle Plugin
     implementation("com.facebook.react:react-android")

BIN
example/android/app/libs/ComPDFKit-UI.aar


BIN
example/android/app/libs/ComPDFKit.aar


BIN
example/android/app/libs/ComPDFKit_Tools-release.aar


BIN
example/android/app/src/main/assets/User guide.pdf


+ 0 - 7
example/android/build.gradle

@@ -10,9 +10,6 @@ buildscript {
   repositories {
     google()
     mavenCentral()
-    maven {
-      url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
-    }
     mavenLocal()
 
   }
@@ -27,11 +24,7 @@ allprojects {
   repositories {
     google()
     mavenCentral()
-    maven {
-      url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
-    }
     mavenLocal()
-
   }
 }
 

+ 1 - 0
example/android/settings.gradle

@@ -3,3 +3,4 @@ apply from: file("../node_modules/@react-native-community/cli-platform-android/n
 include ':app'
 includeBuild('../node_modules/@react-native/gradle-plugin')
 
+

BIN
example/assets/right.png


+ 2 - 2
example/ios/CompdfkitPdfExample.xcodeproj/project.pbxproj

@@ -491,7 +491,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CURRENT_PROJECT_VERSION = 1;
-				DEVELOPMENT_TEAM = 4GGQPGRTSV;
+				DEVELOPMENT_TEAM = 59AC9PMNH2;
 				ENABLE_BITCODE = NO;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				INFOPLIST_FILE = CompdfkitPdfExample/Info.plist;
@@ -526,7 +526,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CURRENT_PROJECT_VERSION = 1;
-				DEVELOPMENT_TEAM = 4GGQPGRTSV;
+				DEVELOPMENT_TEAM = 59AC9PMNH2;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				INFOPLIST_FILE = CompdfkitPdfExample/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.4;

+ 192 - 0
example/src/CPDFAnnotationsExample.tsx

@@ -0,0 +1,192 @@
+/**
+ * Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+import React, { useState, useEffect, useRef } from 'react';
+import { Image, Platform, StyleSheet, Text, View } from 'react-native';
+import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFThemes } from '@compdfkit_pdf_sdk/react_native';
+import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
+import { HeaderBackButton } from '@react-navigation/elements';
+import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import DocumentPicker from 'react-native-document-picker';
+
+type RootStackParamList = {
+    CPDFReaderViewExample: { document?: string };
+};
+
+type CPDFReaderViewExampleScreenRouteProp = RouteProp<
+    RootStackParamList,
+    'CPDFReaderViewExample'
+>;
+
+const CPDFAnnotationsExampleScreen = () => {
+
+    const pdfReaderRef = useRef<CPDFReaderView>(null);
+
+    const navigation = useNavigation();
+
+    const route = useRoute<CPDFReaderViewExampleScreenRouteProp>();
+
+    const [samplePDF] = useState(
+        route.params?.document || (Platform.OS === 'android'
+            ? 'file:///android_asset/PDF_Document.pdf'
+            : 'PDF_Document.pdf')
+    );
+
+    const handleSave = async () => {
+        if (pdfReaderRef.current) {
+            const success = await pdfReaderRef.current.save();
+            if (success) {
+                console.log('ComPDFKitRN save() : Document saved successfully');
+            } else {
+                console.log('ComPDFKitRN save() : Failed to save document');
+            }
+        }
+    };
+
+    const menuOptions = [
+        'Save',
+        'Remove All Annotations',
+        'Import Annotations 1',
+        'Import Annotations 2',
+        'Export Annotations'];
+
+    const handleMenuItemPress = async (action: string) => {
+        switch (action) {
+            case 'Save':
+                handleSave();
+                break;
+            case 'Remove All Annotations':
+                const removeResult = await pdfReaderRef.current?._pdfDocument.removeAllAnnotations();
+                console.log('ComPDFKitRN removeAllAnnotations:', removeResult);
+                break;
+            case 'Import Annotations 1':
+                try {
+                    // Select an xfdf file from the public directory and import it into the current document
+                    const pickerResult = DocumentPicker.pick({
+                        type: [DocumentPicker.types.allFiles],
+                        copyTo: 'cachesDirectory'
+                    });
+                    pickerResult.then(async (res) => {
+                        const file = res[0];
+                    
+                        console.log('fileUri:', file?.uri);
+                        console.log('fileCopyUri:', file?.fileCopyUri);
+                        console.log('fileType:', file?.type);
+                        const path = file!!.fileCopyUri!!
+                        if (!path?.endsWith('xml') && !path?.endsWith('xfdf')) {
+                            console.log('ComPDFKitRN please select xfdf format file');
+                            return;
+                        }
+
+                        const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(path);
+                        console.log('ComPDFKitRN importAnnotations:', importResult);
+                    })
+                } catch (err) {
+                }
+                break;
+            case 'Import Annotations 2':
+                    // Android
+                    // import xfdf file from android assets directory
+                    const testXfdf = Platform.OS === 'android'
+                        ? 'file:///android_asset/test.xfdf'
+                        : 'test.xfdf'
+                    // import xfdf file from file path
+                    // const testXfdf = '/data/user/0/com.compdfkit.reactnative.example/xxx/xxx.xfdf';
+
+                    const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(testXfdf);
+                    console.log('ComPDFKitRN importAnnotations:', importResult);
+                break;
+            case 'Export Annotations':
+                const exportXfdfFilePath = await pdfReaderRef.current?._pdfDocument.exportAnnotations();
+                console.log('ComPDFKitRN exportAnnotations:', exportXfdfFilePath);
+                break;
+            default:
+                break;
+        }
+    };
+
+    const handleBack = () => {
+        navigation.goBack();
+    };
+
+    const renderToolbar = () => {
+        return (
+            <View style={styles.toolbar}>
+                <HeaderBackButton onPress={handleBack} />
+                <Text style={styles.toolbarTitle}>Annotations Example</Text>
+
+                <Menu>
+                    <MenuTrigger>
+                        <Image source={require('../assets/more.png')} style={{ width: 24, height: 24, marginEnd: 8 }} />
+                    </MenuTrigger>
+
+                    <MenuOptions>
+                        {menuOptions.map((option, index) => (
+                            <MenuOption key={index} onSelect={() => handleMenuItemPress(option)}>
+                                <Text style={styles.menuOption}>{option}</Text>
+                            </MenuOption>
+                        ))}
+                    </MenuOptions>
+                </Menu>
+            </View>
+        );
+    };
+
+    return (
+        <MenuProvider>
+            <SafeAreaView style={{ flex: 1 }}>
+                <View style={{ flex: 1 }}>
+                    {renderToolbar()}
+                    <CPDFReaderView
+                        ref={pdfReaderRef}
+                        document={samplePDF}
+                        configuration={ComPDFKit.getDefaultConfig({
+                            toolbarConfig: {
+                                iosLeftBarAvailableActions: [
+                                    CPDFToolbarAction.THUMBNAIL
+                                ]
+                            }
+                        })} />
+                </View>
+            </SafeAreaView>
+        </MenuProvider>
+    );
+};
+
+const styles = StyleSheet.create({
+    toolbar: {
+        height: 56,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'flex-start',
+        backgroundColor: '#FAFCFF',
+        paddingHorizontal: 4,
+    },
+    toolbarButton: {
+        padding: 8,
+    },
+    toolbarTitle: {
+        flex: 1,
+        color: 'black',
+        fontSize: 16,
+        fontWeight: 'bold',
+        marginStart: 8
+    },
+    menuOption: {
+        padding: 8,
+        fontSize: 14,
+        color: 'black',
+    },
+});
+
+export default CPDFAnnotationsExampleScreen;
+
+
+

+ 100 - 61
example/src/CPDFReaderViewControllerExample.tsx

@@ -8,13 +8,15 @@
  */
 
 import React, { useState, useEffect, useRef } from 'react';
-import { Image, Platform, StyleSheet, Text, View } from 'react-native';
-import { CPDFReaderView, ComPDFKit, CPDFToolbarAction } from '@compdfkit_pdf_sdk/react_native';
+import { Image, Platform, StyleSheet, Text, View, Modal, TouchableWithoutFeedback, ScrollView} from 'react-native';
+import PDFReaderContext, { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFThemes } from '@compdfkit_pdf_sdk/react_native';
 import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
 import { HeaderBackButton } from '@react-navigation/elements';
 import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
 import { SafeAreaView } from 'react-native-safe-area-context';
-import DocumentPicker from 'react-native-document-picker';
+import CPDFReaderViewExampleScreen from './CPDFReaderViewExample';
+import { CPDFDisplaySettingsScreen } from './screens/CPDFDisplaySettingsScreen';
+import { CPDFPreviewModeListScreen } from './screens/CPDFPreviewModeListScreen';
 
 type RootStackParamList = {
     CPDFReaderViewExample: { document?: string };
@@ -27,7 +29,12 @@ type CPDFReaderViewExampleScreenRouteProp = RouteProp<
 
 const CPDFReaderViewControllerExampleScreen = () => {
 
-    const pdfReaderRef = useRef<CPDFReaderView>(null);
+
+    const [displaySettingModalVisible, setDisplaySettingModalVisible] = useState(false);
+
+    const [previewModeModalVisible, setPreviewModeModalVisible] = useState(false);
+
+    const pdfReaderRef = useRef<CPDFReaderView | null>(null);
 
     const navigation = useNavigation();
 
@@ -66,25 +73,70 @@ const CPDFReaderViewControllerExampleScreen = () => {
     };
 
     const menuOptions = [
+        'openDocument',
         'save',
         'hasChange',
+        'DisplaySettings',
+        'PreviewModeScreen',
+        'showThumbnailView',
+        'showBotaView',
+        'showAddWatermarkView',
+        'showSecurityView',
+        'showDisplaySettingView',
+        'enterSnipMode',
+        'exitSnipMode',
         'setDisplayPageIndex',
         'getCurrentPageIndex',
-        'removeAllAnnotations',
-        'importAnnotations',
-        'exportAnnotations',
         'setMargins',
-        'removeSignFileList']
+        'removeSignFileList',
+        'setScale',
+        'setPageSpacing',
+        'setPageSameWidth',
+        'isPageInScreen',
+        'setFixedScroll'];
 
     const handleMenuItemPress = async (action: string) => {
         switch (action) {
+            case 'openDocument':
+                // const pdfFile = await ComPDFKit.pickFile();
+                // if(pdfFile){
+                    await pdfReaderRef.current?._pdfDocument.open('file:///android_asset/User guide.pdf');
+                // }
+                break;
             case 'save':
                 handleSave();
                 break;
             case 'hasChange':
-                const hasChange = await pdfReaderRef.current?.hasChange();
+                const hasChange = await pdfReaderRef.current?._pdfDocument.hasChange();
                 console.log('ComPDFKitRN hasChange:', hasChange);
                 break;
+            case 'DisplaySettings':
+                setDisplaySettingModalVisible(true);
+                break;
+            case 'PreviewModeScreen':
+                setPreviewModeModalVisible(true);
+                break;
+            case 'showThumbnailView':
+                await pdfReaderRef.current?.showThumbnailView(false);
+                break;
+            case 'showBotaView':
+                await pdfReaderRef.current?.showBotaView();    
+                break;
+            case 'showAddWatermarkView':
+                await pdfReaderRef.current?.showAddWatermarkView();    
+                break;
+            case 'showSecurityView':
+                await pdfReaderRef.current?.showSecurityView();    
+                break;    
+            case 'showDisplaySettingView':
+                await pdfReaderRef.current?.showDisplaySettingView();    
+                break;
+            case 'enterSnipMode':
+                await pdfReaderRef.current?.enterSnipMode();    
+                break;
+            case 'exitSnipMode':
+                await pdfReaderRef.current?.exitSnipMode();    
+                break;
             case 'setDisplayPageIndex':
                 await pdfReaderRef.current?.setDisplayPageIndex(1);
                 break;
@@ -92,59 +144,30 @@ const CPDFReaderViewControllerExampleScreen = () => {
                 const pageIndex = await pdfReaderRef.current?.getCurrentPageIndex();
                 console.log('ComPDFKitRN currentPageIndex:', pageIndex);
                 break;
-            case 'removeAllAnnotations':
-                const removeResult = await pdfReaderRef.current?.removeAllAnnotations();
-                console.log('ComPDFKitRN removeAllAnnotations:', removeResult);
-                break;
-            case 'importAnnotations':
-                try {
-
-                    // Android
-                    // import xfdf file from android assets directory
-                    // const testXfdf = Platform.OS === 'android'
-                    //     ? 'file:///android_asset/test.xfdf'
-                    //     : 'test.xfdf'
-                    // import xfdf file from file path
-                    // const testXfdf = '/data/user/0/com.compdfkit.reactnative.example/xxx/xxx.xfdf';
-
-                    // const importResult = await pdfReaderRef.current?.importAnnotations(testXfdf);
-                    // console.log('ComPDFKitRN importAnnotations:', importResult);
-
-
-                    // Select an xfdf file from the public directory and import it into the current document
-                    const pickerResult = DocumentPicker.pick({
-                        type: [DocumentPicker.types.allFiles],
-                        copyTo: 'cachesDirectory'
-                    });
-                    pickerResult.then(async (res) => {
-                        const file = res[0];
-                        const fileName = file?.name;
-                    
-                        console.log('fileUri:', file?.uri);
-                        console.log('fileCopyUri:', file?.fileCopyUri);
-                        console.log('fileType:', file?.type);
-                        const path = file!!.fileCopyUri!!
-                        if (!path?.endsWith('xml') && !path?.endsWith('xfdf')) {
-                            console.log('ComPDFKitRN please select xfdf format file');
-                            return;
-                        }
-
-                        const importResult = await pdfReaderRef.current?.importAnnotations(path);
-                        console.log('ComPDFKitRN importAnnotations:', importResult);
-                    })
-                } catch (err) {
-                }
-                break;
-            case 'exportAnnotations':
-                const exportXfdfFilePath = await pdfReaderRef.current?.exportAnnotations();
-                console.log('ComPDFKitRN exportAnnotations:', exportXfdfFilePath);
-                break;
             case 'setMargins':
                 await pdfReaderRef.current?.setMargins(10, 20, 10, 20)
                 break;
             case 'removeSignFileList':
                 await ComPDFKit.removeSignFileList();
                 break;
+            case 'setScale':
+                await pdfReaderRef.current?.setScale(2.3);
+                var scale = await pdfReaderRef.current?.getScale();
+                console.log('ComPDFKitRN getScale:', scale);
+                break; 
+            case 'setPageSpacing':
+                await pdfReaderRef.current?.setPageSpacing(50);
+                break;
+            case 'setPageSameWidth':
+                await pdfReaderRef.current?.setPageSameWidth(true);
+                break;
+            case 'isPageInScreen':
+                const inScreen = await pdfReaderRef.current?.isPageInScreen(1);
+                console.log('ComPDFKit-RN inScreen:', inScreen);
+                break;
+            case 'setFixedScroll':
+                await pdfReaderRef.current?.setFixedScroll(false);
+                break;
             default:
                 break;
         }
@@ -155,18 +178,19 @@ const CPDFReaderViewControllerExampleScreen = () => {
             <View style={styles.toolbar}>
                 <HeaderBackButton onPress={handleBack} />
                 <Text style={styles.toolbarTitle}>Controller Example</Text>
-
                 <Menu>
                     <MenuTrigger>
                         <Image source={require('../assets/more.png')} style={{ width: 24, height: 24, marginEnd: 8 }} />
                     </MenuTrigger>
 
-                    <MenuOptions>
+                    <MenuOptions customStyles={{ optionsWrapper: styles.menuOptionsWrapper }}>
+                        <ScrollView>
                         {menuOptions.map((option, index) => (
                             <MenuOption key={index} onSelect={() => handleMenuItemPress(option)}>
                                 <Text style={styles.menuOption}>{option}</Text>
                             </MenuOption>
                         ))}
+                        </ScrollView>
                     </MenuOptions>
                 </Menu>
             </View>
@@ -181,8 +205,8 @@ const CPDFReaderViewControllerExampleScreen = () => {
         console.log('ComPDFKitRN saveDocument');
     }
 
-
     return (
+        <PDFReaderContext.Provider value={pdfReaderRef.current}>
         <MenuProvider>
             <SafeAreaView style={{ flex: 1 }}>
                 <View style={{ flex: 1 }}>
@@ -197,11 +221,23 @@ const CPDFReaderViewControllerExampleScreen = () => {
                                 iosLeftBarAvailableActions: [
                                     CPDFToolbarAction.THUMBNAIL
                                 ]
+                            },
+                            readerViewConfig:{
+                                formFieldHighlight:false
                             }
                         })} />
+                    <CPDFDisplaySettingsScreen
+                        visible={displaySettingModalVisible}
+                        onClose={() => setDisplaySettingModalVisible(false)}
+                    />
+                    <CPDFPreviewModeListScreen
+                        visible={previewModeModalVisible}
+                        onClose={() => setPreviewModeModalVisible(false)}
+                    />
                 </View>
             </SafeAreaView>
         </MenuProvider>
+        </PDFReaderContext.Provider>
     );
 };
 
@@ -225,10 +261,13 @@ const styles = StyleSheet.create({
         marginStart: 8
     },
     menuOption: {
-        padding: 10,
-        fontSize: 16,
+        padding: 8,
+        fontSize: 14,
         color: 'black',
     },
+    menuOptionsWrapper: {
+        maxHeight: 500, 
+    },
 });
 
 export default CPDFReaderViewControllerExampleScreen;

+ 167 - 0
example/src/CPDFSecurityExample.tsx

@@ -0,0 +1,167 @@
+/**
+ * Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ */
+
+import React, { useState, useEffect, useRef } from 'react';
+import { Image, Platform, StyleSheet, Text, View } from 'react-native';
+import { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFThemes } from '@compdfkit_pdf_sdk/react_native';
+import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
+import { HeaderBackButton } from '@react-navigation/elements';
+import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import DocumentPicker from 'react-native-document-picker';
+import { CPDFDocumentEncryptAlgo } from '../../src/configuration/CPDFOptions';
+
+type RootStackParamList = {
+    CPDFReaderViewExample: { document?: string };
+};
+
+type CPDFSecurityExampleRouteProp = RouteProp<
+    RootStackParamList,
+    'CPDFReaderViewExample'
+>;
+
+const CPDFSecurityExampleScreen = () => {
+
+    const pdfReaderRef = useRef<CPDFReaderView>(null);
+
+    const navigation = useNavigation();
+
+    const route = useRoute<CPDFSecurityExampleRouteProp>();
+
+    const [samplePDF] = useState(
+        route.params?.document || (Platform.OS === 'android'
+            ? 'file:///android_asset/PDF_Document.pdf'
+            : 'PDF_Document.pdf')
+    );
+
+    const handleSave = async () => {
+        if (pdfReaderRef.current) {
+            const success = await pdfReaderRef.current.save();
+            if (success) {
+                console.log('ComPDFKitRN save() : Document saved successfully');
+            } else {
+                console.log('ComPDFKitRN save() : Failed to save document');
+            }
+        }
+    };
+
+    const menuOptions = [
+        'Set Password',
+        'Remove Password',
+        'Check Owner Password',
+        'Document Info'];
+
+    const handleMenuItemPress = async (action: string) => {
+        switch (action) {
+            case 'Set Password':
+                var document = pdfReaderRef.current?._pdfDocument;
+                const result = await document?.setPassword('1234', '4321', false,false, CPDFDocumentEncryptAlgo.AES128);
+                console.log('ComPDFKit-RN setPassword:', result);
+                break;
+            case 'Remove Password':
+                var document = pdfReaderRef.current?._pdfDocument;
+                const removeResult = await document?.removePassword();
+                console.log('ComPDFKit-RN removePassword:', removeResult);
+                break;
+            case 'Check Owner Password':
+                var document = pdfReaderRef.current?._pdfDocument;
+                console.log('ComPDFKit-RN checkOwnerPassword:', await document?.checkOwnerPassword('4321'));
+                break;
+            case 'Document Info':
+                var document = pdfReaderRef.current?._pdfDocument;
+                console.log('ComPDFKit-RN fileName:', await document?.getFileName());
+                console.log('ComPDFKit-RN pageCount:', await document?.getPageCount());
+                console.log('ComPDFKit-RN isEncrypted:', await document?.isEncrypted());
+                console.log('ComPDFKit-RN isImageDoc:', await document?.isImageDoc());
+                console.log('ComPDFKit-RN permissions:', await document?.getPermissions());
+                console.log('ComPDFKit-RN getEncryptAlgo:', await document?.getEncryptAlgo());
+                console.log('ComPDFKit-RN checkOwnerUnlocked:', await document?.checkOwnerUnlocked());
+                break;
+            default:
+                break;
+        }
+    };
+
+    const handleBack = () => {
+        navigation.goBack();
+    };
+
+    const renderToolbar = () => {
+        return (
+            <View style={styles.toolbar}>
+                <HeaderBackButton onPress={handleBack} />
+                <Text style={styles.toolbarTitle}>Security Example</Text>
+                <Menu>
+                    <MenuTrigger>
+                        <Image source={require('../assets/more.png')} style={{ width: 24, height: 24, marginEnd: 8 }} />
+                    </MenuTrigger>
+
+                    <MenuOptions>
+                        {menuOptions.map((option, index) => (
+                            <MenuOption key={index} onSelect={() => handleMenuItemPress(option)}>
+                                <Text style={styles.menuOption}>{option}</Text>
+                            </MenuOption>
+                        ))}
+                    </MenuOptions>
+                </Menu>
+            </View>
+        );
+    };
+
+    return (
+        <MenuProvider>
+            <SafeAreaView style={{ flex: 1 }}>
+                <View style={{ flex: 1 }}>
+                    {renderToolbar()}
+                    <CPDFReaderView
+                        ref={pdfReaderRef}
+                        document={samplePDF}
+                        configuration={ComPDFKit.getDefaultConfig({
+                            toolbarConfig: {
+                                iosLeftBarAvailableActions: [
+                                    CPDFToolbarAction.THUMBNAIL
+                                ]
+                            }
+                        })} />
+                </View>
+            </SafeAreaView>
+        </MenuProvider>
+    );
+};
+
+const styles = StyleSheet.create({
+    toolbar: {
+        height: 56,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'flex-start',
+        backgroundColor: '#FAFCFF',
+        paddingHorizontal: 4,
+    },
+    toolbarButton: {
+        padding: 8,
+    },
+    toolbarTitle: {
+        flex: 1,
+        color: 'black',
+        fontSize: 16,
+        fontWeight: 'bold',
+        marginStart: 8
+    },
+    menuOption: {
+        padding: 8,
+        fontSize: 14,
+        color: 'black',
+    },
+});
+
+export default CPDFSecurityExampleScreen;
+
+
+

+ 30 - 3
example/src/examples.tsx

@@ -10,7 +10,7 @@
 import { Platform } from 'react-native';
 import { ComPDFKit } from '@compdfkit_pdf_sdk/react_native';
 
-const examples = [
+const modalViewExamples = [
     {
         key: 'item1',
         title: 'Basic Example',
@@ -38,7 +38,11 @@ const examples = [
             } catch (err) {
             }
         }
-    },
+    }
+];
+
+
+const uiConpomentExamples = [
     {
         key: 'item3',
         title: 'CPDFReaderView Example',
@@ -72,5 +76,28 @@ const examples = [
             component.props.navigation.navigate('CPDFReaderViewControllerExample');
         }
     },
+    {
+        key: 'item6',
+        title: 'Annotations Example',
+        description: 'Demonstrate how to implement annotation functionality using the CPDFReaderView UI component, including adding, editing, and deleting annotations.',
+        action: (component: any)  => {
+            component.props.navigation.navigate('CPDFAnnotationsExample');
+        }
+    },
+    {
+        key: 'item7',
+        title: 'Security Example',
+        description: 'This example shows how to set passwords, watermarks, etc.',
+        action: (component: any)  => {
+            component.props.navigation.navigate('CPDFSecurityExample');
+        }
+    },
+];
+
+export const examples = [
+    { key: 'header1', type: 'header', title: 'CPDFReaderView Examples' },
+    ...uiConpomentExamples.map(item => ({ ...item, type: 'uiComponent' })),
+
+    { key: 'header2', type: 'header', title: 'Modal View Examples' },
+    ...modalViewExamples.map(item => ({ ...item, type: 'modalView' }))
 ];
-export default examples;

+ 260 - 0
example/src/screens/CPDFDisplaySettingsScreen.tsx

@@ -0,0 +1,260 @@
+import PDFReaderContext, { CPDFDisplayMode, CPDFThemes } from "@compdfkit_pdf_sdk/react_native";
+import { useContext, useEffect, useState } from "react";
+import { Image, Modal, ScrollView, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+import { CPDFReaderView } from "../../../lib/typescript/src";
+
+
+
+interface CPDFDisplaySettingsScreenProps {
+    visible: boolean;
+    onClose: () => void;
+}
+
+export const CPDFDisplaySettingsScreen: React.FC<CPDFDisplaySettingsScreenProps> = ({ visible, onClose }) => {
+
+    
+    const [isVertical, setIsVertical] = useState(false);
+
+    const [displayMode, setDisplayMode] = useState(CPDFDisplayMode.SINGLE_PAGE);
+
+    const [isFormFieldHighlight, setIsFormFieldHighlight] = useState(false);
+
+    const [isLinkHighlight, setIsLinkHighlight] = useState(false);
+
+    const [isContinuousScrolling, setIsContinuousScrolling] = useState(false);
+
+    const [isCrop, setIsCrop] = useState(false);
+
+    const [themes, setThemes] = useState(CPDFThemes.LIGHT);
+
+    const [isCanScale, setCanScale] = useState(true);
+
+    const pdfReader = useContext(PDFReaderContext) as CPDFReaderView | null;
+
+    useEffect(() => {
+        const checkSettings = async () => {
+            if(pdfReader){
+                const isVertical = await pdfReader.isVerticalMode();
+                console.log('isVertical', isVertical);
+                setIsVertical(isVertical);
+                const isDoublePageMode = await pdfReader.isDoublePageMode();
+                const isCoverPageMode = await pdfReader.isCoverPageMode();
+                
+                if(!isDoublePageMode){
+                    setDisplayMode(CPDFDisplayMode.SINGLE_PAGE);
+                } else {
+                    setDisplayMode(isCoverPageMode ? CPDFDisplayMode.COVER_PAGE : CPDFDisplayMode.DOUBLE_PAGE);
+                }
+                const formFieldHighlight = await pdfReader?.isFormFieldHighlight();
+                console.log('formFieldHighlight', formFieldHighlight);
+                setIsFormFieldHighlight(formFieldHighlight);
+                const isLinkHighlight = await pdfReader?.isLinkHighlight();
+                console.log('isLinkHighlight', isLinkHighlight);
+                setIsLinkHighlight(isLinkHighlight);
+                setIsContinuousScrolling(await pdfReader?.isContinueMode());
+                setIsCrop(await pdfReader?.isCropMode());
+                
+                setThemes(await pdfReader?.getReadBackgroundColor());
+            }
+        }
+        
+        if(visible){
+            checkSettings();
+        }
+    }, [visible, pdfReader])
+
+    const renderScrollItem = () =>{
+        return (
+            <View>
+                <Text style={styles.subTitle}>Scroll</Text>
+                {_item('Vertical Scrolling', isVertical, () => {
+                    pdfReader?.setVerticalMode(true);
+                    setIsVertical(true);
+                })}
+                {_item('Horizontal Scrolling', !isVertical, () => {
+                    pdfReader?.setVerticalMode(false);
+                    setIsVertical(false);
+                })}
+            </View>
+        );
+    }
+
+    const renderDisplayMode = () => {
+        return (
+            <View>
+                <Text style={styles.subTitle}>Display Mode</Text>
+                {_item('Single Page', displayMode == CPDFDisplayMode.SINGLE_PAGE, () => {
+                    pdfReader?.setDoublePageMode(false)
+                    setDisplayMode(CPDFDisplayMode.SINGLE_PAGE)
+                })}
+                {_item('Two Page', displayMode == CPDFDisplayMode.DOUBLE_PAGE, () => {
+                    pdfReader?.setDoublePageMode(true)
+                    setDisplayMode(CPDFDisplayMode.DOUBLE_PAGE)
+                })}
+                {_item('Cover Mode', displayMode == CPDFDisplayMode.COVER_PAGE, () => {
+                    pdfReader?.setCoverPageMode(true);
+                    setDisplayMode(CPDFDisplayMode.COVER_PAGE)
+
+                })}
+            </View>
+        );
+    }
+
+    const renderOtherSettings = () => {
+        return (
+            <View>
+                <View style={styles.subTitle} ></View>
+                {_switchItem('Highlight Links', isLinkHighlight, (value) => {
+                    pdfReader?.setLinkHighlight(value);
+                    setIsLinkHighlight(value);
+                })}
+                {_switchItem('Highlight Form Fields', isFormFieldHighlight, (value) => {
+                    pdfReader?.setFormFieldHighlight(value);
+                    setIsFormFieldHighlight(value);
+                })}
+                {_switchItem('Continuous Scrolling', isContinuousScrolling, (value) => {
+                    pdfReader?.setContinueMode(value);
+                    setIsContinuousScrolling(value);
+                })}
+                {_switchItem('Crop', isCrop, (value) => {
+                    pdfReader?.setCropMode(value);
+                    setIsCrop(value);
+                })}
+                {_switchItem('Can Scale', isCanScale, (value) => {
+                    pdfReader?.setCanScale(value);
+                    setCanScale(value);
+                })}
+            </View>
+        );
+    }
+
+    const renderThemes = () => {
+        return (
+            <View>
+                <Text style={styles.subTitle}>Themes</Text>
+                {_item('Light', themes == CPDFThemes.LIGHT, () => {
+                    pdfReader?.setReadBackgroundColor(CPDFThemes.LIGHT);
+                    setThemes(CPDFThemes.LIGHT);
+                })}
+                {_item('Dark',  themes == CPDFThemes.DARK, () => {
+                    pdfReader?.setReadBackgroundColor(CPDFThemes.DARK);
+                    setThemes(CPDFThemes.DARK);
+                })}
+                {_item('Sepia',  themes == CPDFThemes.SEPIA, () => {
+                    pdfReader?.setReadBackgroundColor(CPDFThemes.SEPIA);
+                    setThemes(CPDFThemes.SEPIA);
+                })}
+                {_item('Reseda',  themes == CPDFThemes.RESEDA, () => {
+                    pdfReader?.setReadBackgroundColor(CPDFThemes.RESEDA);
+                    setThemes(CPDFThemes.RESEDA);
+                })}  
+            </View>
+        );
+    }
+
+    const _item = (title : string, isChecked : boolean, onPress : () =>void) => {
+        return (
+            <TouchableOpacity onPress={onPress}>
+                <View style={styles.item}>
+                    <Text style={isChecked ? styles.itemTextSelect : styles.itemTextNormal}>{title}</Text>
+                    {isChecked && (
+                        <Image source={require('../../assets/right.png')} style={{width: 24, height: 24, marginStart: 8}}/>
+                    )}
+                </View>
+            </TouchableOpacity>
+        );
+    }
+
+    const _switchItem = (title : string, isChecked : boolean, onValueChange : (value : boolean) => void) => {
+        return (
+            <TouchableOpacity>
+                <View style={styles.item}>
+                    <Text style={styles.itemTextNormal}>{title}</Text>
+                    <Switch 
+                        thumbColor={isChecked ? '#1460F3' : 'white'}
+                        trackColor={{false: '#E0E0E0', true: '#1460F34D'}}
+                        value={isChecked} onValueChange={onValueChange}/>
+                </View>
+            </TouchableOpacity>
+
+        );
+    }
+
+    return (
+        <Modal
+            animationType="slide"
+            transparent={true}
+            visible={visible}
+            onRequestClose={onClose}>
+            <TouchableWithoutFeedback onPress={onClose}>
+                <View style={styles.container}>
+                    <TouchableWithoutFeedback>
+                        <View style={styles.modalView}>
+                        <Text style={styles.title}>Settings</Text>
+                            <ScrollView>
+                                {renderScrollItem()}
+                                {renderDisplayMode()}
+                                {renderOtherSettings()}
+                                {renderThemes()}
+                            </ScrollView>
+                        </View>
+                    </TouchableWithoutFeedback>
+                </View>
+            </TouchableWithoutFeedback>
+        </Modal>
+    );
+
+}
+
+
+const styles = StyleSheet.create({
+    container: {
+        flex: 1,
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+    },
+    modalView: {
+        backgroundColor: 'white',
+        height: '80%',
+        justifyContent: 'flex-start',
+        borderTopLeftRadius: 20,
+        borderTopRightRadius: 20,
+    },
+    title : {
+        fontSize: 20,
+        fontWeight: 'bold',
+        marginTop : 16,
+        marginStart : 16,
+        marginBottom : 16,
+        color: 'black',
+    },
+    subTitle : {
+        fontSize : 14,
+        height: 32,
+        marginHorizontal: 16,
+        textAlignVertical: 'center',
+        color : 'black',
+        fontWeight : 'bold',
+        backgroundColor: '#FAFCFF',
+        borderRadius: 4
+    },
+    item : {
+        height : 48,
+        marginStart : 16,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        marginEnd : 16,
+        
+    },
+    itemTextNormal : {
+        textAlignVertical: 'center',
+        fontSize: 12,
+        color: 'gray'
+    },
+    itemTextSelect : {
+        textAlignVertical: 'center',
+        color: 'black',
+        fontSize: 12
+    }
+});

+ 126 - 0
example/src/screens/CPDFPreviewModeListScreen.tsx

@@ -0,0 +1,126 @@
+import PDFReaderContext, { CPDFReaderView, CPDFViewMode } from "@compdfkit_pdf_sdk/react_native";
+import { useContext, useState } from "react";
+import { FlatList, Image, Modal, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
+
+interface CPDFPreviewModeListScreenProps {
+    visible: boolean;
+    onClose: () => void;
+}
+
+export const CPDFPreviewModeListScreen : React.FC<CPDFPreviewModeListScreenProps> = ({ visible, onClose }) => {
+    
+    const pdfReader = useContext(PDFReaderContext) as CPDFReaderView | null;
+    
+    const list = [
+        {
+            title : 'Viewer',
+            mode : CPDFViewMode.VIEWER,
+        },
+        {
+            title : 'Annotations',
+            mode : CPDFViewMode.ANNOTATIONS,
+        },
+        {
+            title : 'Content Editor',
+            mode : CPDFViewMode.CONTENT_EDITOR,
+        },
+        {
+            title : 'Forms',
+            mode : CPDFViewMode.FORMS,
+        },
+        {
+            title : 'Signatures',
+            mode : CPDFViewMode.SIGNATURES,
+        },
+        ];
+
+    const [viewMode, setViewMode] = useState(CPDFViewMode.VIEWER);
+    
+    const _item = (title : string, isChecked : boolean, onPress : () =>void) => {
+        return (
+            <TouchableOpacity onPress={onPress}>
+                <View style={styles.item}>
+                    <Text style={isChecked ? styles.itemTextSelect : styles.itemTextNormal}>{title}</Text>
+                    {isChecked && (
+                        <Image source={require('../../assets/right.png')} style={{width: 24, height: 24, marginStart: 8}}/>
+                    )}
+                </View>
+            </TouchableOpacity>
+        );
+    }
+
+    return (
+        <Modal
+            animationType="slide"
+            transparent={true}
+            visible={visible}
+            onRequestClose={onClose}>
+            <TouchableWithoutFeedback onPress={onClose}>
+                <View style={styles.container}>
+                    <TouchableWithoutFeedback>
+                        <View style={styles.modalView}>
+                            <Text style={styles.title}>Mode List</Text>
+                            <FlatList
+                                data={list}
+                                renderItem={({ item }) =>
+                                    _item(
+                                        item.title,
+                                        viewMode === item.mode,
+                                        () => {
+                                            setViewMode(item.mode);
+                                            pdfReader?.setPreviewMode(item.mode);
+                                            onClose();
+                                        }
+                                    )
+                                }
+                                keyExtractor={item => item.title}
+                                />
+                        </View>
+                    </TouchableWithoutFeedback>
+                </View>
+            </TouchableWithoutFeedback>
+        </Modal>
+    );
+
+
+}
+
+const styles = StyleSheet.create({
+    container: {
+        flex: 1,
+        justifyContent: 'flex-end',
+        backgroundColor: 'rgba(0, 0, 0, 0.1)',
+    },
+    modalView: {
+        backgroundColor: 'white',
+        justifyContent: 'flex-start',
+        borderTopLeftRadius: 20,
+        borderTopRightRadius: 20,
+    },
+    title : {
+        fontSize: 20,
+        fontWeight: 'bold',
+        marginTop : 16,
+        marginStart : 16,
+        marginBottom : 16,
+        color: 'black',
+    },
+    item : {
+        height : 48,
+        marginStart : 16,
+        flexDirection: 'row',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        marginEnd : 16,
+    },
+    itemTextNormal : {
+        textAlignVertical: 'center',
+        fontSize: 14,
+        color: 'gray'
+    },
+    itemTextSelect : {
+        textAlignVertical: 'center',
+        color: 'black',
+        fontSize: 14
+    }
+});

+ 20 - 16
example/src/screens/HomeScreen.tsx

@@ -8,7 +8,7 @@ import {
   View,
 } from 'react-native';
 
-import examples from "../examples";
+import {examples} from "../examples";
 
 type Props = {};
 class HomeScreen extends Component<Props> {
@@ -16,7 +16,6 @@ class HomeScreen extends Component<Props> {
   render() {
     return (
         <View style={styles.container}>
-          <Text style={{ fontSize: 16, fontWeight: '500', color:'#000' }}>Examples</Text>
           <FlatList
             data={examples}
             renderItem={this._renderItem}
@@ -27,19 +26,22 @@ class HomeScreen extends Component<Props> {
   }
 
   _renderItem = ({ item }) => {
-    return (
-      <TouchableOpacity
-        style={styles.funItem} onPress={() => item.action(this)}>
-
-        <Image source={require('../../assets/view.png')} style={styles.itemIcon} />
-        <View style={{ flexDirection: 'column', flex: 1 }}>
-          <Text style={styles.itemTitle}>{item.title}</Text>
-          <Text style={styles.itemDescription}>{item.description}</Text>
-        </View>
-        <Image source={require('../../assets/arrow_right.png')} style={styles.itemTailIcon} />
-
-      </TouchableOpacity>
-    );
+    if(item.type === 'header'){
+      return (<Text style={{ fontSize: 16, fontWeight: '500', color:'#000', marginTop : 8 }}>{item.title}</Text>)
+    } else {
+      return (
+        <TouchableOpacity
+          style={styles.funItem} onPress={() => item.action(this)}>
+          <Image source={require('../../assets/view.png')} style={styles.itemIcon} />
+          <View style={{ flexDirection: 'column', flex: 1 }}>
+            <Text style={styles.itemTitle}>{item.title}</Text>
+            <Text style={styles.itemDescription}>{item.description}</Text>
+          </View>
+          <Image source={require('../../assets/arrow_right.png')} style={styles.itemTailIcon} />
+  
+        </TouchableOpacity>
+      );
+    }
   }
 
 }
@@ -56,6 +58,8 @@ const styles = StyleSheet.create({
     justifyContent: 'flex-start',
     alignItems: 'center',
     flexDirection: 'row',
+    marginTop: 4,
+    marginBottom: 4
   },
   itemIcon: {
     width: 32,
@@ -72,7 +76,7 @@ const styles = StyleSheet.create({
     fontWeight: 'bold'
   },
   itemDescription: {
-    fontSize: 12,
+    fontSize: 11,
     color: '#000',
     opacity: 0.6
   },

+ 251 - 8
ios/RCTCPDFView.swift

@@ -44,17 +44,17 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
         
         let homeDiectory = NSHomeDirectory()
         let bundlePath = Bundle.main.bundlePath
-            
+        
         if (documentPath.hasPrefix(homeDiectory) || documentPath.hasPrefix(bundlePath)) {
             let fileManager = FileManager.default
             let samplesFilePath = NSHomeDirectory().appending("/Documents/Files")
             let fileName = document.lastPathComponent
             let docsFilePath = samplesFilePath + "/" + fileName
-
+            
             if !fileManager.fileExists(atPath: samplesFilePath) {
                 try? FileManager.default.createDirectory(atPath: samplesFilePath, withIntermediateDirectories: true, attributes: nil)
             }
-
+            
             try? FileManager.default.copyItem(atPath: document.path, toPath: docsFilePath)
             
             documentPath = docsFilePath
@@ -64,13 +64,13 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
         
         let jsonData = CPDFJSONDataParse(String: configuration)
         let configurations = jsonData.configuration ?? CPDFConfiguration()
-
+        
         pdfViewController = CPDFViewController(filePath: documentPath, password: password, configuration: configurations)
         pdfViewController?.delegate = self
         navigationController = CNavigationController(rootViewController: pdfViewController!)
         navigationController?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         navigationController?.view.frame = self.frame
-
+        
         navigationController?.setViewControllers([pdfViewController!], animated: true)
         
         addSubview(navigationController?.view ?? UIView())
@@ -131,7 +131,7 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
     
     func importAnnotations(xfdfFile : URL, completionHandler: @escaping (Bool) -> Void) {
         if let pdfListView = self.pdfViewController?.pdfListView {
-        
+            
             let documentFolder = NSHomeDirectory().appending("/Documents/Files")
             if !FileManager.default.fileExists(atPath: documentFolder) {
                 try? FileManager.default.createDirectory(at: URL(fileURLWithPath: documentFolder), withIntermediateDirectories: true, attributes: nil)
@@ -194,6 +194,249 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
         }
     }
     
+    func setScale(scale : NSNumber){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.setScaleFactor(CGFloat(truncating: scale), animated: true)
+        }
+    }
+    
+    func getScale(completionHandler: @escaping (NSNumber) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(NSNumber(value: pdfListView.scaleFactor))
+        } else {
+            completionHandler(1.0)
+        }
+    }
+    
+    func setReadBackgroundColor(displayMode : NSString) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            switch displayMode {
+            case "light":
+                pdfListView.displayMode = .normal
+            case "dark":
+                pdfListView.displayMode = .night
+            case "sepia":
+                pdfListView.displayMode = .soft
+            case "reseda":
+                pdfListView.displayMode = .green
+            default:
+                pdfListView.displayMode = .normal
+            }
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func getReadbackgroundColor(completionHandler: @escaping (NSString) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            let dispalyMode = pdfListView.displayMode
+            switch dispalyMode {
+            case .normal:
+                completionHandler("#FFFFFF")
+            case .night:
+                completionHandler("#000000")
+            case .soft:
+                completionHandler("#FFFFFF")
+            case .green:
+                completionHandler("#FFEFBE")
+            case .custom:
+                completionHandler("#CDE6D0")
+            @unknown default:
+                completionHandler("#FFFFFF")
+            }
+        } else {
+            completionHandler("#FFFFFF")
+        }
+    }
+    
+    func setFormFieldHighlight(formFieldHighlight : Bool){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            CPDFKitConfig.sharedInstance().setEnableFormFieldHighlight(formFieldHighlight)
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isFormFieldHighlight(completionHandler: @escaping (Bool) -> Void){
+        completionHandler(CPDFKitConfig.sharedInstance().enableFormFieldHighlight())
+    }
+    
+    func setLinkHighlight(linkHighlight : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            CPDFKitConfig.sharedInstance().setEnableLinkFieldHighlight(linkHighlight)
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isLinkHighlight(completionHandler: @escaping (Bool) -> Void){
+        completionHandler(CPDFKitConfig.sharedInstance().enableLinkFieldHighlight())
+    }
+    
+    func setVerticalMode(isVerticalMode : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.displayDirection = isVerticalMode ? .vertical : .horizontal
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isVerticalMode(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.displayDirection == .vertical)
+        } else {
+            completionHandler(true)
+        }
+    }
+    
+    func setContinueMode(isContinueMode : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.displaysPageBreaks = isContinueMode
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isContinueMode(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.displaysPageBreaks)
+        }else {
+            completionHandler(true)
+        }
+    }
+    
+    func setDoublePageMode(isDoublePageMode : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.displayTwoUp = isDoublePageMode
+            pdfListView.displaysAsBook = false
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isDoublePageMode(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.displayTwoUp)
+        }else {
+            completionHandler(true)
+        }
+    }
+    
+    func setCoverPageMode(isCoverPageMode : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.displayTwoUp = isCoverPageMode
+            pdfListView.displaysAsBook = isCoverPageMode
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isCoverPageMode(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.displaysAsBook)
+        }else {
+            completionHandler(true)
+        }
+    }
+    
+    func setCropMode(isCropMode : Bool) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            pdfListView.displayCrop = isCropMode
+            pdfListView.layoutDocumentView()
+        }
+    }
+    
+    func isCropMode(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.displayCrop)
+        }else {
+            completionHandler(true)
+        }
+    }
+    
+    func getFileName(completionHandler: @escaping (String) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.documentURL.lastPathComponent)
+        }else {
+            completionHandler("")
+        }
+    }
+    
+    func isEncrypted(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.isEncrypted)
+        }else {
+            completionHandler(false)
+        }
+    }
+    
+    func isImageDoc(completionHandler: @escaping (Bool) -> Void){
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.isImageDocument())
+        }else {
+            completionHandler(false)
+        }
+    }
+    
+    func getPermissions(completionHandler: @escaping (NSNumber) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            let permissions = pdfListView.document?.permissionsStatus ?? .none
+            switch permissions {
+            case .none:
+                completionHandler(0)
+            case .user:
+                completionHandler(1)
+            case .owner:
+                completionHandler(2)
+            default:
+                completionHandler(0)
+            }
+        }else {
+            completionHandler(0)
+        }
+    }
+    
+    func getPageCount(completionHandler: @escaping (NSNumber) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.pageCount as NSNumber)
+        }else {
+            completionHandler(0)
+        }
+    }
+    
+    func checkOwnerUnlocked(completionHandler: @escaping (Bool) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.isCheckOwnerUnlocked())
+        }else {
+            completionHandler(false)
+        }
+    }
+    
+    func checkOwnerPassword(password : String, completionHandler: @escaping (Bool) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            completionHandler(pdfListView.document.checkOwnerPassword(password))
+        }else {
+            completionHandler(false)
+        }
+    }
+    
+    func getEncryptAlgo(completionHandler: @escaping (String) -> Void) {
+        if let pdfListView = self.pdfViewController?.pdfListView {
+            let encryptAlgo = pdfListView.document.encryptionLevel
+            switch encryptAlgo {
+            case .RC4:
+                completionHandler("rc4")
+            case .AES128:
+                completionHandler("aes128")
+            case .AES256:
+                completionHandler("aes256")
+            case .noEncryptAlgo:
+                completionHandler("noEncryptAlgo")
+            default:
+                completionHandler("noEncryptAlgo")
+            }
+        }else {
+            completionHandler("noEncryptAlgo")
+        }
+    }
+    
+    
+    
+    
+    
     // MARK: - CPDFViewBaseControllerDelete
     
     func PDFViewBaseController(_ baseController: CPDFViewBaseController, SaveState success: Bool) {
@@ -208,7 +451,7 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
     
     private var configuration: String = ""
     @objc func setConfiguration(_ newSection: String) {
-       configuration = newSection
+        configuration = newSection
         
         if (document.path.count > 1) && (configuration.count > 1) {
             createCPDFView()
@@ -226,7 +469,7 @@ class RCTCPDFView: UIView, CPDFViewBaseControllerDelete {
     
     private var password: String = ""
     @objc func setPassword(_ newSection: String) {
-       password = newSection
+        password = newSection
     }
     
     public var onChange: RCTBubblingEventBlock?

+ 144 - 0
ios/RCTCPDFViewManager.swift

@@ -86,7 +86,151 @@ class RCTCPDFReaderView: RCTViewManager, RCTCPDFViewDelegate {
         })
     }
     
+    func setScale(forCPDFViewTag tag : Int, scale : NSNumber) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setScale(scale: scale)
+    }
+    
+    func getScale(forCPDFViewTag tag : Int, completionHandler: @escaping (NSNumber) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getScale(completionHandler: { success in
+            completionHandler(success)
+        })
+    }
+    
+    func setReadBackgroundColor(forCPDFViewTag tag : Int, displayMode : NSString) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setReadBackgroundColor(displayMode: displayMode)
+    }
+    
+    func getReadBackgroundColor(forCPDFViewTag tag : Int, completionHandler: @escaping (NSString) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getReadbackgroundColor(completionHandler: {color in
+            completionHandler(color)
+        })
+    }
+    
+    func setFormFieldHighlight(forCPDFViewTag tag : Int, formFieldHighlight : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setFormFieldHighlight(formFieldHighlight: formFieldHighlight)
+    }
     
+    func isFormFieldHighlight(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isFormFieldHighlight(completionHandler: {highlight in
+            completionHandler(highlight)
+        })
+    }
+    
+    func setLinkHighlight(forCPDFViewTag tag : Int, linkHighlight : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setLinkHighlight(linkHighlight: linkHighlight)
+    }
+    
+    func isLinkHighlight(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isLinkHighlight(completionHandler: {highlight in
+            completionHandler(highlight)
+        })
+    }
+    
+    func setVerticalMode(forCPDFViewTag tag : Int, isVerticalMode : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setVerticalMode(isVerticalMode: isVerticalMode)
+    }
+    
+    func isVerticalMode(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isVerticalMode(completionHandler: {isVertical in
+            completionHandler(isVertical)
+        })
+    }
+    
+    func setContinueMode(forCPDFViewTag tag : Int, isContinueMode : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setContinueMode(isContinueMode: isContinueMode)
+    }
+    
+    func isContinueMode(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isContinueMode(completionHandler: {isContinue in
+            completionHandler(isContinue)
+        })
+    }
+    
+    func setDoublePageMode(forCPDFViewTag tag : Int, isDoublePageMode : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setDoublePageMode(isDoublePageMode: isDoublePageMode)
+    }
+    
+    func isDoublePageMode(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isDoublePageMode(completionHandler: {isDoublePage in
+            completionHandler(isDoublePage)
+        })
+    }
+    
+    func setCoverPageMode(forCPDFViewTag tag : Int, isCoverPageMode : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setCoverPageMode(isCoverPageMode: isCoverPageMode)
+    }
+    
+    func isCoverPageMode(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isCoverPageMode(completionHandler: { isCoverPageMode in
+            completionHandler(isCoverPageMode)
+        })
+    }
+    
+    func setCropMode(forCPDFViewTag tag : Int, isCropMode : Bool) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.setCropMode(isCropMode: isCropMode)
+    }
+    
+    func isCropMode(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isCropMode(completionHandler: completionHandler)
+    }
+    
+    func getFileName(forCPDFViewTag tag : Int, completionHandler: @escaping (String) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getFileName(completionHandler: completionHandler)
+    }
+    
+    func isEncrypted(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isEncrypted(completionHandler: completionHandler)
+    }
+    
+    func isImageDoc(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void){
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.isImageDoc(completionHandler: completionHandler)
+    }
+    
+    func getPermissions(forCPDFViewTag tag : Int, completionHandler: @escaping (NSNumber) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getPermissions(completionHandler: completionHandler)
+    }
+    
+    func getPageCount(forCPDFViewTag tag : Int, completionHandler: @escaping (NSNumber) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getPageCount(completionHandler: completionHandler)
+    }
+    
+    func checkOwnerUnlocked(forCPDFViewTag tag : Int, completionHandler: @escaping (Bool) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.checkOwnerUnlocked(completionHandler: completionHandler)
+    }
+    
+    func checkOwnerPassword(forCPDFViewTag tag : Int, password : String, completionHandler: @escaping (Bool) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.checkOwnerPassword(password: password, completionHandler: completionHandler)
+    }
+    
+    func getEncryptAlgo(forCPDFViewTag tag : Int, completionHandler: @escaping (String) -> Void) {
+        let rtcCPDFView = cpdfViews[tag]
+        rtcCPDFView?.getEncryptAlgo(completionHandler: completionHandler)
+    }
     
     // MARK: - RCTCPDFViewDelegate
     

+ 163 - 0
ios/RCTDocumentManager.m

@@ -41,6 +41,169 @@ RCT_EXTERN_METHOD(hasChange:(NSInteger)tag
                   withResolver:(RCTPromiseResolveBlock)resolve
                   withRejecter:(RCTPromiseRejectBlock)reject)
 
+RCT_EXTERN_METHOD(setScale:(NSInteger)tag
+                  withScaleValue:(nonnull NSNumber *) scale)
+
+RCT_EXTERN_METHOD(getScale:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setReadBackgroundColor:(NSInteger)tag
+                  withThemes:(NSDictionary) themes)
+
+RCT_EXTERN_METHOD(getReadBackgroundColor:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setFormFieldHighlight:(NSInteger)tag
+                  withFormFieldHighlight:(BOOL) formFieldHighlight)
+
+RCT_EXTERN_METHOD(isFormFieldHighlight:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setLinkHighlight:(NSInteger)tag
+                  withLinkHighlight:(BOOL) linkHighlight)
+
+RCT_EXTERN_METHOD(isLinkHighlight:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setVerticalMode:(NSInteger)tag
+                  withVerticalMode:(BOOL) isVerticalMode)
+
+RCT_EXTERN_METHOD(isVerticalMode:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setContinueMode:(NSInteger)tag
+                  withContiueMode:(BOOL) isContinueMode)
+
+RCT_EXTERN_METHOD(isContinueMode:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setDoublePageMode:(NSInteger)tag
+                  withDoublePageMode:(BOOL) isDoublePageMode)
+
+RCT_EXTERN_METHOD(isDoublePageMode:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setCoverPageMode:(NSInteger)tag
+                  withCoverPageMode:(BOOL) isCoverPageMode)
+
+RCT_EXTERN_METHOD(isCoverPageMode:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(setCropMode:(NSInteger)tag
+                  withCropMode:(BOOL) isCropMode)
+
+RCT_EXTERN_METHOD(isCropMode:(NSInteger)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+// TODO: 设置当前预览的模式
+// viewMode: viewer, annotations, contentEditor, forms, signatures
+RCT_EXTERN_METHOD(setPreviewMode:(NSInteger *)tag
+                  withViewMode:(NSString) viewMode)
+
+// TODO: 获取当前的预览模式
+// 返回值: viewer, annotations, contentEditor, forms, signatures
+RCT_EXTERN_METHOD(getPreviewMode:(NSInteger *)tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+// TODO: 显示缩略图列表弹窗
+// editMode: true: 进入编辑模式, false:不进入编辑模式
+RCT_EXTERN_METHOD(showThumbnailView:(NSInteger *)tag
+                  withEditMode:(BOOL) editMode)
+
+// TODO: 显示BOTA弹窗界面
+RCT_EXTERN_METHOD(showBotaView:(NSInteger *)tag)
+
+// TODO: 显示添加水印弹窗界面
+RCT_EXTERN_METHOD(showAddWatermarkView:(NSInteger *)tag)
+
+// TODO: 显示安全设置界面
+RCT_EXTERN_METHOD(showSecurityView:(NSInteger *)tag)
+
+// TODO: 显示预览设置界面
+RCT_EXTERN_METHOD(showDisplaySettingView:(NSInteger *)tag)
+
+// TODO: 进入截取模式
+RCT_EXTERN_METHOD(enterSnipMode:(NSInteger *)tag)
+
+// TODO: 退出截取模式
+RCT_EXTERN_METHOD(exitSnipMode:(NSInteger *)tag)
+
+// TODO: 打开文档
+// document: 文档的路径
+// password: 文档密码
+// 返回值: true | false  表示打开成功或失败
+RCT_EXTERN_METHOD(open:(NSInteger *)tag
+                  withDocument(NSURL *) document
+                  withPassword(NSString *) password
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+
+RCT_EXTERN_METHOD(getFileName:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(isEncrypted:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(isImageDoc:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(getPermissions:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(getPageCount:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(checkOwnerUnlocked:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(checkOwnerPassword:(NSInteger *) tag
+                  withPassword:(NSString *) password
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+//TODO: 移除当前文档密码
+//移除执行增量保存
+//返回值:true | false
+RCT_EXTERN_METHOD(removePassword:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+// TODO: 设置密码, 增量保存到当前文档
+// withInfo : NSDictionary 数据
+// user_password : String : 用户密码,可以为空
+// owner_password : String : 所有者密码,可以为空
+// allows_printing: Bool : 是否允许打印
+// allows_copying : Bool : 是否允许复制
+// encrypt_algo : String : 加密方式 : rc4, aes128, aes256, noEncryptAlgo
+// 返回值:true | false
+RCT_EXTERN_METHOD(setPassword:(NSInteger *) tag
+                  withInfo:(NSDictionary) info
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+RCT_EXTERN_METHOD(getEncryptAlgo:(NSInteger *) tag
+                  withResolver:(RCTPromiseResolveBlock)resolve
+                  withRejecter:(RCTPromiseRejectBlock)reject)
+
+
+
 + (BOOL)requiresMainQueueSetup
 {
   return NO;

+ 243 - 0
ios/RCTDocumentManager.swift

@@ -116,4 +116,247 @@ class RCTDocumentManager: NSObject, RCTBridgeModule {
         }
     }
     
+    @objc(setScale: withScaleValue:)
+    func setScale(tag : Int, scale : NSNumber) -> Void {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setScale(forCPDFViewTag: tag, scale: scale)
+        }
+    }
+    
+    @objc(getScale: withResolver: withRejecter:)
+    func getScale(tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getScale(forCPDFViewTag: tag) { scale in
+                resolve(scale)
+            }
+        }
+    }
+    
+    @objc(setReadBackgroundColor: withThemes:)
+    func setReadBackgroundColor(tag : Int, themes : NSDictionary) -> Void{
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            let displayMode = themes["displayMode"] as? NSString ?? "light"
+            reader.setReadBackgroundColor(forCPDFViewTag: tag, displayMode: displayMode)
+        }
+    }
+    
+    @objc(getReadBackgroundColor: withResolver: withRejecter:)
+    func getReadBackgroundColor(tag: Int,  resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getReadBackgroundColor(forCPDFViewTag: tag, completionHandler: {color in
+                resolve(color)
+            })
+        }
+    }
+    
+    @objc(setFormFieldHighlight: withFormFieldHighlight:)
+    func setFormFieldHighlight(tag: Int, formFieldHighlight : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setFormFieldHighlight(forCPDFViewTag: tag, formFieldHighlight: formFieldHighlight)
+        }
+    }
+    
+    @objc(isFormFieldHighlight: withResolver: withRejecter:)
+    func isFormFieldHighlight(tag: Int,  resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isFormFieldHighlight(forCPDFViewTag: tag, completionHandler: {highlight in
+                resolve(highlight)
+            })
+        }
+    }
+    
+    @objc(setLinkHighlight: withLinkHighlight:)
+    func setLinkHighlight(tag: Int, linkHighlight : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setLinkHighlight(forCPDFViewTag: tag, linkHighlight: linkHighlight)
+        }
+    }
+    
+    @objc(isLinkHighlight: withResolver: withRejecter:)
+    func isLinkHighlight(tag: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isLinkHighlight(forCPDFViewTag: tag, completionHandler: {highlight in
+                resolve(highlight)
+            })
+        }
+    }
+    
+    @objc(setVerticalMode: withVerticalMode:)
+    func setVerticalMode(tag : Int, isVerticalMode : Bool){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setVerticalMode(forCPDFViewTag: tag, isVerticalMode: isVerticalMode)
+        }
+    }
+    
+    @objc(isVerticalMode: withResolver: withRejecter:)
+    func isVerticalMode(tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isVerticalMode(forCPDFViewTag: tag, completionHandler: {isVertical in
+                resolve(isVertical)
+            })
+        }
+    }
+    
+    @objc(setContinueMode: withContiueMode:)
+    func setContinueMode(forCPDFViewTag tag : Int, isContinueMode : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setContinueMode(forCPDFViewTag: tag, isContinueMode: isContinueMode)
+        }
+    }
+    
+    @objc(isContinueMode: withResolver: withRejecter:)
+    func isContinueMode(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isContinueMode(forCPDFViewTag: tag, completionHandler: {isContinue in
+                resolve(isContinue)
+            })
+        }
+    }
+    
+    @objc(setDoublePageMode: withDoublePageMode:)
+    func setDoublePageMode(forCPDFViewTag tag : Int, isDoublePageMode : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setDoublePageMode(forCPDFViewTag: tag, isDoublePageMode: isDoublePageMode)
+        }
+    }
+    
+    @objc(isDoublePageMode: withResolver: withRejecter:)
+    func isDoublePageMode(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isDoublePageMode(forCPDFViewTag: tag, completionHandler: {isDoublePageMode in
+                resolve(isDoublePageMode)
+            })
+        }
+    }
+    
+    @objc(setCoverPageMode: withCoverPageMode:)
+    func setCoverPageMode(forCPDFViewTag tag : Int, isCoverPageMode : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setCoverPageMode(forCPDFViewTag: tag, isCoverPageMode: isCoverPageMode)
+        }
+    }
+    
+    @objc(isCoverPageMode: withResolver: withRejecter:)
+    func isCoverPageMode(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isCoverPageMode(forCPDFViewTag: tag, completionHandler: {isCoverPageMode in
+                resolve(isCoverPageMode)
+            })
+        }
+    }
+    
+    @objc(setCropMode: withCropMode:)
+    func setCropMode(forCPDFViewTag tag : Int, isCropMode : Bool) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.setCropMode(forCPDFViewTag: tag, isCropMode: isCropMode)
+        }
+    }
+    
+    @objc(isCropMode: withResolver: withRejecter:)
+    func isCropMode(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isCropMode(forCPDFViewTag: tag, completionHandler: {isCropMode in
+                resolve(isCropMode)
+            })
+        }
+    }
+    
+    @objc(getFileName: withResolver: withRejecter:)
+    func getFileName(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getFileName(forCPDFViewTag: tag, completionHandler: {fileName in
+                resolve(fileName)
+            })
+        }
+    }
+    
+    @objc(isEncrypted: withResolver: withRejecter:)
+    func isEncrypted(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isEncrypted(forCPDFViewTag: tag, completionHandler: {isEncrypted in
+                resolve(isEncrypted)
+            })
+        }
+    }
+    
+    @objc(isImageDoc: withResolver: withRejecter:)
+    func isImageDoc(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.isImageDoc(forCPDFViewTag: tag, completionHandler: {isImageDoc in
+                resolve(isImageDoc)
+            })
+        }
+    }
+    
+    @objc(getPermissions: withResolver: withRejecter:)
+    func getPermissions(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getPermissions(forCPDFViewTag: tag, completionHandler: {permissions in
+                resolve(permissions)
+            })
+        }
+    }
+    
+    @objc(getPageCount: withResolver: withRejecter:)
+    func getPageCount(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getPageCount(forCPDFViewTag: tag, completionHandler: {pageCount in
+                resolve(pageCount)
+            })
+        }
+    }
+    
+    @objc(checkOwnerUnlocked: withResolver: withRejecter:)
+    func checkOwnerUnlocked(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.checkOwnerUnlocked(forCPDFViewTag: tag, completionHandler: {unlocked in
+                resolve(unlocked)
+            })
+        }
+    }
+    
+    
+    @objc(checkOwnerPassword: withPassword: withResolver: withRejecter:)
+    func checkOwnerPassword(forCPDFViewTag tag : Int, password : String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock){
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.checkOwnerPassword(forCPDFViewTag: tag, password: password, completionHandler: {correct in
+                resolve(correct)
+            })
+        }
+    }
+    
+    @objc(getEncryptAlgo: withResolver: withRejecter:)
+    func getEncryptAlgo(forCPDFViewTag tag : Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
+        DispatchQueue.main.async {
+            let reader = self.readerView()
+            reader.getEncryptAlgo(forCPDFViewTag: tag, completionHandler: {encryptAlgo in
+                resolve(encryptAlgo)
+            })
+        }
+    }
 }

+ 70 - 21
src/configuration/CPDFOptions.ts

@@ -299,27 +299,28 @@ export type CPDFDisplayMode = ValueOf<typeof CPDFDisplayMode>;
 
 export const CPDFThemes = {
 
-  /**
-   * Bright mode, readerview background is white
-   */
-  LIGHT: 'light',
-
-  /**
-   * dark mode, readerview background is black
-   */
-  DARK: 'dark',
-
-  /**
-   * brown paper color
-   */
-  SEPIA: 'sepia',
-
-  /**
-   * Light green, eye protection mode
-   */
-  RESEDA: 'reseda'
-
-}
+    /**
+     * Bright mode, readerview background is white
+     */
+    LIGHT: 'light',
+  
+    /**
+     * dark mode, readerview background is black
+     */
+    DARK: 'dark',
+  
+    /**
+     * brown paper color
+     */
+    SEPIA: 'sepia',
+  
+    /**
+     * Light green, eye protection mode
+     */
+    RESEDA: 'reseda'
+  
+  }
+  
 export type CPDFThemes = ValueOf<typeof CPDFThemes>;
 
 /**
@@ -345,6 +346,54 @@ export const CPDFThemeMode = {
 }
 export type CPDFThemeMode = ValueOf<typeof CPDFThemeMode>;
 
+/**
+ * Represents the permissions available for the currently opened document.
+ */
+export const CPDFDocumentPermissions = {
+    /**
+     * No restrictions. The document does not have an open password or owner permission password.
+     */
+    NONE: 'none',
+
+    /**
+     * User permissions. The document can only be viewed and has an owner password set.
+     */
+    USER: 'user',
+
+    /**
+     * Owner permissions. The current viewer is identified as the owner of the document.
+     */
+    OWNER: 'owner',
+};
+export type CPDFDocumentPermissions = ValueOf<typeof CPDFDocumentPermissions>;
+
+/**
+ * Specifies the encryption algorithms supported for a PDF document.
+ */
+export const CPDFDocumentEncryptAlgo = {
+    /**
+     * RC4 encryption algorithm.
+     */
+    RC4: 'rc4',
+
+    /**
+     * AES 128-bit encryption algorithm.
+     */
+    AES128: 'aes128',
+
+    /**
+     * AES 256-bit encryption algorithm.
+     */
+    AES256: 'aes256',
+
+    /**
+     * Indicates that no encryption algorithm is applied.
+     */
+    NO_ENCRYPT_ALGO: 'noEncryptAlgo',
+};
+
+export type CPDFDocumentEncryptAlgo = ValueOf<typeof CPDFDocumentEncryptAlgo>;
+
 export type AnyCase<T extends string> =
     string extends T ? string :
     T extends `${infer F1}${infer F2}${infer R}` ? (

+ 6 - 0
src/index.tsx

@@ -10,6 +10,8 @@
 import { NativeModules } from 'react-native';
 import { CPDFConfiguration } from './configuration/CPDFConfiguration';
 import { CPDFAlignment, CPDFAnnotationType, CPDFBorderStyle, CPDFCheckStyle, CPDFConfigTool, CPDFContentEditorType, CPDFDisplayMode, CPDFFormType, CPDFLineType,CPDFThemeMode, CPDFThemes, CPDFToolbarAction, CPDFToolbarMenuAction, CPDFTypeface, CPDFViewMode } from './configuration/CPDFOptions';
+import React from 'react';
+import { CPDFReaderView } from '../lib/typescript/src';
 
 declare module 'react-native' {
   interface NativeModulesStatic {
@@ -459,3 +461,7 @@ function mergeDeep(defaults: any, overrides: any): any {
 
   return merged;
 }
+
+const PDFReaderContext = React.createContext<CPDFReaderView | null>(null);
+
+export default PDFReaderContext;

+ 324 - 0
src/view/CPDFDocument.tsx

@@ -0,0 +1,324 @@
+import { NativeModules, findNodeHandle } from 'react-native';
+import { CPDFDocumentEncryptAlgo, CPDFDocumentPermissions } from '../configuration/CPDFOptions';
+const { CPDFViewManager } = NativeModules;
+
+class CPDFDocument {
+
+    _viewerRef: any;
+
+    constructor(viewerRef: any) {
+        this._viewerRef = viewerRef;
+    }
+
+    /**
+     * Reopens a specified document in the current `CPDFReaderView` component.
+     *
+     * @example
+     * await pdfReaderRef.current?._pdfDocument.open(filePath, 'password');
+     *
+     * @param filePath The file path of the PDF document.
+     * * (Android) For a local storage file path:
+     * ```tsx
+     *    filePath = 'file:///storage/emulated/0/Download/sample.pdf'
+     * ```
+     * * (Android) For a content URI:
+     * ```tsx
+     *    filePath = 'content://...'
+     * ```
+     * * (Android) For an asset file path:
+     * ```tsx
+     *    filePath = "file:///android_asset/..."
+     * ```
+     * @param password The password for the document, which can be null or empty.
+     * @returns A promise that resolves to `true` if the document is successfully opened, otherwise `false`.
+     */
+    open = (filePath: string, password: string | null = null): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.open(tag, filePath, password);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    };
+
+    /**
+     * Gets the file name of the PDF document.
+     * @example
+     * const fileName = await pdfReaderRef.current?._pdfDocument.getFileName();
+     * @returns 
+     */
+    getFileName = (): Promise<string> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.getFileName(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Checks if the PDF document is encrypted.
+     * @example
+     * const isEncrypted = await pdfReaderRef.current?._pdfDocument.isEncrypted();
+     * @returns 
+     */
+    isEncrypted = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.isEncrypted(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Checks if the PDF document is an image document.
+     * This is a time-consuming operation that depends on the document size.
+     * @example
+     * const isImageDoc = await pdfReaderRef.current?._pdfDocument.isImageDoc();
+     * @returns 
+     */
+    isImageDoc = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.isImageDoc(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Gets the current document's permissions. There are three types of permissions:
+     * No restrictions: [CPDFDocumentPermissions.NONE]
+     * If the document has an open password and an owner password,
+     * using the open password will grant [CPDFDocumentPermissions.USER] permissions,
+     * and using the owner password will grant [CPDFDocumentPermissions.OWNER] permissions.
+     * 
+     * @example
+     * const permissions = await pdfReaderRef.current?._pdfDocument.getPermissions();
+     * @returns 
+     */
+    getPermissions = async (): Promise<CPDFDocumentPermissions> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            const id = await CPDFViewManager.getPermissions(tag);
+            if (id == 0) {
+                return Promise.resolve(CPDFDocumentPermissions.NONE);
+            } else if (id == 1) {
+                return Promise.resolve(CPDFDocumentPermissions.USER);
+            } else if (id == 2) {
+                return Promise.resolve(CPDFDocumentPermissions.OWNER);
+            }
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Check if owner permissions are unlocked
+     * 
+     * @example
+     * const unlocked = await pdfReaderRef.current?._pdfDocument.checkOwnerUnlocked();
+     * @returns 
+     */
+    checkOwnerUnlocked = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.checkOwnerUnlocked(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Whether the owner password is correct.
+     * If the password is correct, the document will be unlocked with full owner permissions.
+     * 
+     * @example
+     * const check = await pdfReaderRef.current?._pdfDocument.checkOwnerPassword('ownerPassword');
+     * 
+     * @param password password The owner password to be verified.
+     * @returns A promise that resolves to `true` if the owner password is correct, otherwise `false`.
+     */
+    checkOwnerPassword = (password: string): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.checkOwnerPassword(tag, password);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Get the total number of pages in the current document
+     * 
+     * @example
+     * const pageCount = await pdfReaderRef.current?._pdfDocument.getPageCount();
+     * 
+     * @returns 
+     */
+    getPageCount = (): Promise<number> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.getPageCount(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Remove the user password and owner permission password
+     * set in the document, and perform an incremental save.
+     * 
+     * @example
+     * const result = await pdfReaderRef.current?._pdfDocument.removePassword();
+     * @returns 
+     */
+    removePassword = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.removePassword(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * 
+     * This method sets the document password, including the user password for access restrictions
+     * and the owner password for granting permissions.
+     * 
+     * - To enable permissions like printing or copying, the owner password must be set; otherwise,
+     * the settings will not take effect.
+     * 
+     * @example
+     * const success = await pdfReaderRef.current?._pdfDocument.setPassword(
+     *  'user_password',
+     *  'owner_password',
+     *  false,
+     *  false,
+     *  CPDFDocumentEncryptAlgo.rc4
+     * );
+     * 
+     * @param userPassword The user password for document access restrictions.
+     * @param ownerPassword The owner password to grant permissions (e.g., printing, copying).
+     * @param allowsPrinting Whether printing is allowed (true or false).
+     * @param allowsCopying Whether copying is allowed (true or false).
+     * @param encryptAlgo The encryption algorithm to use (e.g., `CPDFDocumentEncryptAlgo.rc4`).
+     * @returns A promise that resolves to `true` if the password is successfully set, otherwise `false`.
+     */
+    setPassword = (
+        userPassword: string,
+        ownerPassword: string,
+        allowsPrinting: boolean,
+        allowsCopying: boolean,
+        encryptAlgo: CPDFDocumentEncryptAlgo): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.setPassword(tag, {
+                'user_password': userPassword,
+                'owner_password': ownerPassword,
+                'allows_printing': allowsPrinting,
+                'allows_copying': allowsCopying,
+                'encrypt_algo': encryptAlgo
+            });
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * Get the encryption algorithm of the current document
+     * 
+     * @example
+     * const encryptAlgo = await pdfReaderRef.current?._pdfDocument.getEncryptAlgo();
+     * @returns 
+     */
+    getEncryptAlgo = async (): Promise<CPDFDocumentEncryptAlgo> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            const encryptAlgo = await CPDFViewManager.getEncryptAlgo(tag);
+            if (encryptAlgo == 'noEncryptAlgo') {
+                return Promise.resolve(CPDFDocumentEncryptAlgo.NO_ENCRYPT_ALGO);
+            } else if (encryptAlgo == 'rc4') {
+                return Promise.resolve(CPDFDocumentEncryptAlgo.RC4);
+            } else if (encryptAlgo == 'aes128') {
+                return Promise.resolve(CPDFDocumentEncryptAlgo.AES128);
+            } else if (encryptAlgo == 'aes256') {
+                return Promise.resolve(CPDFDocumentEncryptAlgo.AES256);
+            }
+        }
+        return Promise.reject('Unable to find the native view reference')
+    }
+
+    /**
+     * Checks whether the document has been modified
+     *
+     * @example
+     * const hasChange = await pdfReaderRef.current?._pdfDocument.hasChange();
+     *
+     * @returns {Promise<boolean>} Returns a Promise indicating if the document has been modified.
+     *          `true`: The document has been modified,
+     *          `false`: The document has not been modified.
+     *          If the native view reference cannot be found, a rejected Promise will be returned.
+     */
+    hasChange = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.hasChange(tag);
+        }
+        return Promise.resolve(false);
+    }
+
+    /**
+     * Exports annotations from the current PDF document to an XFDF file.
+     *
+     * @example
+     * const exportXfdfFilePath = await pdfReaderRef.current?._pdfDocument.exportAnnotations();
+     *
+     * @returns The path of the XFDF file if export is successful; an empty string if the export fails.
+     */
+    exportAnnotations = (): Promise<string> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.exportAnnotations(tag);
+        }
+        return Promise.reject('Unable to find the native view reference');
+    }
+
+    /**
+     * 
+     * Delete all comments in the current document
+     * @example
+     * const removeResult = await pdfReaderRef.current?._pdfDocument.removeAllAnnotations();
+     *
+     * @returns
+     */
+    removeAllAnnotations = (): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.removeAllAnnotations(tag);
+        }
+        return Promise.resolve(false);
+    }
+
+    /**
+     * Imports annotations from the specified XFDF file into the current PDF document.
+     * @example
+     * // Android - assets file
+     * const testXfdf = 'file:///android_asset/test.xfdf';
+     * const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(testXfdf);
+     *
+     * // Android - file path
+     * const testXfdf = '/data/user/0/com.compdfkit.reactnative.example/xxx/xxx.xfdf';
+     * const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(testXfdf);
+     *
+     * // Android - Uri
+     * const xfdfUri = 'content://xxxx'
+     * const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(xfdfUri);
+     *
+     * // iOS
+     *
+     * @param xfdfFile Path of the XFDF file to be imported.
+     * @returns true if the import is successful; otherwise, false.
+     */
+    importAnnotations = (xfdfFile: string): Promise<boolean> => {
+        const tag = findNodeHandle(this._viewerRef);
+        if (tag != null) {
+            return CPDFViewManager.importAnnotations(tag, xfdfFile);
+        }
+        return Promise.resolve(false);
+    }
+
+}
+export default CPDFDocument;

+ 597 - 36
src/view/CPDFReaderView.tsx

@@ -9,8 +9,10 @@
 
 import React, { PureComponent } from 'react';
 import PropTypes, { Requireable, Validator } from 'prop-types';
-import { findNodeHandle, requireNativeComponent, NativeModules } from 'react-native';
+import { findNodeHandle, requireNativeComponent, NativeModules,Platform } from 'react-native';
 import { ViewPropTypes } from 'deprecated-react-native-prop-types';
+import { CPDFThemes, CPDFViewMode } from '../configuration/CPDFOptions';
+import CPDFDocument from './CPDFDocument';
 const { CPDFViewManager } = NativeModules;
 
 /**
@@ -41,7 +43,7 @@ type CPDFReaderViewProps = PropTypes.InferProps<typeof propTypes>;
 
 function func<T>(): Requireable<T> {
 
-  let validator: Validator<T> = function (props: { [key: string]: any }, propName: string, componentName: string, location: string, propFullName: string): Error | null {
+  let validator: Validator<T> = function (props: { [key: string]: any }, propName: string, componentName: string): Error | null {
     if (typeof props[propName] !== "function" && typeof props[propName] !== "undefined") {
       return new Error(`Invalid prop \`${propName}\` of type \`${typeof props[propName]}\` supplied to \`${componentName}\`, expected a function.`);
     }
@@ -57,6 +59,7 @@ function func<T>(): Requireable<T> {
 export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
 
   _viewerRef: any;
+  _pdfDocument : CPDFDocument;
 
   static propTypes = propTypes;
 
@@ -64,8 +67,14 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
     password: ''
   }
 
+  constructor(props : CPDFReaderViewProps) {
+    super(props);
+    this._pdfDocument = new CPDFDocument(this._viewerRef);
+  }
+  
   _setNativeRef = (ref: any) => {
     this._viewerRef = ref;
+    this._pdfDocument = new CPDFDocument(this._viewerRef);
   }
 
   onChange = (event : any) => {
@@ -108,16 +117,19 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    * @param bottom
    * @returns
    */
-  setMargins = (left: number, top: number, right: number, bottom: number) => {
+  setMargins = (left: number, top: number, right: number, bottom: number) : Promise<void> => {
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return;
+    if (tag != null) {
+      return CPDFViewManager.setMargins(tag, [left, top, right, bottom]);
     }
-    CPDFViewManager.setMargins(tag, [left, top, right, bottom]);
+    return Promise.resolve();
   };
 
   /**
+   * 
+   * @deprecated This method is deprecated and will be removed in future versions. 
+   * Use `_pdfDocument.removeAllAnnotations()` instead.
+   * 
    * Delete all comments in the current document
    * @example
    * const removeResult = await pdfReaderRef.current?.removeAllAnnotations();
@@ -126,14 +138,17 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    */
   removeAllAnnotations = () : Promise<boolean> => {
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.resolve(false);
+    if (tag != null) {
+      return CPDFViewManager.removeAllAnnotations(tag);
     }
-    return CPDFViewManager.removeAllAnnotations(tag);
+    return Promise.resolve(false);
   }
 
   /**
+   * 
+   * @deprecated This method is deprecated and will be removed in future versions. 
+   * Use `_pdfDocument.importAnnotations()` instead.
+   * 
    * Imports annotations from the specified XFDF file into the current PDF document.
    * @example
    * // Android - assets file
@@ -157,14 +172,17 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    */
   importAnnotations = (xfdfFile : string) : Promise<boolean> => {
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.resolve(false);
+    if (tag != null) {
+      return CPDFViewManager.importAnnotations(tag, xfdfFile);
     }
-    return CPDFViewManager.importAnnotations(tag, xfdfFile);
+    return Promise.resolve(false);
   }
 
   /**
+   * 
+   * @deprecated This method is deprecated and will be removed in future versions. 
+   * Use `_pdfDocument.exportAnnotations()` instead.
+   * 
    * Exports annotations from the current PDF document to an XFDF file.
    *
    * @example
@@ -173,12 +191,7 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    * @returns The path of the XFDF file if export is successful; an empty string if the export fails.
    */
   exportAnnotations = () : Promise<string> =>{
-    const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.reject("Unable to find the native view reference")
-    }
-    return CPDFViewManager.exportAnnotations(tag);
+    return this._pdfDocument.exportAnnotations();
   }
 
   /**
@@ -190,13 +203,12 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    * @param pageIndex The index of the page to jump.
    * @returns
    */
-  setDisplayPageIndex = (pageIndex : number) => {
+  setDisplayPageIndex = (pageIndex : number) : Promise<void> => {
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.reject("Unable to find the native view reference")
+    if(tag != null){
+      return CPDFViewManager.setDisplayPageIndex(tag, pageIndex);
     }
-    return CPDFViewManager.setDisplayPageIndex(tag, pageIndex);
+    return Promise.resolve();
   }
 
   /**
@@ -209,14 +221,16 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    */
   getCurrentPageIndex = () : Promise<number> =>{
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.reject("Unable to find the native view reference")
+    if(tag != null){
+      return CPDFViewManager.getCurrentPageIndex(tag);
     }
-    return CPDFViewManager.getCurrentPageIndex(tag);
+    return Promise.resolve(0);
   }
 
-/**
+  /**
+   * @deprecated This method is deprecated and will be removed in future versions. 
+   * Use `_pdfDocument.hasChange()` instead.
+   * 
    * Checks whether the document has been modified
    *
    * @example
@@ -228,18 +242,564 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
    *          If the native view reference cannot be found, a rejected Promise will be returned.
    */
   hasChange = () : Promise<boolean> => {
+    return this._pdfDocument.hasChange();
+  }
+
+  /**
+   * Set the page scale
+   * Value Range: 1.0~5.0
+   * 
+   * @example
+   * await pdfReaderRef.current?.setScale(2.0);
+   * 
+   * @param scale 
+   * @returns Returns a Promise.
+   */
+  setScale = (scale : number) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setScale(tag, scale);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Get the current page scale
+   * 
+   * @example
+   * const scale = await pdfReaderRef.current?.getScale();
+   * 
+   * @returns Returns the zoom ratio of the current page.
+   */
+  getScale = () : Promise<number> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.getScale(tag);
+    }
+    return Promise.resolve(1);
+  }
+
+  /**
+   * Whether allow to scale.
+   * Default : true
+   * 
+   * @example
+   * await pdfReaderRef.current?.setCanScale(false);
+   * 
+   * @param canScale 
+   * @returns 
+   */
+  setCanScale = (canScale : boolean) : Promise<void> =>{
+    if(Platform.OS != 'android'){
+      return Promise.reject('setCanScale() method only support Android platform.')
+    }
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setCanScale(tag, canScale);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Sets background color of reader.
+   * The color of each document space will be set to 75% of [color] transparency
+   * @example
+   * await pdfReaderRef.current?.setReadBackgroundColor(CPDFThemes.LIGHT);
+   * 
+   * @param theme 
+   * @returns 
+   */
+  setReadBackgroundColor = (theme : CPDFThemes) : Promise<void> =>{
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      let color: string;
+      switch (theme) {
+        case CPDFThemes.LIGHT:
+          color = '#FFFFFF';
+          break;
+        case CPDFThemes.DARK:
+          color = '#000000';
+          break;
+        case CPDFThemes.SEPIA:
+          color = '#FFEFBE';
+          break;
+        case CPDFThemes.RESEDA:
+          color = '#CDE6D0';
+          break;
+        default:
+          color = '#FFFFFF';
+      }
+      return CPDFViewManager.setReadBackgroundColor(tag, {
+          'displayMode' : theme,
+          'color' : color
+      });
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Get background color of reader.
+   * 
+   * @example
+   * CPDFThemes theme = await pdfReaderRef.current?.getReadBackgroundColor();
+   * @returns 
+   */
+  getReadBackgroundColor = async () : Promise<CPDFThemes> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      var themesColor : string = await CPDFViewManager.getReadBackgroundColor(tag);
+      console.log('ComPDFKit themesColor:', themesColor);
+      let theme: CPDFThemes;
+      switch (themesColor) {
+        case '#FFFFFFFF':
+          theme = CPDFThemes.LIGHT;
+          break;
+        case '#FF000000':
+          theme = CPDFThemes.DARK;
+          break;
+        case '#FFFFEFBE':
+          theme = CPDFThemes.SEPIA;
+          break;
+        case '#FFCDE6D0':
+          theme = CPDFThemes.RESEDA;
+          break;
+        default:
+          theme = CPDFThemes.LIGHT;
+      }
+      return Promise.resolve(theme);
+    }
+    return Promise.resolve(CPDFThemes.LIGHT);
+  }
+
+  /**
+   * Sets whether to display highlight Form Field.
+   * @example
+   * await pdfReaderRef.current?.setFormFieldHighlight(true);
+   * @param isFormFieldHighlight true to display highlight Form Field.
+   * @returns 
+   */
+  setFormFieldHighlight = (isFormFieldHighlight : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setFormFieldHighlight(tag, isFormFieldHighlight);
+    }
+    return Promise.resolve();
+  }
+  
+  /**
+   * Whether to display highlight Form Field.
+   * @example
+   * const isFormFieldHighlight = await pdfReaderRef.current?.isFormFieldHighlight();
+   * @returns 
+   */
+  isFormFieldHighlight = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isFormFieldHighlight(tag);
+    }
+    return Promise.resolve(false);
+  }
+
+  /**
+   * Sets whether to display highlight Link.
+   * @example
+   * await pdfReaderRef.current?.setLinkHighlight(true);
+   * @param isLinkHighlight Whether to highlight Link.
+   * @returns 
+   */
+  setLinkHighlight = (isLinkHighlight : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setLinkHighlight(tag, isLinkHighlight);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Whether to display highlight Link.
+   * @example
+   * const isLinkHighlight = await pdfReaderRef.current?.isLinkHighlight();
+   * @returns 
+   */
+  isLinkHighlight = () : Promise<boolean> => {
     const tag = findNodeHandle(this._viewerRef);
-    if (!tag) {
-      console.error('Unable to find the native view reference');
-      return Promise.reject("Unable to find the native view reference")
+    if(tag != null){
+      return CPDFViewManager.isLinkHighlight(tag);
     }
-    return CPDFViewManager.hasChange(tag);
+    return Promise.resolve(false);
+  }
+
+  /**
+   * Sets whether it is vertical scroll mode.
+   * @example
+   * await pdfReaderRef.current?.setVerticalMode(true);
+   * @param isVerticalMode Whether it is vertical scroll mode.
+   * @returns 
+   */
+  setVerticalMode = (isVerticalMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setVerticalMode(tag, isVerticalMode);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Whether it is vertical scroll mode.
+   * @example
+   * await pdfReaderRef.current?.isVerticalMode();
+   * @returns 
+   */
+  isVerticalMode = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isVerticalMode(tag);
+    }
+    return Promise.resolve(false);
+  }
+
+  /**
+   * Sets the spacing between pages. This method is supported only on the [Android] platform.
+   * - For the [iOS] platform, use the [setMargins] method instead.
+   * The spacing between pages is equal to the value of [CPDFEdgeInsets.top].
+   * @example
+   * await pdfReaderRef.current?.setPageSpacing(10);
+   * @param pageSpacing The space between pages, in pixels.
+   * @returns 
+   */
+  setPageSpacing = (pageSpacing : number) : Promise<void> => {
+    if(Platform.OS === 'ios'){
+      return Promise.reject('This method is not supported on iOS, only supported on Android');
+    }
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setPageSpacing(tag, pageSpacing);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Sets whether it is continuous scroll mode.
+   * @example
+   * await pdfReaderRef.current?.setContinueMode(true);
+   * @param isContinueMode Whether it is continuous scroll mode.
+   * @returns 
+   */
+  setContinueMode = (isContinueMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setContinueMode(tag, isContinueMode);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Whether it is continuous scroll mode.
+   * @example
+   * await pdfReaderRef.current?.isContinueMode();
+   * @returns 
+   */
+  isContinueMode = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isContinueMode(tag);
+    }
+    return Promise.resolve(true);
+  }
+
+  /**
+   * Sets whether it is double page mode.
+   * @example
+   * await pdfReaderRef.current?.setDoublePageMode(true);
+   * @param isDoublePageMode Whether it is double page mode.
+   * @returns 
+   */
+  setDoublePageMode = (isDoublePageMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setDoublePageMode(tag, isDoublePageMode);
+    }
+    return Promise.resolve();
+  }
+  
+  /**
+   * Whether it is double page mode.
+   * @example
+   * await pdfReaderRef.current?.isDoublePageMode();
+   * @returns 
+   */
+  isDoublePageMode = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isDoublePageMode(tag);
+    }
+    return Promise.resolve(false);
+  }
+
+  /**
+   * Sets whether it is cover page mode.
+   * @example
+   * await pdfReaderRef.current?.setCoverPageMode(true);
+   * @param isCoverPageMode 
+   * @returns 
+   */
+  setCoverPageMode = (isCoverPageMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setCoverPageMode(tag, isCoverPageMode);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Whether it is cover page mode.
+   * @example
+   * await pdfReaderRef.current?.isCoverPageMode();
+   * @returns 
+   */
+  isCoverPageMode = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isCoverPageMode(tag);
+    }
+    return Promise.resolve(false);
+  }
+  /**
+   * Sets whether it is crop mode.
+   * @example
+   * await pdfReaderRef.current?.setCropMode(true);
+   * @param isCropMode Whether it is crop mode.
+   * @returns 
+   */
+  setCropMode = (isCropMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setCropMode(tag, isCropMode);
+    }
+    return Promise.resolve();
+  }
+  /**
+   * Whether it is crop mode.
+   * @example
+   * await pdfReaderRef.current?.isCropMode();
+   * @returns 
+   */
+  isCropMode = () : Promise<boolean> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isCropMode(tag);
+    }
+    return Promise.resolve(false);
+  }
+
+  /**
+   * In the single page mode, set whether all pages keep the same width 
+   * and the original page keeps the same width as readerView.
+   * 
+   * @example
+   * await pdfReaderRef.current?.setPageSameWidth(true);
+   * 
+   * @param isPageSameWidth true: All pages keep the same width, the original state keeps the same width as readerView; false: Show in the actual width of page
+   * @returns 
+   */
+  setPageSameWidth = (isPageSameWidth : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setPageSameWidth(tag, isPageSameWidth);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Gets whether the specified [pageIndex] is displayed on the screen
+   * @example
+   * const isPageInScreen = await pdfReaderRef.current?.isPageInScreen(1);
+   * @param pageIndex 
+   * @returns 
+   */
+  isPageInScreen = (pageIndex : number) : Promise<boolean> => {
+    if(Platform.OS === 'ios'){
+      return Promise.reject('This method is not supported on iOS, only supported on Android');
+    }
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.isPageInScreen(tag, pageIndex);
+    }
+    return Promise.resolve(false);
+  }
+
+  /**
+   * Sets whether to fix the position of the non-swipe direction when zooming in for reading.
+   * @example
+   * await pdfReaderRef.current?.setFixedScroll(true);
+   * @param isFixedScroll
+   * @returns 
+   */
+  setFixedScroll = (isFixedScroll : boolean) : Promise<void> => {
+    if(Platform.OS != 'android'){
+      return Promise.reject('setFixedScroll() method only support Android platform')
+    }
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setFixedScroll(tag, isFixedScroll);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Switch the mode displayed by the current CPDFReaderWidget.
+   * Please see [CPDFViewMode] for available modes.
+   * 
+   * @example
+   * await pdfReaderRef.current?.setPreviewMode(CPDFViewMode.VIEWER);
+   * @param viewMode 
+   * @returns 
+   */
+  setPreviewMode = (viewMode : CPDFViewMode) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.setPreviewMode(tag, viewMode);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Get the currently displayed mode
+   * @example
+   * const mode = await pdfReaderRef.current?.getPreviewMode();
+   * @returns 
+   */
+  getPreviewMode = () : Promise<CPDFViewMode> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      var modeStr = CPDFViewManager.getPreviewMode(tag);
+      for (const key in CPDFViewMode) {
+        if (CPDFViewMode[key as keyof typeof CPDFViewMode] === modeStr) {
+          return Promise.resolve(CPDFViewMode[key as keyof typeof CPDFViewMode]);
+        }
+      }
+    }
+    return Promise.resolve(CPDFViewMode.VIEWER);
+  }
+
+  /**
+   * Displays the thumbnail view. When [editMode] is `true`, 
+   * the page enters edit mode, allowing operations such as insert, delete, extract, etc.
+   * 
+   * @example
+   * await pdfReaderRef.current?.showThumbnailView(true);
+   * 
+   * @param editMode 
+   * @returns 
+   */
+  showThumbnailView = (editMode : boolean) : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.showThumbnailView(tag, editMode);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Displays the BOTA view, which includes the document outline, bookmarks, and annotation list.
+   * 
+   * @example
+   * await pdfReaderRef.current?.showBotaView();
+   * 
+   * @returns 
+   */
+  showBotaView = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.showBotaView(tag);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Displays the "Add Watermark" view, where users can add watermarks to the document.
+   * 
+   * @example
+   * await pdfReaderRef.current?.showAddWatermarkView();
+   * 
+   * @returns 
+   */
+  showAddWatermarkView = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.showAddWatermarkView(tag);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Displays the document security settings view, allowing users to configure document security options.
+   * 
+   * @example
+   * await pdfReaderRef.current?.showSecurityView();
+   * 
+   * @returns 
+   */
+  showSecurityView = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.showSecurityView(tag);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Displays the display settings view, where users can configure options such as scroll direction, scroll mode, and themes.
+   * 
+   * @example
+   * await pdfReaderRef.current?.showDisplaySettingView();
+   * 
+   * @returns 
+   */
+  showDisplaySettingView = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.showDisplaySettingView(tag);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Enters snip mode, allowing users to capture screenshots.
+   * 
+   * @example
+   * await pdfReaderRef.current?.enterSnipMode();
+   * 
+   * @returns 
+   */
+  enterSnipMode = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.enterSnipMode(tag);
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Exits snip mode, stopping the screenshot capture.
+   * 
+   * @example
+   * await pdfReaderRef.current?.exitSnipMode();
+   * 
+   * @returns 
+   */
+  exitSnipMode = () : Promise<void> => {
+    const tag = findNodeHandle(this._viewerRef);
+    if(tag != null){
+      return CPDFViewManager.exitSnipMode(tag);
+    }
+    return Promise.resolve();
   }
 
   render() {
     return (
       <RCTCPDFReaderView
-        ref={(ref) => {this._viewerRef = ref}}
+        ref={(ref) => {this._setNativeRef(ref)}}
         style={{ flex: 1 }}
         onChange={this.onChange}
         {...this.props}
@@ -249,3 +809,4 @@ export class CPDFReaderView extends PureComponent<CPDFReaderViewProps, any> {
 }
 
 const RCTCPDFReaderView = requireNativeComponent<CPDFReaderViewProps>('RCTCPDFReaderView');
+