\ No newline at end of file
diff --git a/_includes/sidelist-apis.html b/_includes/sidelist-apis.html
index 5bebd70..fa1b80c 100644
--- a/_includes/sidelist-apis.html
+++ b/_includes/sidelist-apis.html
@@ -17,7 +17,6 @@
\ No newline at end of file
diff --git a/_includes/sidelist-features.html b/_includes/sidelist-features.html
index 6dd7105..1157ae9 100644
--- a/_includes/sidelist-features.html
+++ b/_includes/sidelist-features.html
@@ -16,6 +16,7 @@
{% comment %}
diff --git a/api/class/customviewer.md b/_old/api/class/customviewer.md
similarity index 99%
rename from api/class/customviewer.md
rename to _old/api/class/customviewer.md
index ee2a38d..59c9b60 100644
--- a/api/class/customviewer.md
+++ b/_old/api/class/customviewer.md
@@ -7,7 +7,6 @@ title: Dynamsoft Document Viewer API Reference - CustomViewer Class
keywords: Documentation, Dynamsoft Document Viewer, API Reference, CustomViewer Class
breadcrumbText: CustomViewer Class
description: Dynamsoft Document Viewer Documentation API Reference CustomViewer Class Page
-permalink: /api/class/customviewer.html
---
# CustomViewer Class
diff --git a/_v1.1/index.md b/_v1.1/index.md
index d2b9ffb..f4b19d4 100644
--- a/_v1.1/index.md
+++ b/_v1.1/index.md
@@ -10,7 +10,7 @@ description: Dynamsoft Document Viewer Documentation Homepage
- [Introduction]({{site.introduction}}index.html)
- Getting Started
- - [System Requirements]({{ site.gettingstarted }}sys_requirement.html)
+ - [System Requirements]({{ site.gettingstarted }}sys_requirements.html)
- [Adding the dependency]({{ site.gettingstarted }}add_dependency.html)
- [SDK Initialization]({{ site.gettingstarted }}sdk_init.html)
- [Creating HelloWorld]({{ site.gettingstarted }}helloworld.html)
diff --git a/_v2.1/index.md b/_v2.1/index.md
index 9cb1b7c..0e28362 100644
--- a/_v2.1/index.md
+++ b/_v2.1/index.md
@@ -10,7 +10,7 @@ description: Dynamsoft Document Viewer Documentation Homepage
- [Introduction]({{site.introduction}}index.html)
- Getting Started
- - [System Requirements]({{ site.gettingstarted }}sys_requirement.html)
+ - [System Requirements]({{ site.gettingstarted }}sys_requirements.html)
- [Adding the dependency]({{ site.gettingstarted }}add_dependency.html)
- [SDK Initialization]({{ site.gettingstarted }}sdk_init.html)
- [Creating HelloWorld]({{ site.gettingstarted }}helloworld.html)
diff --git a/_v2.1/releasenotes/index.md b/_v2.1/releasenotes/index.md
index 052b951..19e2cdd 100644
--- a/_v2.1/releasenotes/index.md
+++ b/_v2.1/releasenotes/index.md
@@ -223,7 +223,7 @@ Additionally, we've optimized performance and added several new features to enha
### Improved
-- Optimized compatibility with browsers. [>> Detail]({{ site.gettingstarted }}sys_requirement.html#supported-browsers)
+- Optimized compatibility with browsers. [>> Detail]({{ site.gettingstarted }}sys_requirements.html#supported-browsers)
### Added
diff --git a/_v3.2.1/releasenotes/index.md b/_v3.2.1/releasenotes/index.md
index d47e217..22f6867 100644
--- a/_v3.2.1/releasenotes/index.md
+++ b/_v3.2.1/releasenotes/index.md
@@ -331,7 +331,7 @@ Additionally, we've optimized performance and added several new features to enha
### Improved
-- Optimized compatibility with browsers. [>> Detail]({{ site.gettingstarted }}sys_requirement.html#supported-browsers)
+- Optimized compatibility with browsers. [>> Detail]({{ site.gettingstarted }}sys_requirements.html#supported-browsers)
### Added
diff --git a/_v4.0/api/class/annotationmanager.md b/_v4.0/api/class/annotationmanager.md
new file mode 100644
index 0000000..b3479a3
--- /dev/null
+++ b/_v4.0/api/class/annotationmanager.md
@@ -0,0 +1,592 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - AnnotationManager Class
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, AnnotationManager Class
+breadcrumbText: AnnotationManager Class
+description: Dynamsoft Document Viewer Documentation API Reference AnnotationManager Class Page
+---
+
+# AnnotationManager Class
+
+The `Dynamsoft.DDV.annotationManager` instance will be created automatically as soon as DDV is initialized. Please refer to [`annotationManager`]({{ site.api }}namespace/ddv.html#static-annotationmanager).
+
+## API Index
+
+**Methods**
+
+| API Name | Description |
+| ------------------------------ | ------------------------------------------------------------ |
+| [`applyRedactions()`](#applyredactions) | Apply redaction annotations. |
+| [`createAnnotation()`](#createAnnotation) | Create an annotation instance. |
+| [`getAnnotationsByUids()`](#getannotationsbyuids) | Get annotations by annotation uids. |
+| [`getAnnotationsByPage()`](#getannotationsbypage) | Get annotations in specified page. |
+| [`getAnnotationsByDoc()`](#getannotationsbydoc) | Get all annotations in specified document. |
+| [`deleteAnnotations()`](#deleteannotations) | Delete specified annotations. |
+| [`bringAnnotationForward()`](#bringannotationforward) | Bring the specified annotation forward. |
+| [`sendAnnotationBackward()`](#sendannotationbackward) | Send the specified annotation backward. |
+| [`bringAnnotationToFront()`](#bringannotationtofront) | Bring the specified annotation in front of all other annotations. |
+| [`sendAnnotationToBack()`](#sendannotationtoback) | Send the specified annotation behind all other annotations. |
+{% comment %}
+| [`importXfdf()`](#importxfdf) | Import annotations in an XFDF(XML) string to the specified document. |
+| [`exportXfdf()`](#exportxfdf) | Export all annotations from the specified document as an XFDF(XML) string. |
+{% endcomment %}
+
+
+**Events**
+
+| API Name | Description |
+| -------- | -------------------------------------------------- |
+| [`on()`](#on) | Bind a listener to the specified event. |
+| [`off()`](#off) | Unbind event listener(s) from the specified event. |
+
+
+***Integrated Events***
+
+| Event Name | Description |
+| --------------- | ----------------------------------------- |
+| [`annotationsAdded`](#annotationsadded) | Triggered when new annotation(s) is added. |
+| [`annotationsDeleted`](#annotationsdeleted) | Triggered when annotation(s) is deleted. |
+| [`annotationLayerChanged`](#annotationlayerchanged) | Triggered when annotation's layer is changed. |
+| [`annotationsModified`](#annotationsmodified) | Triggered when annotation(s) is modified. |
+
+
+## Methods
+
+### applyRedactions()
+
+Apply redaction annotations.
+
+**Syntax**
+
+```typescript
+applyRedactions(pageUid: string, annotationUids?: string[]): Promise;
+```
+
+**Parameters**
+
+`pageUid`: Specify the page to apply redaction annotations.
+
+`annotationUids`: Specify the array of uids of redaction annotations to apply for one page. If it is empty, all the redaction annotations on the specified page will be used.
+
+**Return value**
+
+A Promise object which indicates whether the operation is successful or not.
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+ -80324 | The specified annotation(s) contain annotations other than redaction annotations.
+ -80325 | The specified page does not contain redaction annotations.
+ -80327 | The specified annotation(s) are not on the specified page or do not exist.
+
+
+### createAnnotation()
+Create an annotation instance and add the created instance to the specified page.
+
+**Syntax**
+
+```typescript
+createAnnotation(pageUid: string, type: K, annotationOptions?: AnnotationsTypeMapOuter[K]["options"]): AnnotationsTypeMapOuter[K]["return"];
+```
+
+**Parameters**
+
+`pageUid`: Specify the page to add the annotation.
+
+`type`: Specify the type of annotation to create.
+```typescript
+type AnnotationType = "rectangle" | "redaction" | "ellipse" | "polygon" | "polyline" | "line" | "ink" | "textBox" | "textTypewriter" | "stamp" | "highlight" | "underline"| "strikeout";
+```
+
+`annotationOptions`: The annotation options. Please refer to [the options list](/api/interface/annotationinterface/index.md#options).
+
+**Return value**
+
+The instance of annotation. Please refer to [Annotation](/api/class/annotation/index.md).
+
+**Code Snippet**
+
+- To creat new annotations.
+
+ ```typescript
+ // Given that editViewer is an existing instance of EditViewer and a document is currently open.
+ const pageUid = editViewer.indexToUid(0);
+
+ const rect = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "rectangle");
+ const ellipse = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "ellipse");
+ const polygon = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "polygon");
+ const polyline = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "polyline");
+ const line = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "line");
+ const ink = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "ink");
+ const textBox = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "textBox");
+ const textTypewriter = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "textTypewriter");
+ const highlight = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "highlight");
+ const underline = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "underline");
+ const strikeout = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "strikeout");
+ const redaction = Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "redaction");
+ const stamp = await Dynamsoft.DDV.annotationManager.createAnnotation(pageUid, "stamp");
+ ```
+
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+ -80328 | Rectangle-type redaction requires exactly one rect.
+
+### getAnnotationsByUids()
+
+Get annotations by annotation uids.
+
+**Syntax**
+
+```typescript
+getAnnotationsByUids(annotationUids: string[]): Annotation[];
+```
+
+**Parameters**
+
+`annotationUids`: The array of the annotation uids.
+
+**Return value**
+
+An array of [Annotation](/api/class/annotation/index.md) objects.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|-----------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | []
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | []
+ -80106 | *XXX(API)*: The specified annotation does not exist.| []
+
+### getAnnotationsByPage()
+
+Get annotations in specified page.
+
+**Syntax**
+
+```typescript
+getAnnotationsByPage(pageUid: string): Annotation[];
+```
+
+**Parameters**
+
+`pageUid`: Specify the page.
+
+**Return value**
+
+An array of [Annotation](/api/class/annotation/index.md) object.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|-----------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | []
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | []
+ -80105 | *XXX(API)*: The specified page(s) do not exist. | []
+
+### getAnnotationsByDoc()
+
+Get all annotations in specified document.
+
+**Syntax**
+
+```typescript
+getAnnotationsByDoc(docUid: string): Annotation[];
+```
+
+`docUid`: Specify the doc.
+
+**Return value**
+
+An array of [Annotation](/api/class/annotation/index.md) objects.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+--------|-----------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | []
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | []
+ -80104 | *XXX(API)*: The specified document(s) do not exist. | []
+
+
+### deleteAnnotations()
+
+Delete specified annotations.
+
+**Syntax**
+
+```typescript
+deleteAnnotations(annotationUids: string[]): boolean;
+```
+
+**Parameters**
+
+`annotationUids`: Specify the array of annotation uids to delete.
+
+**Return value**
+
+`true`
+
+`false`
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|--------------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80106 | *XXX(API)*: The specified annotation does not exist. | `false`
+
+### bringAnnotationForward()
+
+Bring the specified annotation forward.
+
+**Syntax**
+
+```typescript
+bringAnnotationForward(annotationUid: string): boolean;
+```
+
+**Parameters**
+
+`annotationUid`: Specify the annotation uid to bring forward.
+
+**Return value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|--------------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80106 | *XXX(API)*: The specified annotation does not exist. | `false`
+
+### sendAnnotationBackward()
+
+Send the specified annotation backward.
+
+**Syntax**
+
+```typescript
+sendAnnotationBackward(annotationUid: string): boolean;
+```
+
+**Parameters**
+
+`annotationUid`: Specify the annotation uid to send backward.
+
+**Return value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|--------------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80106 | *XXX(API)*: The specified annotation does not exist. | `false`
+
+### bringAnnotationToFront()
+
+Bring the specified annotation in front of all other annotations.
+
+**Syntax**
+
+```typescript
+bringAnnotationToFront(annotationUid: string): boolean;
+```
+
+**Parameters**
+
+`annotationUid`: Specify the annotation uid to bring to front.
+
+**Return value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|--------------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80106 | *XXX(API)*: The specified annotation does not exist. | `false`
+
+### sendAnnotationToBack()
+
+Send the specified annotation behind all other annotations.
+
+**Syntax**
+
+```typescript
+sendAnnotationToBack(annotationUid: string): boolean;
+```
+
+**Parameters**
+
+`annotationUid`: Specify the annotation uid to send to back.
+
+**Return value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|--------------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80106 | *XXX(API)*: The specified annotation does not exist. | `false`
+
+{% comment %}
+### importXfdf()
+
+Import annotations in an XFDF(XML) string to the specified document.
+
+**Syntax**
+
+```typescript
+importXfdf(docUid: string, xfdf: string): Prmoise;
+```
+
+**Parameters**
+
+`docUid`: Specify the document.
+
+`xfdf`: The XFDF(XML) string to import.
+
+**Return value**
+
+An array of imported [Annotation](/api/class/annotation/index.md) objects.
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+
+ **Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
+
+### exportXfdf()
+
+Export all annotations from the specified document as an XFDF(XML) string.
+
+**Syntax**
+
+```typescript
+exportXfdf(docUid: string): Promise;
+```
+
+**Parameters**
+
+`docUid`: Specify the document.
+
+**Return value**
+
+The XFDF(XML) string.
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+
+{% endcomment %}
+
+## Events
+
+### on()
+
+Bind a listener to the specified event.
+
+**Syntax**
+
+```typescript
+on(eventName: EventName, listener:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It should be [an integrated event name](#integrated-events).
+
+`listener`: Specify the listener.
+
+**Code Snippet**
+
+```typescript
+// Bind a listener to the integrated event annotationsModified.
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.modifiedAnnotations[0].uid);
+ console.log(e.modifiedAnnotations[0].newOptions);
+ console.log(e.actions);
+};
+
+Dynamsoft.DDV.annotationManager.on("annotationsModified", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+### off()
+
+Unbind event listener(s) from the specified event.
+
+**Syntax**
+
+```typescript
+off(eventName: EventName, listener?:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It should be [an integrated event name](#integrated-events).
+
+`listener`: Specify the listener. If no listener is specified, unbind all event listeners from the specified event
+
+**Code Snippet**
+
+```typescript
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.modifiedAnnotations[0].uid);
+ console.log(e.modifiedAnnotations[0].newOptions);
+ console.log(e.actions);
+};
+
+Dynamsoft.DDV.annotationManager.on("annotationsModified", eventFunc);
+
+// Unbind the specified event listener.
+Dynamsoft.DDV.annotationManager.off("annotationsModified", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+### Integrated events
+
+#### annotationsAdded
+
+Triggered when new annotation(s) is added.
+
+**Callback**
+
+An EventObject.
+
+**Attributes**
+
+`annotationUids`: The array of new added annotations uids.
+
+#### annotationsDeleted
+
+Triggered when annotation(s) is deleted.
+
+**Callback**
+
+An EventObject.
+
+**Attributes**
+
+`annotationUids`: The array of deleted annotations uids.
+
+#### annotationLayerChanged
+
+Triggered when annotation's layer is changed.
+
+**Callback**
+
+An EventObject.
+
+**Attributes**
+
+`oldAnnotationUidList `: The list of old annotation uids, arranged in hierarchical order from bottom to top for each page.
+
+`newAnnotationUidList`: The list of new annotation uids, arranged in hierarchical order from bottom to top for each page.
+
+#### annotationsModified
+
+Triggered when annotation(s) is modified.
+
+**Callback**
+
+An EventObject.
+
+**Attributes**
+
+`modifiedAnnotations`: The array of the objects which include below properties.
+
+- `uid`: The modified annotation uid.
+- `oldOptions`: The modified annotation old options.
+- `newOptions`: The modified annotation new options.
+
+`actions`: The array of actions. Supported actions:
+
+- `moved`
+- `resized`
+- `rotated`
+- `flagsChanged`
+- `appearanceChanged`
+- `contentChanged`
diff --git a/_v4.0/api/class/captureviewer.md b/_v4.0/api/class/captureviewer.md
new file mode 100644
index 0000000..7b42440
--- /dev/null
+++ b/_v4.0/api/class/captureviewer.md
@@ -0,0 +1,1095 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - CaptureViewer Class
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, CaptureViewer Class
+breadcrumbText: CaptureViewer Class
+description: Dynamsoft Document Viewer Documentation API Reference CaptureViewer Class Page
+---
+
+# CaptureViewer Class
+
+Capture Viewer is used to control camera, play video stream, and capture the images from camera.
+
+## API Index
+
+**Create and Destroy Instances**
+
+| API Name | Description |
+| ------------ | --------------------------------------------- |
+| [`CaptureViewer()`](#captureviewer) | Default constructor of a `CaptureViewer` instance. |
+| [`destroy()`](#destroy) | Destroy the `CaptureViewer` instance. |
+
+**Viewer Control**
+
+| API Name | Description |
+| --------------------- | ------------------------------------------------------------ |
+| [`bindContainer()`](#bindcontainer) | Bind the viewer to the specified container. |
+| [`unbindContainer()`](#unbindcontainer) | Unbind the viewer from the specified container. |
+| [`isBoundContainer`](#isboundcontainer) | Return whether the viewer is bound to a container. |
+| [`getStyle()`](#getstyle) | Get the style object of `CaptureViewer`. |
+| [`updateStyle()`](#updatestyle) | Update the style object of `CaptureViewer`. |
+| [`getUiConfig()`](#getuiconfig) | Get current `UiConfig` object. |
+| [`updateUiConfig()`](#updateuiconfig) | Update `UiConfig` object. |
+| [`show()`](#show) | Show the viewer. |
+| [`hide()`](#hide) | Hide the viewer. |
+| [`isVisible`](#isvisible) | Return whether the viewer is shown or hidden. |
+
+**Document Control**
+
+| API Name | Description |
+| --------------------- | ------------------------------------------------------------ |
+| [`openDocument()`](#opendocument) | Open the specified document by document uid. |
+| [`closeDocument()`](#closedocument) | Close current document. |
+| [`currentDocument`](#currentdocument) | Return the object of the current document. |
+
+**Camera Control**
+
+| API Name | Description |
+| --------------------- | ------------------------------------------------------------ |
+| [`play()`](#play) | Play the camera video stream. |
+| [`stop()`](#stop) | Stop the camera video stream. |
+| [`capture()`](#capture) | Capture a frame from video stream. |
+| [`getAllCameras()`](#getallcameras) | Return information of all available cameras on the device. |
+| [`selectCamera()`](#selectcamera) | Select a camera as the video source. |
+| [`getCurrentCamera()`](#getcurrentcamera) | Return information about the current camera. |
+| [`getCurrentResolution()`](#getcurrentresolution) | Return the resolution of the current video input. |
+| [`turnOnTorch()`](#turnontorch) | Turn on the torch/flashlight if the current camera supports it. |
+| [`turnOffTorch()`](#turnofftorch) | Turn off the torch/flashlight. |
+| [`enableAutoCapture`](#enableautocapture) | Specify or return whether to enable automatic capture. |
+| [`enableAutoDetect`](#enableautodetect) | Specify or return whether to enable automatic border detection in video stream. |
+| [`acceptedPolygonConfidence`](#acceptedpolygonconfidence) | Specify or return the confidence when detecting the border. |
+| [`maxFrameNumber`](#maxframenumber) | Specify or return the maximum number of frames detected per second. |
+
+
+**Events**
+
+| API Name | Description |
+| -------- | -------------------------------------------------- |
+| [`on()`](#on) | Bind a listener to the specified event. |
+| [`off()`](#off) | Unbind event listener(s) from the specified event. |
+
+***Integrated Events***
+
+| Event Name |
+| ------------- |
+| [`resized`](#resized) |
+| [`played`](#played) |
+| [`stopped`](#stopped) |
+| [`captured`](#captured) |
+| [`cameraChanged`](#camerachanged) |
+| [`click`](#click) |
+| [`dblclick`](#dblclick) |
+| [`rightclick`](#rightclick) |
+| [`visibilityChanged`](#visibilitychanged) |
+| [`paginationChanged`](#paginationchanged) |
+
+## Create and Destroy Instances
+
+### CaptureViewer()
+
+Default constructor of a `CaptureViewer` instance.
+
+**Syntax**
+
+```typescript
+new Dynamsoft.DDV.CaptureViewer(options?: CaptureViewerConstructorOptions);
+```
+
+**Parameters**
+
+`options`: The constructor options for a `CaptureViewer` instance. Please refer to [`CaptureViewerConstructorOptions`]({{ site.api }}interface/captureviewerconstructoroptions.html).
+
+**Code Snippet**
+
+```typescript
+const captureViewer = new Dynamsoft.DDV.CaptureViewer({
+ container: document.getElementById("viewer"),
+});
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+
+**Warning**
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------------
+ -80315 | DocumentDetect needs to be configured by Dynamsoft.DDV.setProcessingHandler to enable the document detection feature.
+
+### destroy()
+
+Destroy the `CaptureViewer` instance.
+
+**Syntax**
+
+```typescript
+destroy(): void;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.destroy();
+```
+
+## Viewer Control
+
+### bindContainer()
+
+Bind the viewer to the specified container.
+
+**Syntax**
+
+```typescript
+bindContainer(container: string | HTMLElement): void;
+```
+
+**Parameters**
+
+`container`: The container which is used to show the viewer. Its `id` or `HTMLElement` is acceppted.
+
+**Code Snippet**
+
+```typescript
+// Assume there is a container with id "viewercontainer" on the page.
+captureViewer.bindContainer("viewercontainer");
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80301 | The specified container does not exist.
+
+**Remark**
+
+- A viewer can only be bound to one container at once. If you bind the viewer to another container when it has been bound to a container, the viewer will be bound to the new container and unbound from the old container automatically.
+
+### unbindContainer()
+
+Unbind the viewer from the specified container.
+
+**Syntax**
+
+```typescript
+unbindContainer(): void;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.unbindContainer();
+```
+
+### isBoundContainer
+
+Return whether the viewer is bound to a container.
+
+**Syntax**
+
+```typescript
+readonly isBoundContainer: boolean;
+```
+
+### getStyle()
+
+Get the style object of `CaptureViewer`.
+
+**Syntax**
+
+```typescript
+getStyle(captureViewerStyleName: CaptureViewerStyleName): CaptureViewerStyle | null;
+```
+
+**Parameters**
+
+`captureViewerStyleName`: A `CaptureViewerStyleName` can be one of two types.
+
+```typescript
+type CaptureViewerStyleName = "canvasStyle" | "quadSelectionStyle";
+```
+
+**Return values**
+
+The style object. Please refer to [Style Interfaces]({{ site.api }}interface/styleinterface/index.html).
+
+**Code Snippet**
+
+```typescript
+// Get canvasStyle object;
+const canvasStyle = captureViewer.getStyle("canvasStyle");
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-------------------------------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `null`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `null`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `null`
+
+### updateStyle()
+
+Update the style object of `CaptureViewer`.
+
+**Syntax**
+
+```typescript
+updateStyle(captureViewerStyleName: CaptureViewerStyleName, captureViewerStyle: CaptureViewerStyle): boolean;
+```
+
+**Parameters**
+
+`captureViewerStyleName`: A `CaptureViewerStyleName` can be one of two types.
+
+```typescript
+type CaptureViewerStyleName = "canvasStyle" | "quadSelectionStyle";
+```
+
+`captureViewerStyle`: The style object. Please refer to [Style Interfaces]({{ site.api }}interface/styleinterface/index.html)..
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+- First method
+
+ ```typescript
+ // Get style object;
+ const canvasStyle = captureViewer.getStyle("canvasStyle");
+
+ // Modify the style object.
+ canvasStyle.background = "red";
+ canvasStyle.border = "1px solid green";
+
+ // Update canvas style;
+ captureViewer.updateStyle("canvasStyle", canvasStyle);
+ ```
+
+- Second method
+
+ ```typescript
+ // Update the style object directly
+ captureViewer.updateStyle("canvasStyle", {
+ background: "red",
+ border: "1px solid green",
+ });
+ ```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-------------------------------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `false`
+
+
+**Remark**
+
+- The updates are independent of whether the viewer is displayed and are updated in real time.
+
+### getUiConfig()
+
+Get current `UiConfig` object.
+
+**Syntax**
+
+```typescript
+getUiConfig(): UiConfig;
+```
+
+**Return Value**
+
+The [`UiConfig`]({{ site.api }}interface/uiconfig.html) object.
+
+**Code Snippet**
+
+```typescript
+const viewerUi = captureViewer.getUiConfig();
+```
+
+### updateUiConfig()
+
+Update `UiConfig` object.
+
+**Syntax**
+
+```typescript
+updateUiConfig(uiConfig: UiConfig): boolean;
+```
+
+**Parameters**
+
+`uiConfig`: The [`UiConfig`]({{ site.api }}interface/uiconfig.html) to update.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const viewerUi = Dynamsoft.DDV.getDefaultUiConfig("captureViewer");
+const header = viewerUi.children[0];
+header.children.splice(0,1); //Remove Resolution element
+captureViewer.updateUiConfig(viewerUi);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80313 | The element *XXX(ElementName)* is not supported in *XXX(ClassName)* class. | `false`
+
+**Remark**
+
+- The updates are independent of whether the viewer is displayed and are updated in real time.
+
+### show()
+
+Show the viewer.
+
+**Syntax**
+
+```typescript
+show(): void;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.show();
+```
+
+**Remark**
+
+- The viewer is shown automatically when it is created.
+
+### hide()
+
+Hide the viewer.
+
+**Syntax**
+
+```typescript
+hide(): void;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.hide();
+```
+
+### isVisible
+
+Return whether the viewer is shown or hidden.
+
+**Syntax**
+
+```typescript
+readonly isVisible: boolean;
+```
+
+**Remark**
+
+- The viewer is shown automatically when it is created which means the default value of `isVisible` is `true`.
+
+## Document Control
+
+### openDocument()
+
+Open the specified document.
+
+**Syntax**
+
+```typescript
+openDocument(docUid: string | doc: IDocument): void;
+```
+
+**Parameters**
+
+`docUid`: The uid of the specified document.
+
+`doc`: The object of the document to open. Please refer to [IDocument]({{ site.api }}interface/idocument/index.html).
+
+**Code Snippet**
+
+```typescript
+// Assume there is a document whose id is "lnn0ll9o124".
+captureViewer.openDocument("lnn0ll9o124");
+
+// OR
+// Assume there is a document object firstDoc.
+const docUid = firstDoc.uid;
+captureViewer.openDocument(docUid);
+captureViewer.openDocument(firstDoc);
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: docUid or doc is invalid.
+ -80102 | *XXX(API)*: docUid or doc is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+
+**Remark**
+
+- If another ducument is opened when there is a document already opened, the opened document will be closed automatically.
+- If there are already pages in the opened document, the number of existing pages and the preview image of the last page will appear in the elements `Dynamsoft.DDV.Elements.ImagePreview`.
+
+### closeDocument()
+
+Close current document.
+
+**Syntax**
+
+```typescript
+closeDocument(): boolean;
+```
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+captureViewer.closeDocument();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|--------------------
+ -80304 | No document opened. | `false`
+
+### currentDocument
+
+Return the object of the current document.
+
+**Syntax**
+
+```typescript
+readonly currentDocument: IDocument | null;
+```
+
+**Code Snippet**
+
+```typescript
+const currentDoc = captureViewer.currentDocument;
+```
+
+**See Also**
+
+[IDocument]({{ site.api }}interface/idocument/index.html)
+
+## Camera Control
+
+### play()
+
+Play the camera video stream.
+
+**Syntax**
+
+```typescript
+play(videoConfig?: VideoConfig): Promise;
+```
+
+**Parameter**
+
+`videoConfig`: The object [`VideoConfig`]({{ site.api }}interface/videoconfig.html) which can be used to set resolution, etc.
+
+**Code Snippet**
+
+```typescript
+const captureViewer = new Dynamsoft.DDV.CaptureViewer({
+ container: document.getElementById("viewer"),
+});
+await captureViewer.play({
+ resolution: [1080, 720],
+ fill: true,
+});
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80401 | The specified camera is occupied.
+ -80403 | Not HTTPS, failed to play the video stream.
+ -80405 | No camera available.
+ -80406 | The selected camera is denied by browser.
+
+**Remark**
+
+- The value of `videoConfig` will be remembered and automatically applied the next time `play()` is called, unless another `videoConfig` is specified.
+
+### stop()
+
+Stop the camera video stream.
+
+**Syntax**
+
+```typescript
+stop(): void;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.stop();
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80402 | No video stream is played.
+
+### capture()
+
+Capture a frame from video stream.
+
+**Syntax**
+
+```typescript
+capture(): Promise;
+```
+
+**Return value**
+
+The Blob of the captured image.
+
+**Code Snippet**
+
+```typescript
+const captureViewer = new Dynamsoft.DDV.CaptureViewer({
+ container: document.getElementById("viewer"),
+});
+await captureViewer.play( {
+ resolution: [1080, 720],
+ fill: true,
+});
+
+const capturedPage = await captureViewer.capture();
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80402 | No video stream is played.
+ -80407 | No bound container.
+
+**Remark**
+
+- If there is no document opened while capturing, a new document will be created and opened automatically.
+
+### getAllCameras()
+
+Return information of all available cameras on the device.
+
+**Syntax**
+
+```typescript
+getAllCameras(): Promise;
+```
+
+**Return value**
+
+A promise resolving to an array of [`VideoDeviceInfo`]({{ site.api }}interface/videodeviceinfo.html) objects.
+
+**Code Snippet**
+
+```typescript
+const cameras = await captureViewer.getAllCameras();
+```
+
+### selectCamera()
+
+Select a camera as the video source.
+
+**Syntax**
+
+```typescript
+selectCamera(cameraObjectOrDeviceID: VideoDeviceInfo | string): Promise;
+```
+
+**Parameters**
+
+`cameraObjectOrDeviceID`: Specify the camera by an object [`VideoDeviceInfo`]({{ site.api }}interface/videodeviceinfo.html) or the device id string.
+
+**Return value**
+
+A promise resolving to a [`PlayCallbackInfo`]({{ site.api }}interface/playcallbackinfo.html) object.
+
+**Code Snippet**
+
+```typescript
+const cameras = await captureViewer.getAllCameras();
+if (cameras.length) {
+ await captureViewer.selectCamera(cameras[0]);
+}
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80400 | The specified camera does not exist.
+ -80401 | The specified camera is occupied.
+
+**Remark**
+
+- If called before [`play()`](#play), the selected camera will be used. Otherwise, the system will decide which one to use.
+
+### getCurrentCamera()
+
+Return information about the current camera.
+
+**Syntax**
+
+```typescript
+getCurrentCamera(): VideoDeviceInfo;
+```
+
+**Parameters**
+
+None.
+
+**Return value**
+
+A [`VideoDeviceInfo`]({{ site.api }}interface/videodeviceinfo.html) object with details about the current camera.
+
+**Code Snippet**
+
+```typescript
+const currentCamera = captureViewer.getCurrentCamera();
+console.log("Current camera is "currentCamera.label);
+```
+
+### getCurrentResolution()
+
+Return the resolution of the current video input.
+
+**Syntax**
+
+```typescript
+getCurrentResolution(): [number, number]; //current resolution
+```
+
+**Parameters**
+
+None.
+
+**Return value**
+
+An array of two numbers representing the resolution in the sequence of `[width, height]`.
+
+**Code Snippet**
+
+```typescript
+const currentRes = captureViewer.getCurrentResolution();
+console.log("Current resolution is " + currentRes[0] + " x " + currentRes[1]);
+```
+
+### turnOnTorch()
+
+Turn on the torch/flashlight if the current camera supports it.
+
+**Syntax**
+
+```typescript
+turnOnTorch(): Promise;
+```
+
+**Return value**
+
+A promise that resolves when the operation succeeds.
+
+**Code Snippet**
+
+```typescript
+await captureViewer.turnOnTorch();
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80402 | No video stream is played.
+ -80404 | The camera does not support a flashlight.
+
+**Remark**
+
+- This method should be called when the camera is played.
+- Note that it only works with Chromium-based browsers such as Edge and Chrome on Windows or Android. Other browsers such as Firefox or Safari are not supported.
+- Note that all browsers on iOS (including Chrome) use WebKit as the rendering engine and are not supported.
+
+### turnOffTorch()
+
+Turn off the torch/flashlight.
+
+**Syntax**
+
+```typescript
+turnOffTorch(): Promise;
+```
+
+**Return value**
+
+A promise that resolves when the operation succeeds.
+
+**Code Snippet**
+
+```typescript
+await captureViewer.turnOffTorch();
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80402 | No video stream is played.
+ -80404 | The camera does not support a flashlight.
+
+**Remark**
+
+- This method should be called when the camera is played.
+- Note that it only works with Chromium-based browsers such as Edge and Chrome on Windows or Android. Other browsers such as Firefox or Safari are not supported.
+- Note that all browsers on iOS (including Chrome) use WebKit as the rendering engine and are not supported.
+
+### enableAutoCapture
+
+Specify or return whether to enable automatic capture.
+
+**Syntax**
+
+```typescript
+enableAutoCapture: boolean;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.enableAutoCapture = true;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+
+**Remark**
+
+- If it is not specified in [`viewerConfig`]({{ site.api }}interface/captureviewerconstructoroptions.html#viewerconfig) while creating the viewer additionally, the default value is `false`.
+- If the auto detect is disabled, it will automatically capture a frame every 1 second by default. It can be set by [autoCaptureDelay]({{ site.api }}interface/captureviewerconfig.html#autocapturedelay).
+- If the auto detect is enabled, automatic capturing will only be performed when the detection result meets expectations. See also [`enableAutoDetect`](#enableautodetect).
+
+### enableAutoDetect
+
+Specify or return whether to enable automatic border detection in video stream.
+
+**Syntax**
+
+```typescript
+enableAutoDetect: boolean;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.enableAutoDetect = true;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80315 | DocumentDetect needs to be configured to enable the document detection feature.
+
+**Remark**
+
+- If it is not specified in [`viewerConfig`]({{ site.api }}interface/captureviewerconstructoroptions.html#viewerconfig) while creating the viewer additionally, the default value is `false`.
+- This API only takes effect when [`DocumentDetect`]({{ site.api }}class/advanced/documentdetect.html) is set by [`setProcessingHandler()`]({{ site.api }}namespace/ddv.html#static-setprocessinghandler).
+
+### acceptedPolygonConfidence
+
+Specify or return the threshold confidence level when detecting boundaries.
+
+**Syntax**
+
+```typescript
+acceptedPolygonConfidence: number;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.acceptedPolygonConfidence = 60;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+
+**Remark**
+
+- If it is not specified in [`viewerConfig`]({{ site.api }}interface/captureviewerconstructoroptions.html#viewerconfig) while creating the viewer additionally, the default value is 80.
+- The range of available values is [0,100] on a percentage scale.
+- The higher the setting, the more accurate the automatic border detection.
+
+### maxFrameNumber
+
+Specify or return the maximum number of frames detected per second.
+
+**Syntax**
+
+```typescript
+maxFrameNumber: number;
+```
+
+**Code Snippet**
+
+```typescript
+captureViewer.maxFrameNumber = 3;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+
+**Remark**
+
+- If it is not specified in [`viewerConfig`]({{ site.api }}interface/captureviewerconstructoroptions.html#viewerconfig) while creating the viewer additionally, the default value is 10.
+- The value range is (0,60].
+
+## Events
+
+### on()
+
+Bind a listener to the specified event.
+
+**Syntax**
+
+```typescript
+on(eventName: EventName, listener:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It can be [an integrated event name](#integrated-events) or a custom event name configured through [`UiConfig`-`events`]({{ site.api }}interface/uiconfig.html#events).
+
+`listener`: Specify the listener.
+
+**Code Snippet**
+
+```typescript
+// Bind a listener to the integrated event resized.
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.oldWidth);
+ console.log(e.newWidth);
+};
+
+captureViewer.on("resized", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+
+### off()
+
+Unbind event listener(s) from the specified event.
+
+**Syntax**
+
+```typescript
+off(eventName: EventName, listener?:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It can be [an integrated event name](#integrated-events) or a custom event name configured through [`UiConfig`-`events`]({{ site.api }}interface/uiconfig.html#events).
+
+`listener`: Specify the listener. If no listener is specified, unbind all event listeners from the specified event.
+
+**Code Snippet**
+
+```typescript
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.oldWidth);
+ console.log(e.newWidth);
+};
+
+captureViewer.on("resized", eventFunc);
+
+// Unbind the specified event listener.
+captureViewer.off("resized", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### Integrated Events
+
+#### resized
+
+Triggered when the viewer is resized.
+
+**Callback**
+
+`ResizedEvent`: An EventObject.
+
+**Attributes**
+
+`oldWidth`: The old width of the viewer.
+
+`oldHeight`: The old height of the viewer.
+
+`newWidth`: The new width of the viewer.
+
+`newHeight`: The new height of the viewer.
+
+#### played
+
+Triggered when the camera video stream is played.
+
+**Callback**
+
+`PlayedEvent`: An EventObject.
+
+**Attributes**
+
+`deviceId`: The camera device id.
+
+`resolution`: The resolution used.
+
+#### stopped
+
+Triggered when the camera video stream is stopped.
+
+**Callback**
+
+`StoppedEvent`: An EventObject.
+
+**Attributes**
+
+`deviceId`: The camera device id.
+
+#### captured
+
+Triggered when a frame is captured.
+
+**Callback**
+
+`CapturedEvent`: An EventObject.
+
+**Attributes**
+
+`pageUid`: The pageUid of the captured image.
+
+#### cameraChanged
+
+Triggered when the used camera is changed.
+
+**Callback**
+
+`CameraChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldDeviceId`: The old camera device id.
+
+`newDeviceId`: The new camera device id.
+
+#### paginationChanged
+
+Triggered when the viewer's current page number or the page count is changed. It will return an [`IPaginationChangedEvent`](/api/interface/ipaginationchangedevent.md) object.
+
+#### visibilityChanged
+
+Triggered when the viewer's visibility is changed. It will return an `isVisible` boolean value.
+
+
+#### Mouse Events
+
+##### click
+
+Triggered when click in the viewer's viewing area. On mobile device, triggered when tap in the viewer's viewing area.
+
+##### dblclick
+
+Triggered when double click in the viewer's viewing area.
+
+##### rightclick
+
+Triggered when right click in the viewer's viewing area. On mobile device, triggered when long-tap in the viewer's viewing area.
+
+
+**Callback for mouse events**
+
+ `IPointerEvent`: An EventObject.
+
+**Attributes**
+
+`index`: The page index.
+
+`pageUid`: The page uid.
+
+`imageX`: The relative x-coordinate of the click pointer on the image.
+
+`imageY`: The relative y-coordinate of the click pointer on the image.
+
+`canvasX`: The relative x-coordinate of the click pointer on the canvas.
+
+`canvasY`: The relative x-coordinate of the click pointer on the canvas.
+
+`nativeEvent`: [`PointerEvent`](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent)
\ No newline at end of file
diff --git a/_v4.0/api/class/editviewer.md b/_v4.0/api/class/editviewer.md
new file mode 100644
index 0000000..b108e65
--- /dev/null
+++ b/_v4.0/api/class/editviewer.md
@@ -0,0 +1,1884 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - EditViewer Class
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, EditViewer Class
+breadcrumbText: EditViewer Class
+description: Dynamsoft Document Viewer Documentation API Reference EditViewer Class Page
+---
+
+# EditViewer Class
+
+Edit Viewer is used to edit the pages in document, such as, rotating, cropping, filtering, etc. as well as adjust the layout of the display.
+
+## API Index
+
+**Create and Destroy Instances**
+
+| API Name | Description |
+| ----------------------------- | ------------------------------------------------ |
+| [`EditViewer()`](#editviewer) | Default constructor of an `EditViewer` instance. |
+| [`destroy()`](#destroy) | Destroy the `EditViewer` instance. |
+
+**Viewer Control**
+
+| API Name | Description |
+| --------------------------------------- | ---------------------------------------------------- |
+| [`bindContainer()`](#bindcontainer) | Bind the viewer to the specified container. |
+| [`unbindContainer()`](#unbindcontainer) | Unbind the viewer from the specified container. |
+| [`isBoundContainer`](#isboundcontainer) | Return whether the viewer is bound to a container. |
+| [`getStyle()`](#getstyle) | Get the style object of `EditViewer`. |
+| [`getVisiblePagesInfo()`](#getVisiblePagesInfo) | Get the visible pages info |
+| [`updateStyle()`](#updatestyle) | Update the style object of `EditViewer`. |
+| [`getUiConfig()`](#getuiconfig) | Get current `UiConfig` object. |
+| [`updateUiConfig()`](#updateuiconfig) | Update `UiConfig` object. |
+| [`show()`](#show) | Show the viewer. |
+| [`hide()`](#hide) | Hide the viewer. |
+| [`isVisible`](#isvisible) | Return whether the viewer is shown or hidden. |
+| [`toolMode`](#toolmode) | Specify or return the tool mode of the viewer. |
+| [`annotationMode`](#annotationmode) | Specify or return the annotation mode of the viewer. |
+
+**Document and Page Control**
+
+| API Name | Description |
+| ----------------------------------------------- | ----------------------------------------------- |
+| [`openDocument()`](#opendocument) | Open the specified document by document uid. |
+| [`closeDocument()`](#closedocument) | Close current document. |
+| [`currentDocument`](#currentdocument) | Return the object of the current document. |
+| [`getPageCount()`](#getpagecount) | Get the page count in the viewer. |
+| [`goToPage()`](#gotopage) | Navigate to the specified page by index. |
+| [`getCurrentPageIndex()`](#getcurrentpageindex) | Get the index of current page. |
+| [`getCurrentPageUid()`](#getcurrentpageuid) | Get the uid of the current page. |
+| [`indexToUid()`](#indextouid) | Get the uid of the specified page by its index. |
+| [`uidToIndex()`](#uidtoindex) | Get the index of the specified page by its uid. |
+
+
+**Display Control**
+
+| API Name | Description |
+| ----------------------------------------------------- | -------------------------------------------------- |
+| [`displayMode`](#displaymode) | Specify or return the display mode of the viewer. |
+| [`setParallelScrollCount()`](#setparallelscrollcount) | Specify the number of pages to scroll in parallel. |
+| [`fitMode`](#fitmode) | Specify or return the fit mode of the viewer. |
+| [`zoom`](#zoom) | Specify or return zoom ratio. |
+| [`zoomOrigin`](#zoomorigin) | Specify or return the zoom origin of the viewer. |
+
+**Annotation Control**
+
+| API Name | Description |
+| ----------------------------------------------------------- | ---------------------------------------------------------------- |
+| [`setAnnotationDrawingStyle()`](#setannotationdrawingstyle) | Set the default drawing style of annotations by annotation type. |
+| [`selectAnnotations()`](#selectannotations) | Select the specified annotation(s) on the current page. |
+| [`getSelectedAnnotations()`](#getselectedannotations) | Get selected annotation(s). |
+| [`getAnnotationDrawingStyle()`](#getannotationdrawingstyle) | Get the annotation drawing style(s). |
+
+
+**Edit Operations**
+
+| API Name | Description |
+| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| [`rotate()`](#rotate) | Rotate the specified pages. |
+| [`crop()`](#crop) | Crop the specified page(s) with the specified rectangle. |
+| [`getCropRect()`](#getcroprect) | Get the crop rectangular selection. |
+| [`setCropRect()`](#setcroprect) | Set a crop rectangular selection on the current page. *This method is only available when [`toolMode`](#toolmode) is `crop` mode.* |
+| [`cropMode`](#cropmode) | Get the current mode for cropping: crop the current image or all the images |
+| [`undo()`](#undo) | Undo the last editing operation. |
+| [`redo()`](#redo) | Redo the last undo operation. |
+| [`saveOperations()`](#saveoperations) | Save the edit operations in pages to document. |
+
+**Text Selection**
+
+| API Name | Description |
+| --------------- | -------------------------------------------------- |
+| [`getTextSelection()`](#gettextselection) | Get selected text's detailed info. |
+
+**Search**
+
+| API Name | Description |
+| --------------- | -------------------------------------------------- |
+| [`searchNextText()`](#searchnexttext) | Search the next matched result. |
+| [`searchPrevText()`](#searchprevtext) | Search the previous matched result. |
+| [`searchFullText()`](#searchfulltext) | Search the full text to get all the matched results. |
+
+**Events**
+
+| API Name | Description |
+| --------------- | -------------------------------------------------- |
+| [`on()`](#on) | Bind a listener to the specified event. |
+| [`off()`](#off) | Unbind event listener(s) from the specified event. |
+
+***Integrated Events***
+
+| Event Name |
+| ----------------------------------------------------------- |
+| [`resized`](#resized) |
+| [`pageRendered`](#pagerendered) |
+| [`currentIndexChanged`](#currentindexchanged) |
+| [`currentPageChanged`](#currentpagechanged) |
+| [`displayModeChanged`](#displaymodechanged) |
+| [`fitModeChanged`](#fitmodechanged) |
+| [`zoomChanged`](#zoomchanged) |
+| [`toolModeChanged`](#toolmodechanged) |
+| [`cropRectDrawn`](#croprectdrawn) |
+| [`cropRectDeleted`](#croprectdeleted) |
+| [`cropRectModified`](#croprectmodified) |
+| [`annotationDrawingStyleChanged`](#annotationdrawingstylechanged) |
+| [`selectedAnnotationsChanged`](#selectedannotationschanged) |
+| [`click`](#click) |
+| [`dblclick`](#dbclick) |
+| [`rightclick`](#rightclick) |
+| [`visibilityChanged`](#visibilitychanged) |
+| [`textUnselected`](#textunselected) |
+| [`textSelected`](#textselected) |
+| [`textSearchTriggered`](#textsearchtriggered) |
+| [`undoRedoStateChanged`](#undoredostatechanged) |
+| [`paginationChanged`](#paginationchanged) |
+| [`pointerdown`](#pointerdown) |
+| [`pointerdown`](#pointerdown) |
+| [`pointermove`](#pointermove) |
+| [`pointerup`](#pointerup) |
+| [`pageover`](#pageover) |
+| [`pageout`](#pageout) |
+| [`scroll`](#scroll) |
+
+## Create and Destroy Instances
+
+### EditViewer()
+
+Default constructor of an `EditViewer` instance.
+
+**Syntax**
+
+```typescript
+new Dynamsoft.DDV.EditViewer(options?: EditViewerConstructorOptions);
+```
+
+**Parameters**
+
+`options`: The constructor options for an `EditViewer` instance. Please refer to [`EditViewerConstructorOptions`](/api/interface/editviewerconstructoroptions.md).
+
+**Code Snippet**
+
+```typescript
+const editViewer = new Dynamsoft.DDV.EditViewer({
+ container: document.getElementById("viewer"),
+});
+
+// An IBrowseViewer object will be created at meanwhile. Please refer to Remark part.
+const thumbnailObj = editViewer.thumbnail;
+```
+
+**Exception**
+
+ | Error Code | Error Message |
+ | ---------- | -------------------------------------------------------------------------------------- |
+ | -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. |
+ | -80001 | License string is invalid. |
+ | -80002 | *XXX(LicenseModuleName)* module license has expired. |
+ | -80003 | *XXX(LicenseModuleName)* module license is missing. |
+ | -80004 | *XXX(LicenseModuleName)* module license version does not match. |
+ | -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license. |
+ | -80050 | DDV.Core.init() has not been set up yet. |
+ | -80051 | DDV.Core.init() has not been completed. |
+ | -80302 | minZoom value cannot be larger than maxZoom value. |
+
+**Warning**
+
+ | Error Code | Error Message |
+ | ---------- | ------------------------------------------------------------------------------------------------------------ |
+ | -80316 | ImageFilter needs to be configured by Dynamsoft.DDV.setProcessingHandler to enable the image filter feature. |
+
+**Remark**
+
+- An `IBrowseViewer` object, `editViewer.thumbnail`, will be created at meanwhile which represents the thumbnail object in edit viewer. Please refer to [`IBrowseViewer`]({{ site.api }}interface/ibrowseviewer.html).
+
+### destroy()
+
+Destroy the `EditViewer` instance.
+
+**Syntax**
+
+```typescript
+destroy(): void;
+```
+
+**Code Snippet**
+
+```typescript
+editViewer.destroy();
+```
+
+**Remark**
+
+- The editing operations (rotating, cropping, filtering) in pages will be saved to document automatically when destroy the viewer instance.
+
+**See Also**
+
+[saveOperations](#saveoperations)
+
+## Viewer Control
+
+### bindContainer()
+
+Bind the viewer to the specified container.
+
+**Syntax**
+
+```typescript
+bindContainer(container: string | HTMLElement): void;
+```
+
+**Parameters**
+
+`container`: The container which is used to show the viewer. Its `id` or `HTMLElement` is acceppted.
+
+**Code Snippet**
+
+```typescript
+// Assume there is a container with id "viewercontainer" on the page.
+editViewer.bindContainer("viewercontainer");
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80301 | The specified container does not exist.
+
+**Remark**
+
+- A viewer can only be bound to one container at once. If you bind the viewer to another container when it has been bound to a container, the viewer will be bound to the new container and unbound from the old container automatically.
+
+### unbindContainer()
+
+Unbind the viewer from the specified container.
+
+**Syntax**
+
+```typescript
+unbindContainer(): void;
+```
+
+**Code Snippet**
+
+```typescript
+editViewer.unbindContainer();
+```
+
+### isBoundContainer
+
+Return whether the viewer is bound to a container.
+
+**Syntax**
+
+```typescript
+readonly isBoundContainer: boolean;
+```
+
+### getStyle()
+
+Get the style object of `EditViewer`.
+
+**Syntax**
+
+```typescript
+getStyle(editViewerStyleName: EditViewerStyleName): EditViewerStyle | null;
+```
+
+**Parameters**
+
+`editViewerStyleName`: An `EditViewerStyleName` can be one of five types.
+
+```typescript
+type EditViewerStyleName = "canvasStyle" | "pageStyle" | "currentPageStyle" | "quadSelectionStyle" | "annotationSelectionStyle";
+```
+
+**Return values**
+
+The style object. Please refer to [Style Interfaces]({{ site.api }}interface/styleinterface/index.html)..
+
+**Code Snippet**
+
+```typescript
+// Get pageStyle object;
+const pageStyle = editViewer.getStyle("pageStyle");
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-------------------------------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `null`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `null`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `null`
+
+### getVisiblePagesInfo()
+
+Get the visible pages info.
+
+**Syntax**
+
+```typescript
+getVisiblePagesInfo(): PageVisualInfo[];
+```
+
+**Return values**
+
+Array of the `PageVisualInfo` object. Please refer to [`PageVisualInfo`](/api/interface/pagevisualinfo.md).
+
+### updateStyle()
+
+Update the style object of `EditViewer`.
+
+**Syntax**
+
+```typescript
+updateStyle(editViewerStyleName: EditViewerStyleName, editViewerStyle: EditViewerStyle): boolean;
+```
+
+**Parameters**
+
+`editViewerStyleName`: An `EditViewerStyleName` can be one of five types.
+
+```typescript
+type EditViewerStyleName = "canvasStyle" | "pageStyle" | "currentPageStyle" | "quadSelectionStyle" | "annotationSelectionStyle";
+```
+
+`editViewerStyle`: The style object. Please refer to [Style Interfaces]({{ site.api }}interface/styleinterface/index.html).
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+- First method
+
+ ```typescript
+ // Get style object
+ const pageStyle = editViewer.getStyle("pageStyle");
+
+ // Modify the style object
+ pageStyle.background = "red";
+ pageStyle.border = "1px solid green";
+
+ // Update page style
+ editViewer.updateStyle("pageStyle", pageStyle);
+ ```
+
+- Second method
+
+ ```typescript
+ // Update the style object directly
+ editViewer.updateStyle("pageStyle", {
+ background: "red",
+ border: "1px solid green",
+ });
+ ```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-------------------------------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `false`
+
+
+**Remark**
+
+- The updates are independent of whether the viewer is displayed and are updated in real time.
+
+### getUiConfig()
+
+Get current `UiConfig` object.
+
+**Syntax**
+
+```typescript
+getUiConfig(): UiConfig;
+```
+
+**Return Value**
+
+The [`UiConfig`]({{ site.api }}interface/uiconfig.html) object.
+
+**Code Snippet**
+
+```typescript
+const viewerUi = editViewer.getUiConfig();
+```
+
+### updateUiConfig()
+
+Update `UiConfig` object.
+
+**Syntax**
+
+```typescript
+updateUiConfig(uiConfig: UiConfig): boolean;
+```
+
+**Parameters**
+
+`uiConfig`: The [`UiConfig`]({{ site.api }}interface/uiconfig.html) to update.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const viewerUi = Dynamsoft.DDV.getDefaultUiConfig("editViewer");
+const header = viewerUi.children[0];
+header.children.splice(0,0,Dynamsoft.DDV.Elements.Delete); //Add `Delete` element in header.
+editViewer.updateUiConfig(viewerUi);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80313 | The element *XXX(ElementName)* is not supported in *XXX(ClassName)* class. | `false`
+
+**Remark**
+
+- The updates are independent of whether the viewer is displayed and are updated in real time.
+
+### show()
+
+Show the viewer.
+
+**Syntax**
+
+```typescript
+show(): void;
+```
+
+**Code Snippet**
+
+```typescript
+editViewer.show();
+```
+
+**Remark**
+
+- The viewer is shown automatically when it is created.
+
+### hide()
+
+Hide the viewer.
+
+**Syntax**
+
+```typescript
+hide(): void;
+```
+
+**Code Snippet**
+
+```typescript
+editViewer.hide();
+```
+
+### isVisible
+
+Return whether the viewer is shown or hidden.
+
+**Syntax**
+
+```typescript
+readonly isVisible: boolean;
+```
+
+**Remark**
+
+- The viewer is shown automatically when it is created which means the default value of `isVisible` is `true`.
+
+### toolMode
+
+Specify or return the tool mode of the viewer.
+
+**Syntax**
+
+```typescript
+toolMode: ToolMode;
+```
+
+A `ToolMode` can be one of following types.
+
+```typescript
+type ToolMode = "pan" | "crop" | "annotation" | "textSelection" | "redaction";
+```
+
+`pan`: The default tool mode.
+
+`crop`: A mode what allows drawing a rectangle by [`setCropRect()`](#setcroprect).
+
+`annotation`: A mode that allows creating annotations to be manipulated via the UI.
+
+`textSelection`: A mode that allows selecting text to be manipulated via the UI.
+
+`redaction`: A mode that allows marking areas or pages for redaction.
+
+**Code Snippet**
+
+```typescript
+editViewer.toolMode = "crop";
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+**Remark**
+
+- If `toolMode` is set to `annotation`, can use [`annotationMode`](#annotationmode) to clarify the specific operation.
+
+### annotationMode
+
+Specify or return the annotation mode of the viewer.
+
+**Syntax**
+
+```typescript
+annotationMode: AnnotationMode;
+```
+
+An `AnnotationMode` can be one of following types.
+
+```typescript
+type AnnotationMode = "select" | "erase" | "rectangle" | "ellipse" | "line" | "polygon" | "polyline" | "ink" | "textBox" | "textTypewriter" | "stamp" | "highlight" | "strikeout" | "underline";
+```
+
+**Code Snippet**
+
+```typescript
+editViewer.toolMode = "annotation";
+editViewer.annotationMode = "select";
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+**Remark**
+
+- It only take effect when [`toolMode`](#toolmode) is `annotation`.
+- Default value is `select`.
+- When `enableContinuousDrawing` is false, please note that the `toolMode` will automatically switch to `pan` after completing an annotation drawing interaction, unless the `annotationMode` is set to `select`, `erase`, or `ink` mode.
+
+## Document and Page Control
+
+### openDocument()
+
+Open the specified document.
+
+**Syntax**
+
+```typescript
+openDocument(docUid: string | doc: IDocument): void;
+```
+
+**Parameters**
+
+`docUid`: The uid of the specified document.
+
+`doc`: The object of the document to open. Please refer to [IDocument]({{ site.api }}interface/idocument/index.html).
+
+**Code Snippet**
+
+```typescript
+// Assume there is a document whose id is "lnn0ll9o124".
+editViewer.openDocument("lnn0ll9o124");
+
+// OR
+// Assume there is a document object firstDoc.
+const docUid = firstDoc.uid;
+editViewer.openDocument(docUid);
+editViewer.openDocument(firstDoc);
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: docUid or doc is invalid.
+ -80102 | *XXX(API)*: docUid or doc is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+
+**Remark**
+
+- If another ducument is opened when there is a document already opened, the opened document will be closed automatically.
+
+### closeDocument()
+
+Close current document.
+
+**Syntax**
+
+```typescript
+closeDocument(): boolean;
+```
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+editViewer.closeDocument();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|--------------------
+ -80304 | No document opened. | `false`
+
+### currentDocument
+
+Return the object of the current document.
+
+**Syntax**
+
+```typescript
+readonly currentDocument: IDocument | null;
+```
+
+**Code Snippet**
+
+```typescript
+const currentDoc = editViewer.currentDocument;
+```
+
+**See Also**
+
+[IDocument]({{ site.api }}interface/idocument/index.html)
+
+### getPageCount()
+
+Get the page count in the viewer.
+
+**Syntax**
+
+```typescript
+getPageCount(): number;
+```
+
+**Return Value**
+
+The page count.
+
+**Code Snippet**
+
+```typescript
+const pageCount = editViewer.getPageCount();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|--------------------
+ -80304 | No document opened. | `-1`
+
+### goToPage()
+
+Navigate to the specified page by index.
+
+**Syntax**
+
+```typescript
+goToPage(index: number): number;
+```
+
+**Parameters**
+
+`index`: The index of the page which need to navigate to.
+
+**Return Value**
+
+The index of the page which navigate to.
+
+**Code Snippet**
+
+```typescript
+// Navigate to page 4.
+editViewer.goToPage(3);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|----------------------------------------------------------|------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `-1`
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range. | `-1`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `-1`
+ -80304 | No document opened. | `-1`
+ -80305 | There is no image in the current document. | `-1`
+
+### getCurrentPageIndex()
+
+Get the index of the current page.
+
+**Syntax**
+
+```typescript
+getCurrentPageIndex(): number;
+```
+
+**Return Value**
+
+The index of the current page.
+
+**Code Snippet**
+
+```typescript
+const currentIndex = editViewer.getCurrentPageIndex();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|--------------------
+ -80304 | No document opened. | `-1`
+ -80305 | There is no image in the current document. | `-1`
+
+### getCurrentPageUid()
+
+Get the uid of the current page.
+
+**Syntax**
+
+```typescript
+getCurrentPageUid(): string;
+```
+
+**Return Value**
+
+The uid of the current page.
+
+**Code Snippet**
+
+```typescript
+const curPageUid = editViewer.getCurrentPageUid();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|--------------------
+ -80304 | No document opened. | `''`
+ -80305 | There is no image in the current document. | `''`
+
+### indexToUid()
+
+Get the uid of the specified page by its index.
+
+**Syntax**
+
+```typescript
+indexToUid(index: number): string;
+```
+
+**Parameters**
+
+`index`: The index of the specified page.
+
+**Return Value**
+
+The uid of the page.
+
+**Code Snippet**
+
+```typescript
+// Get the first page's uid
+const firstPageUid = editViewer.indexToUid(0);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|----------------------------------------------------------|------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `''`
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range. | `''`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `''`
+ -80304 | No document opened. | `''`
+ -80305 | There is no image in the current document. | `''`
+
+### uidToIndex()
+
+Get the index of the specified page by its uid.
+
+**Syntax**
+
+```typescript
+uidToIndex(pageUid: string): number;
+```
+
+**Parameters**
+
+`pageUid`: The uid of the specified page.
+
+**Return Value**
+
+The index of the page.
+
+**Code Snippet**
+
+```typescript
+const curPageUid = editViewer.getCurrentPageUid();
+editViewer.uidToIndex(curPageUid);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|----------------------------------------------------------|------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `-1`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `-1`
+ -80105 | *XXX(API)*: The specified page(s) do not exist. | `-1`
+ -80304 | No document opened. | `-1`
+ -80305 | There is no image in the current document. | `-1`
+
+## Annotation Control
+
+### setAnnotationDrawingStyle()
+
+Set the default drawing style of annotations by annotation type.
+
+**Syntax**
+
+```typescript
+setAnnotationDrawingStyle(config: AnnotationDrawingStyleConfig): boolean;
+```
+
+**Parameters**
+
+`config`: Specifies the default drawing style of each stamp type provided. See [`AnnotationDrawingStyleConfig`]({{ site.api }}interface/styleinterface/annotationdrawingstyleconfig.html) for details.
+
+**Return value**
+
+`true`: Successfully set the specified default drawing styles.
+
+`false`: Failed to set the specified default drawing styles.
+
+**Warning**
+
+ | Error Code | Error Message | API return value |
+ | ---------- | -------------------------------------------- | ---------------- |
+ | -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false` |
+ | -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false` |
+
+### selectAnnotations()
+
+Select the specified annotations on the current page.
+
+**Syntax**
+
+```typescript
+selectAnnotations(annotationUids: string[]): boolean;
+```
+
+**Parameters**
+
+`annotationUids`: Specify the array of annotation uids to select. If set to `[]`, no annotation will be selected.
+
+**Return value**
+
+`true`: Selected the specified annotations.
+
+`false`: Failed to select the specified annotations.
+
+
+**Warning**
+
+ | Error Code | Error Message | API return value |
+ | ---------- | ------------------------------------------------------------------------- | ---------------- |
+ | -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false` |
+ | -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false` |
+ | -80304 | No document opened. | `false` |
+ | -80305 | There is no image in the current document. | `false` |
+ | -80314 | *XXX(API)*: Not available in current toolMode. | `false` |
+ | -80317 | The specified annotation(s) is not on the current page or does not exist. | `false` |
+ | -80319 | ReadOnly annotation or noView annotation cannot be selected. | `false` |
+ | -80320 | Unknown annotation or incomplete annotation cannot be selected. | `false` |
+ | -80321 | Flattened annotation cannot be selected. | `false` |
+
+### getSelectedAnnotations()
+
+Get selected annotation(s).
+
+**Syntax**
+
+```typescript
+getSelectedAnnotations(): Annotation[];
+```
+
+**Return value**
+
+An array of selected `Annotation` object.
+
+**Code Snippet**
+
+```typescript
+const selectAnnots = editViewer.getSelectAnnotations();
+```
+
+**Warning**
+
+ Error Code | Error Message | API return value
+ ---------- | ------------------------------------------------------------|---------
+ -80304 | No document opened. | `[]`
+ -80305 | There is no image in the current document. | `[]`
+
+### getAnnotationDrawingStyle()
+
+Get the annotation drawing style.
+
+**Syntax**
+
+```typescript
+getAnnotationDrawingStyle(): AnnotationDrawingStyleConfig;
+```
+
+**Return value**
+
+An [`AnnotationDrawingStyleConfig`](/api/interface/styleinterface/annotationdrawingstyleconfig.md) object.
+
+
+## Display Control
+
+### displayMode
+
+Specify or return the display mode of the viewer.
+
+**Syntax**
+
+```typescript
+displayMode: DisplayMode;
+```
+
+A `DisplayMode` can be one of two types.
+
+```typescript
+type DisplayMode = "single" | "continuous";
+```
+
+`single`: The pages in the viewer is displayed page by page.
+
+`continuous`: The pages in the viewer is displayed continuously.
+
+**Code Snippet**
+
+```typescript
+editViewer.displayMode = "single";
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+**Remark**
+
+- Default `displayMode` is `continuous`.
+- When `displayMode` is `continuous`, the default number of pages to scroll in parallel is 1 and which can be configure by [`setParallelScrollCount`](#setparallelscrollcount).
+
+### setParallelScrollCount()
+
+Specify the number of pages to scroll in parallel.
+
+**Syntax**
+
+```typescript
+setParallelScrollCount(count: number): boolean;
+```
+**Parameters**
+
+`count`: The number of pages to scroll in parallel. The maximum value is 20.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+// Set three pages to scroll in parallel
+editViewer.setParallelScrollCount(3);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|--------------------------------------------------------------|--------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80308 | EditViewer.setParallelScrollCount: Not available in current displayMode. | `false`
+
+**Remark**
+
+- The setting will be applied when [`displayMode`](#displaymode) is `continuous` mode.
+
+### fitMode
+
+Specify or return the fit mode of the viewer.
+
+**Syntax**
+
+```typescript
+fitMode: FitMode;
+```
+
+A `FitMode` can be one of four types.
+
+```typescript
+type FitMode = "width" | "height" | "window" | "actualSize";
+```
+
+`width`: The page is displayed to fit the width.
+
+`height`: The page is displayed to fit the height.
+
+`window`: The page is displayed to fit the window.
+
+`actualSize`: The page is displayed at its actual size, equal to [`zoom`](#zoom) set to 1.
+
+**Code Snippet**
+
+```typescript
+editViewer.fitMode = "width";
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+**Remark**
+
+- The default `fitMode` is `window`, which means fit window.
+- Since the specified `fitMode` is calculated by zoom ratio, if the zoom ratio which set by `zoom` does not match any of `fitMode`, the page will be displayed in specified zoom ratio and `fitMode` will return `none`.
+
+### zoom
+
+Specify or return zoom ratio.
+
+**Syntax**
+
+```typescript
+zoom: number;
+```
+
+**Code Snippet**
+
+```typescript
+//Actual size
+editViewer.zoom = 1;
+
+//Twice the actual size
+editViewer.zoom = 2;
+
+//10% the actual size
+editViewer.zoom = 0.1;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80306 | The value for zoom is larger than maxZoom value.
+ -80307 | The value for zoom is smaller than minZoom value.
+
+**Remark**
+
+- The interval of available values depends on `minZoom` and `maxZoom` which is set in [EditViewerConfig](#editviewerconfig) when create `EditViewer` object.
+- 1 means actual size of the page and equals to `actualSize` in [`fitMode`](#fitmode).
+- Return value will be rounded to four decimal places.
+
+### zoomOrigin
+
+Specify or return the zoom origin of the viewer.
+
+**Syntax**
+
+```typescript
+zoomOrigin: ZoomOrigin;
+```
+
+**Code Snippet**
+
+```typescript
+// Set the zoom origin to upper left
+const newZoomOrigin = {
+ x: "start",
+ y: "start",
+};
+
+editViewer.zoomOrigin = newZoomOrigin;
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+
+**Remark**
+
+- The default zoomOrigin is center point of the viewer.
+
+**See Also**
+
+[`ZoomOrigin`]({{ site.api }}interface/zoomorigin.html)
+
+## Edit Operations
+
+### rotate()
+
+Rotate the specified pages.
+
+**Syntax**
+
+```typescript
+rotate(
+ angle: number,
+ indices?: number[]
+): boolean;
+```
+
+**Parameters**
+
+`angle`: Specify the angle. Only multiples of 90 degrees are supported. Positive value means clockwise rotation, negative value means counterclockwise rotation.
+
+`indices`: The array of the pages indices which will be rotated. If not set, the current page will be rotated.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+// Rotate the first and second pages 90 degrees clockwise.
+editViewer.rotate(90, [0,1]);
+
+// Rotate current page 90 degrees counterclockwise.
+editViewer.rotate(-90);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-------------------------------------------------------------------------|-------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `false`
+ -80304 | No document opened. | `false`
+ -80305 | There is no image in the current document. | `false`
+
+### crop()
+
+Crop the specified page(s) with the specified rectangle.
+
+**Syntax**
+
+```typescript
+crop(
+ rect: Rect,
+ indices?: number[]
+): boolean;
+```
+**Parameters**
+
+`rect`: Specify the rectangle. Please refer to [`Rect`]({{ site.api }}interface/rect.html).
+
+`indices`: Specify the indices of the pages to be cropped. If not set, it will crop based on [`cropMode`](#cropmode), which uses the current image if the mode is `current` and all the images if the mode is `all`.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const rect = {
+ left: 100,
+ top: 100,
+ width: 200,
+ height: 200,
+};
+
+editViewer.crop(rect, [0]); // Crop the first page
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|------------------------------------------------------------|-------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80304 | No document opened. | `false`
+ -80305 | There is no image in the current document. | `false`
+ -80309 | The specified rect exceeds the bounds of page index *X(IndexNum)*. | `false`
+
+**Remark**
+
+If one of the points of the rectangle is out of page range, crop operation does not take effect in this page and report warning.
+
+
+### cropMode
+
+Get or set the current mode for cropping: crop the current image or all the images.
+
+**Syntax**
+
+```typescript
+cropMode: CropMode;
+```
+
+It can be one of the two types.
+
+```typescript
+type CropMode = "current" | "all";
+```
+
+### getCropRect()
+
+Get the crop rectangular selection.
+
+**Syntax**
+
+```typescript
+getCropRect(): Rect | null;
+```
+
+**Return Value**
+
+The rectangular selection. Please refer to [`Rect`]({{ site.api }}interface/rect.html).
+
+**Code Snippet**
+
+```typescript
+editViewer.getCropRect();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------------|---------------------
+-80304 | No document opened. | `null`
+
+**Remark**
+
+- If there is no crop rectangular selection, returns `null`.
+
+### setCropRect()
+
+> *This method is only available when [`toolMode`](#toolmode) is `crop` mode.*
+
+Set a crop rectangular selection on the current page.
+
+**Syntax**
+
+```typescript
+setCropRect(rect: Rect): boolean;
+```
+
+**Parameters**
+
+`rect`: Specify the rectangular selection. Please refer to [`Rect`]({{ site.api }}interface/rect.html).
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+editViewer.toolMode = "crop"; // Set toolMode to "crop"
+
+const rect = {
+ left: 100,
+ top: 100,
+ width: 200,
+ height: 200,
+};
+
+editViewer.setCropRect(rect);
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------------|-------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+ -80304 | No document opened. | `false`
+ -80305 | There is no image in the current document. | `false`
+ -80309 | The specified rect exceeds the bounds of page index *X(IndexNum)*. | `false`
+ -80314 | *XXX(API)*: Not available in current toolMode. | `false`
+
+**Remark**
+
+- In the viewer, only one rectangular selection can exist on the page at a time, which means if there is a rectangular selection existed when a new selection is drawn, the old one will be clear automatically.
+- When [`toolMode`](#toolmode) is set to `pan`, the drawn rectangular selection will be clear.
+
+### undo()
+
+> *This method takes effect only for [crop](#crop), [rotate](#rotate) operations.*
+
+Undo the last editing operation.
+
+**Syntax**
+
+```typescript
+undo(): boolean;
+```
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+editViewer.undo();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|-----------------
+ -80304 | No document opened. | `false`
+ -80310 | No operations to undo. | `false`
+
+### redo()
+
+> *This method takes effect only for [crop](#crop), [rotate](#rotate) operations.*
+
+Redo the last undo operation.
+
+**Syntax**
+
+```typescript
+redo(): boolean;
+```
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+editViewer.redo();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|-----------------
+ -80304 | No document opened. | `false`
+ -80311 | No operations to redo. | `false`
+
+### saveOperations()
+
+> *This method takes effect only for [crop](#crop), [rotate](#rotate) & filter(which is operated by using UI Element) operations.*
+
+Save the edit operations in pages to document.
+
+**Syntax**
+
+```typescript
+saveOperations(): boolean;
+```
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+editViewer.saveOperations();
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|-----------------------------------------------------|-----------------
+ -80304 | No document opened. | `false`
+
+## Text Selection
+
+### getTextSelection()
+
+Get selected text's detailed info.
+
+**Syntax**
+
+```typescript
+getTextSelection(): ITextSelectedInfo[];
+```
+
+**Return values**
+
+Array of the `ITextSelectedInfo` object. Please refer to [`ITextSelectedInfo`](/api/interface/itextselectedinfo.md).
+
+## Search
+
+### searchNextText()
+
+Search the next matched result.
+
+**Syntax**
+
+```typescript
+searchNextText(text: string, options?: SearchTextOptions): Promise;
+```
+
+**Parameters**
+
+* `text`: text to search
+* `options`: Please refer to [`SearchTextOptions`](/api/interface/searchtextoptions.md)
+
+**Warnings**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+ -80304 | No document opened.
+ -80305 | There is no image in the current document.
+ -80322 | No results found.
+
+### searchPrevText()
+
+Search the previous matched result.
+
+**Syntax**
+
+```typescript
+searchPrevText(text: string, options?: SearchTextOptions): Promise;
+```
+
+**Parameters**
+
+* `text`: text to search
+* `options`: Please refer to [`SearchTextOptions`](/api/interface/searchtextoptions.md)
+
+**Warnings**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+ -80304 | No document opened.
+ -80305 | There is no image in the current document.
+ -80322 | No results found.
+
+### searchFullText()
+
+Search the full text to get all the matched results.
+
+**Syntax**
+
+```typescript
+searchFullText(text: string, options?: SearchTextOptions): Promise;
+```
+
+**Parameters**
+
+* `text`: text to search
+* `options`: Please refer to [`SearchTextOptions`](/api/interface/searchtextoptions.md)
+
+**Warnings**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+ -80304 | No document opened.
+ -80305 | There is no image in the current document.
+ -80322 | No results found.
+
+## Events
+
+### on()
+
+Bind a listener to the specified event.
+
+**Syntax**
+
+```typescript
+on(eventName: EventName, listener:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It can be [an integrated event name](#integrated-events) or a custom event name configured through [`UiConfig`-`events`]({{ site.api }}interface/uiconfig.html#events).
+
+`listener`: Specify the listener.
+
+**Code Snippet**
+
+```typescript
+// Bind a listener to the integrated event resized.
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.oldWidth);
+ console.log(e.newWidth);
+};
+
+editViewer.on("resized", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+
+### off()
+
+Unbind event listener(s) from the specified event.
+
+**Syntax**
+
+```typescript
+off(eventName: EventName, listener?:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It can be [an integrated event name](#integrated-events) or a custom event name configured through [`UiConfig`-`events`]({{ site.api }}interface/uiconfig.html#events).
+
+`listener`: Specify the listener. If no listener is specified, unbind all event listeners from the specified event.
+
+**Code Snippet**
+
+```typescript
+const eventFunc = (e)=>{
+ console.log(e);
+ console.log(e.oldWidth);
+ console.log(e.newWidth);
+};
+
+editViewer.on("resized", eventFunc);
+
+// Unbind the specified event listener.
+editViewer.off("resized", eventFunc);
+```
+
+**Warning**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### Integrated Events
+
+#### resized
+
+Triggered when the viewer is resized.
+
+**Callback**
+
+`ResizedEvent`: An EventObject.
+
+**Attributes**
+
+`oldWidth`: The old width of the viewer.
+
+`oldHeight`: The old height of the viewer.
+
+`newWidth`: The new width of the viewer.
+
+`newHeight`: The new height of the viewer.
+
+#### pageRendered
+
+Triggered when a page has been completely rendered. We only render the pages that are visible on the screen, so this event won't get fired for every page in the document at once. This event will get called when the user scrolls up and down the document, or when a page is zoomed or rotated, or anything else that makes it rerender.
+
+**Callback**
+
+`PageRenderedEvent`: An EventObject.
+
+**Attributes**
+
+`index`: The index of the rendered page.
+
+`pageUid`: The pageUid of the rendered page.
+
+#### currentIndexChanged
+
+Triggered when currentIndex is changed.
+
+**Callback**
+
+`CurrentindexChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldIndex`: The old current index.
+
+`newIndex`: The new current index. If there is no index in the viewer, return `-1`.
+
+#### currentPageChanged
+
+Triggered when current page is changed.
+
+**Callback**
+
+`CurrentPageChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldPageUid`: The uid of the page which is old current index. If the old page is removed, return `''`.
+
+`newPageUid`: The uid of the page which is new current index. If there is no index in the viewer, return `''`.
+
+#### displayModeChanged
+
+Triggered when the display mode is changed.
+
+**Callback**
+
+`DisplayModeChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldDisplayMode`: The old display mode.
+
+`newDisplayMode`: The new display mode.
+
+#### fitModeChanged
+
+Triggered when the fit mode has changed.
+
+**Callback**
+
+`FitModeChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldFitMode`: The old fit mode.
+
+`newFitmode`: The new fit mode.
+
+#### zoomChanged
+
+Triggered when the zoom ratio has been changed.
+
+**Callback**
+
+`ZoomChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldZoomRatio`: The old zoom ratio.
+
+`newZoomRatio`: The new zoom ratio.
+
+#### toolModeChanged
+
+Triggered when the tool mode has changed.
+
+**Callback**
+
+`ToolModeChangedEvent`: An EventObject.
+
+**Attributes**
+
+`oldToolMode`: The old tool mode.
+
+`newToolMode`: The new tool mode.
+
+#### cropRectDrawn
+
+Triggered when a rectangular selection is drawn.
+
+**Callback**
+
+`CropRectDrawnEvent`: An EventObject.
+
+**Attributes**
+
+`rect`: The drawn rectangle.
+
+#### cropRectDeleted
+
+Triggered when the rectangular selection is deleted.
+
+**Callback**
+
+`CropRectDeletedEvent`: An EventObject.
+
+**Attributes**
+
+`rect`: The deleted rectangle.
+
+#### cropRectModified
+
+Triggered when the crop rectangular selection is modified.
+
+**Callback**
+
+`CropRectModifiedEvent`: An EventObject.
+
+**Attributes**
+
+`oldRect`: The old rectangle.
+
+`newRect`: The new rectangle.
+
+#### annotationDrawingStyleChanged
+
+Triggered when the annotation drawing style is changed. It will return the old drawing style and the new drawing style of the selected annotation. See also [`AnnotationDrawingStyleConfig`](/api/interface/styleinterface/annotationdrawingstyleconfig.md).
+
+#### selectedAnnotationsChanged
+
+Triggered when selected annotation(s) is changed.
+
+**Callback**
+
+`SelectedAnnotationsChanged`: An EventObject.
+
+**Attributes**
+
+`oldAnnotationUids`: The array of old selected annotations uids.
+
+`newAnnotationUids`: The array of new selected annotations uids.
+
+#### visibilityChanged
+
+Triggered when the viewer's visibility is changed. It will return an `isVisible` boolean value.
+
+#### textSelected
+
+Triggered when text is selected. It will return an array of [`ITextSelectedInfo`](/api/interface/itextselectedinfo.md).
+
+#### textUnselected
+
+Triggered when text is unselected.
+
+#### textSearchTriggered
+
+Triggered when text search is performed. It will return an array of [`ITextSearchedInfo`](/api/interface/itextsearchedinfo.md).
+
+
+
+#### undoRedoStateChanged
+
+Triggered when the viewer's undo and redo state is changed. It will return an [`IUndoRedoStateChangedEvent`](/api/interface/iundoredostatechangedevent.md) object.
+
+#### paginationChanged
+
+Triggered when the viewer's current page number or the page count is changed. It will return an [`IPaginationChangedEvent`](/api/interface/ipaginationchangedevent.md) object.
+
+#### pointerdown
+
+Triggered when a pointer becomes active buttons state. It will return an [`IPointerEvent`](/api/interface/ipointerevent.md) object.
+
+#### pointermove
+
+Triggered when a pointer changes coordinates. It will return an [`IPointerEvent`](/api/interface/ipointerevent.md) object.
+
+#### pointerup
+
+Triggered when a pointer is no longer active buttons state. It will return an [`IPointerEvent`](/api/interface/ipointerevent.md) object.
+
+#### pageover
+
+Triggered when a pointer is moved into a page's hit test boundaries. It will return an [`IPointerEvent`](/api/interface/ipointerevent.md) object.
+
+#### pageout
+
+Triggered when a pointer is moved out of the hit test boundaries of a page. It will return an [`IPointerEvent`](/api/interface/ipointerevent.md) object.
+
+#### scroll
+
+Triggered when the viewer is scrolled. It will return the native event object.
+
+#### Mouse Events
+
+##### click
+
+Triggered when click in the viewer's viewing area. On mobile device, triggered when tap in the viewer's viewing area.
+
+##### dblclick
+
+Triggered when double click in the viewer's viewing area.
+
+##### rightclick
+
+Triggered when right click in the viewer's viewing area. On mobile device, triggered when long-tap in the viewer's viewing area.
+
+
+**Callback for mouse events**
+
+ `IPointerEvent`: An EventObject.
+
+**Attributes**
+
+`index`: The page index.
+
+`pageUid`: The page uid.
+
+`imageX`: The relative x-coordinate of the click pointer on the image.
+
+`imageY`: The relative y-coordinate of the click pointer on the image.
+
+`canvasX`: The relative x-coordinate of the click pointer on the canvas.
+
+`canvasY`: The relative x-coordinate of the click pointer on the canvas.
+
+`nativeEvent`: [`PointerEvent`](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent)
diff --git a/_v4.0/api/class/index.md b/_v4.0/api/class/index.md
new file mode 100644
index 0000000..9edea44
--- /dev/null
+++ b/_v4.0/api/class/index.md
@@ -0,0 +1,48 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Class
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Class
+breadcrumbText: EditViewer Class
+description: Dynamsoft Document Viewer Documentation API Reference Class Index Page
+---
+
+
+# Class
+
+Dynamsoft Document Viewer JavaScript library has two main categories of classes: one is under the namespace Dynamsoft.DDV, and the other is related to annotations.
+
+## Dynamsoft.DDV Classes
+
+Under the namespace Dynamsoft.DDV, Dynamsoft Document Viewer JavaScript library contains seven primary classes:
+
+- [DocumentManager](/api/class/documentmanager.md)
+- [AnnotationManager](/api/class/annotationmanager.md)
+- [EditViewer](/api/class/editviewer.md)
+- [CaptureViewer](/api/class/captureviewer.md)
+- [PerspectiveViewer](/api/class/perspectiveviewer.md)
+- [BrowseViewer](/api/class/browseviewer.md)
+- [CustomViewer](/api/class/customviewer.md)
+
+## Annotation
+
+Annotation has the following main classes:
+
+
+- [Rectangle](/api/class/annotation/rectangle.md)
+- [Redaction](/api/class/annotation/redaction.md)
+- [Ellipse](/api/class/annotation/ellipse.md)
+- [Polygon](/api/class/annotation/polygon.md)
+- [Polyline](/api/class/annotation/polyline.md)
+- [Line](/api/class/annotation/line.md)
+- [Ink](/api/class/annotation/ink.md)
+- [TextBox](/api/class/annotation/textbox.md)
+- [TextTypewriter](/api/class/annotation/texttypewriter.md)
+- [Highlight](/api/class/annotation/highlight.md)
+- [Underline](/api/class/annotation/underline.md)
+- [Strikeout](/api/class/annotation/strikeout.md)
+- [Stamp](/api/class/annotation/stamp.md)
+- [Incomplete](/api/class/annotation/incomplete.md)
+- [Unknown](/api/class/annotation/unknown.md)
diff --git a/_v4.0/api/enumeration-type/enumannnotationrendermode.md b/_v4.0/api/enumeration-type/enumannnotationrendermode.md
new file mode 100644
index 0000000..2120d99
--- /dev/null
+++ b/_v4.0/api/enumeration-type/enumannnotationrendermode.md
@@ -0,0 +1,20 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Enumeration EnumAnnotationRenderMode
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Enumeration EnumAnnotationRenderMode
+breadcrumbText: Enumeration EnumAnnotationRenderMode
+description: Dynamsoft Document Viewer Documentation API Reference Enumeration EnumAnnotationRenderMode Page
+---
+
+# EnumAnnotationRenderMode
+
+```typescript
+enum EnumAnnotationRenderMode {
+ NO_ANNOTATIONS = "noAnnotations", // default, means that the annotations in the PDF file will not be loaded
+ RENDER_ANNOTATIONS = "renderAnnotations", // means that the annotations in the PDF file will be rendered
+ LOAD_ANNOTATIONS = "loadAnnotations", // means that the annotations in the PDF file will be loaded normally, a valid PDF Annotation license is requested
+}
+```
diff --git a/_v4.0/api/enumeration-type/enumlineending.md b/_v4.0/api/enumeration-type/enumlineending.md
new file mode 100644
index 0000000..1c15fab
--- /dev/null
+++ b/_v4.0/api/enumeration-type/enumlineending.md
@@ -0,0 +1,42 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Enumeration EnumLineEnding
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Enumeration EnumLineEnding
+breadcrumbText: Enumeration EnumLineEnding
+description: Dynamsoft Document Viewer Documentation API Reference Enumeration EnumLineEnding Page
+---
+
+# EnumLineEnding
+
+```typescript
+enum EnumLineEnding {
+ NONE = "none",
+ OPEN = "open",
+ OPEN_REVERSE = "openReverse",
+ CLOSED = "closed",
+ CLOSED_REVERSE = "closedReverse",
+ BUTT = "butt",
+ SLASH = "slash",
+ SQUARE = "square",
+ DIAMOND = "diamond",
+ CIRCLE = "circle",
+}
+```
+
+## Corresponding line endings
+
+| EnumLineEnding | Corresponding line ending |
+| -------------- | ------------------------- |
+| NONE |  |
+| OPEN |  |
+| OPEN_REVERSE |  |
+| CLOSED |  |
+| CLOSED_REVERSE |  |
+| BUTT |  |
+| SLASH |  |
+| SQUARE |  |
+| DIAMOND |  |
+| CIRCLE |  |
diff --git a/_v4.0/api/enumeration-type/enumstampicon.md b/_v4.0/api/enumeration-type/enumstampicon.md
new file mode 100644
index 0000000..0292a0b
--- /dev/null
+++ b/_v4.0/api/enumeration-type/enumstampicon.md
@@ -0,0 +1,46 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Enumeration EnumStampIcon
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Enumeration EnumStampIcon
+breadcrumbText: Enumeration EnumStampIcon
+description: Dynamsoft Document Viewer Documentation API Reference Enumeration EnumStampIcon Page
+---
+
+# EnumStampIcon
+
+```typescript
+enum EnumStampIcon {
+ REJECTED = "rejected",
+ ACCEPTED = "accepted",
+ INIT_ALHERE = "initalHere",
+ SIGN_HERE = "signHere",
+ WITNESS = "witness",
+ APPROVED = "approved",
+ NOT_APPROVED = "notApproved",
+ DRAFT = "draft",
+ FINAL = "final",
+ COMPLETED = "completed",
+ CONFIDENTIAL = "confidential",
+ VOID = "void",
+}
+```
+
+## Corresponding standard business stamps
+
+| EnumStampIcon | Corresponding stamp |
+| ------------- | ------------------- |
+| REJECTED |  |
+| ACCEPTED |  |
+| INITAL_HERE |  |
+| SIGN_HERE |  |
+| WITNESS |  |
+| APPROVED |  |
+| NOT_APPROVED |  |
+| DRAFT |  |
+| FINAL |  |
+| COMPLETED |  |
+| CONFIDENTIAL |  |
+| VOID |  |
diff --git a/_v4.0/api/errorlist.md b/_v4.0/api/errorlist.md
new file mode 100644
index 0000000..428fd41
--- /dev/null
+++ b/_v4.0/api/errorlist.md
@@ -0,0 +1,117 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Error List
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Error List
+breadcrumbText: API Reference
+description: Dynamsoft Document Viewer Documentation API Reference Error List Page
+---
+
+# Error List
+
+## License Related Errors
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+
+## Initialize Related Errors
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80052 | *XXX(API)*: Resource is not found from the specified engineResourcePath.
+ -80053 | *XXX(API)*: The resource version at the specified engineResourcePath does not match this version of Dynamsoft Document Viewer.
+
+## Common Errors
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+ -80104 | *XXX(API)*: The specified document(s) do not exist.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+ -80106 | *XXX(API)*: The specified annotation does not exist.
+ -80108 | *XXX(API)*: The document has been destroyed.
+ -80109 | *XXX(API)*: The page has been destroyed.
+
+
+## Document Related Errors
+
+ Error Code | Error Message
+ ---------- | ---------------------------------------------
+ -80200 | File type is not supported.
+ -80201 | docUid does not allow duplicate.
+ -80202 | Failed to read the PDF file because it's encrypted and the correct password is not provided.
+ -80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
+ -80204 | PDFs containing XFA (XML Forms Architecture) forms are not supported.
+ -80205 | The pageData has been destroyed.
+ -80206 | The DocTextSearcher has been destroyed.
+
+## Viewer Releated Errors
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------------
+ -80301 | The specified container does not exist.
+ -80302 | minZoom value cannot be larger than maxZoom value.
+ -80304 | No document opened.
+ -80305 | There is no image in the current document.
+ -80306 | The value for zoom is larger than maxZoom value.
+ -80307 | The value for zoom is smaller than minZoom value.
+ -80308 | EditViewer.setParallelScrollCount: Not available in current displayMode.
+ -80309 | The specified rect exceeds the bounds of page index *X(IndexNum)*.
+ -80310 | No operations to undo.
+ -80311 | No operations to redo.
+ -80312 | The specified quad exceeds the bounds of the current page.
+ -80313 | The element *XXX(ElementName)* is not supported in *XXX(ClassName)* class.
+ -80314 | *XXX(API)*: Not available in current toolMode.
+ -80315 | DocumentDetect needs to be configured by Dynamsoft.DDV.setProcessingHandler to enable the document detection feature.
+ -80316 | ImageFilter needs to be configured by Dynamsoft.DDV.setProcessingHandler to enable the image filter feature.
+ -80317 | The specified annotation(s) is not on the current page or does not exist.
+ -80318 | The document contains unsupported fonts, which may result in font loss after saving.
+ -80319 | ReadOnly annotation or noView annotation cannot be selected.
+ -80320 | Unknown annotation or incomplete annotation cannot be selected.
+ -80321 | Flattened annotation cannot be selected.
+ -80322 | No results found.
+ -80323 | The redaction annotation has already been applied.
+ -80324 | The specified annotation(s) contain annotations other than redaction annotations.
+ -80325 | The specified page does not contain redaction annotations.
+ -80326 | The annotation has already been deleted.
+ -80327 | The specified annotation(s) are not on the specified page or do not exist.
+ -80328 | Rectangle-type redaction requires exactly one rect.
+
+## Camera Releated Errors
+
+ Error Code | Error Message
+ ---------- | -------------------------------------------
+ -80400 | The specified camera does not exist.
+ -80401 | The specified camera is occupied.
+ -80402 | No video stream is played.
+ -80403 | Not HTTPS, failed to play the video stream.
+ -80404 | The camera does not support a flashlight.
+ -80405 | No camera available.
+ -80406 | The selected camera is denied by browser.
+ -80407 | No bound container.
+
+
+## Wasm Error
+
+ Error Code | Error Message
+------------|----------------
+ -81000 | *WASM Error*
+
+## External Error
+
+ Error Code | Error Message
+------------|----------------
+ -81100 | *External Error*
+
\ No newline at end of file
diff --git a/_v4.0/api/index.md b/_v4.0/api/index.md
new file mode 100644
index 0000000..c984221
--- /dev/null
+++ b/_v4.0/api/index.md
@@ -0,0 +1,175 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference
+keywords: Documentation, Dynamsoft Document Viewer, API Reference
+breadcrumbText: API Reference
+description: Dynamsoft Document Viewer Documentation API Reference Page
+---
+
+# API Reference
+
+## Namespaces
+
+- [`Dynamsoft.DDV`]({{ site.api }}namespace/ddv.html)
+- [`Dynamsoft.DDV.Core`]({{ site.api }}namespace/ddv_core.html)
+- [`Dynamsoft.DDV.Elements`]({{ site.api }}namespace/ddv_elements.html)
+
+## Classes
+
+- Dynamsoft.DDV
+ - [DocumentManager]({{ site.api }}class/documentmanager.html)
+ - [EditViewer]({{ site.api }}class/editviewer.html)
+ - [CaptureViewer]({{ site.api }}class/captureviewer.html)
+ - [PerspectiveViewer]({{ site.api }}class/perspectiveviewer.html)
+ - [BrowseViewer]({{ site.api }}class/browseviewer.html)
+ - [CustomViewer]({{ site.api }}class/customviewer.html)
+ - Advanced
+ - [ImageFilter]({{ site.api }}class/advanced/imagefilter.html)
+ - [DocumentDetect]({{ site.api }}class/advanced/documentdetect.html)
+
+- Annotation
+ - [Rectangle]({{ site.api }}class/annotation/rectangle.html)
+ - [Redaction](/api/class/annotation/redaction.md)
+ - [Ellipse]({{ site.api }}class/annotation/ellipse.html)
+ - [Polygon]({{ site.api }}class/annotation/polygon.html)
+ - [Polyline]({{ site.api }}class/annotation/polyline.html)
+ - [Line]({{ site.api }}class/annotation/line.html)
+ - [Ink]({{ site.api }}class/annotation/ink.html)
+ - [TextBox]({{ site.api }}class/annotation/textbox.html)
+ - [TextTypewriter]({{ site.api }}class/annotation/texttypewriter.html)
+ - [Stamp]({{ site.api }}class/annotation/stamp.html)
+ - [Highlight](/api/class/annotation/highlight.md)
+ - [Underline](/api/class/annotation/underline.md)
+ - [Strikeout](/api/class/annotation/strikeout.md)
+ - [Incomplete]({{ site.api }}class/annotation/incomplete.html)
+ - [Unknown]({{ site.api }}class/annotation/unknown.html)
+
+
+## Interfaces
+
+- [`IDocument`]({{ site.api }}interface/idocument/index.html)
+ - [`Source`]({{ site.api }}interface/idocument/source.html)
+ - [`PdfSource`]({{ site.api }}interface/idocument/pdfsource.html)
+ - [`SavePngSettings`]({{ site.api }}interface/idocument/savepngsettings.html)
+ - [`SaveJpegSettings`]({{ site.api }}interface/idocument/savejpegsettings.html)
+ - [`SaveTiffSettings`]({{ site.api }}interface/idocument/savetiffsettings.html)
+ - [`SavePdfSettings`]({{ site.api }}interface/idocument/savepdfsettings.html)
+ - [`CustomTag`]({{ site.api }}interface/idocument/customtag.html)
+ - [`PrintSettings`]({{ site.api }}interface/idocument/printsettings.html)
+ - [`IDocTextSearcher`](/api/interface/idocument/idoctextsearcher.md)
+
+- Style Interfaces
+
+ | Style Name | Style Interface |
+ | -------------------- | ------------------------------------------------------------ |
+ | `pageStyle` | [`BaseStyle`]({{ site.api }}interface/styleinterface/basestyle.html) |
+ | `currentPageStyle` | [`BaseStyle`]({{ site.api }}interface/styleinterface/basestyle.html) |
+ | `selectedPageStyle` | [`BaseStyle`]({{ site.api }}interface/styleinterface/basestyle.html) |
+ | `hoveredPageStyle` | [`BaseStyle`]({{ site.api }}interface/styleinterface/basestyle.html) |
+ | `placeholderStyle` | [`BaseStyle`]({{ site.api }}interface/styleinterface/basestyle.html) |
+ | `pageNumberStyle` | [`PageNumberStyle`]({{ site.api }}interface/styleinterface/pagenumberstyle.html) |
+ | `checkboxStyle` | [`CheckboxStyle`]({{ site.api }}interface/styleinterface/checkboxstyle.html) |
+ | `canvasStyle` | [`CanvasStyle`]({{ site.api }}interface/styleinterface/canvasstyle.html) |
+ | `quadSelectionStyle` | [`QuadSelectionStyle`]({{ site.api }}interface/styleinterface/quadselectionstyle.html) |
+ | `annotationSelectionStyle`| [`AnnotationSelectionStyle`]({{ site.api }}interface/styleinterface/annotationselectionstyle.html) |
+
+- Annotation Interfaces
+ - [`RectAnnotationOptions`]({{ site.api }}interface/annotationinterface/rectannotationoptions.html)
+ - [`EllipseAnnotationOptions`]({{ site.api }}interface/annotationinterface/ellipseannotationoptions.html)
+ - [`PolygonAnnotationOptions`]({{ site.api }}interface/annotationinterface/polygonannotationoptions.html)
+ - [`PolylineAnnotationOptions`]({{ site.api }}interface/annotationinterface/polylineannotationoptions.html)
+ - [`LineAnnotationOptions`]({{ site.api }}interface/annotationinterface/lineannotationoptions.html)
+ - [`InkAnnotationOptions`]({{ site.api }}interface/annotationinterface/inkannotationoptions.html)
+ - [`TextBoxAnnotationOptions`]({{ site.api }}interface/annotationinterface/textboxannotationoptions.html)
+ - [`TextTypewriterAnnotationOptions`]({{ site.api }}interface/annotationinterface/texttypewriterannotationoptions.html)
+ - [`StampAnnotationOptions`]({{ site.api }}interface/annotationinterface/stampannotationoptions.html)
+ - [`HighlightAnnotationOptions`](/api/interface/annotationinterface/highlightannotationoptions.md)
+ - [`UnderlineAnnotationOptions`](/api/interface/annotationinterface/underlineannotationoptions.md)
+ - [`StrikeoutAnnotationOptions`](/api/interface/annotationinterface/strikeoutannotationoptions.md)
+ - [`RedactionAnnotationOptions`](/api/interface/annotationinterface/redactionannotationoptions.md)
+ - [`Flags`]({{ site.api }}interface/annotationinterface/flags.html)
+ - [`Point`]({{ site.api }}interface/annotationinterface/point.html)
+ - [`TextContent`]({{ site.api }}interface/annotationinterface/textcontent.html)
+ - [`RectangleStyle`]({{ site.api }}interface/annotationinterface/rectanglestyle.html)
+ - [`EllipseStyle`]({{ site.api }}interface/annotationinterface/ellipsestyle.html)
+ - [`PolygonStyle`]({{ site.api }}interface/annotationinterface/polygonstyle.html)
+ - [`PolylineStyle`]({{ site.api }}interface/annotationinterface/polylinestyle.html)
+ - [`LineStyle`]({{ site.api }}interface/annotationinterface/linestyle.html)
+ - [`InkStyle`]({{ site.api }}interface/annotationinterface/inkstyle.html)
+ - [`TextBoxStyle`]({{ site.api }}interface/annotationinterface/textboxstyle.html)
+ - [`TextTypewriterStyle`]({{ site.api }}interface/annotationinterface/texttypewriterstyle.html)
+ - [`StampStyle`]({{ site.api }}interface/annotationinterface/stampstyle.html)
+ - [`HighlightStyle`](/api/interface/annotationinterface/highlightstyle.md)
+ - [`UnderlineStyle`](/api/interface/annotationinterface/underlinestyle.md)
+ - [`StrikeoutStyle`](/api/interface/annotationinterface/strikeoutstyle.md)
+ - [`RedactionStyle`](/api/interface/annotationinterface/rectanglestyle.md)
+ - [`ToolbarConfig`]({{ site.api }}interface/annotationinterface/toolbarconfig.html)
+ - [`PaletteConfig`]({{ site.api }}interface/annotationinterface/paletteconfig.html)
+ - [`AnnotationToolbarButton`]({{ site.api }}interface/annotationinterface/annotationtoolbarbutton.html)
+
+- [`AnnotationConfig`]({{ site.api }}interface/annotationconfig.html)
+- [`BrowseViewerConfig`]({{ site.api }}interface/browseviewerconfig.html)
+- [`BrowseViewerConstructorOptions`]({{ site.api }}interface/browseviewerconstructoroptions.html)
+- [`CaptureViewerConfig`]({{ site.api }}interface/captureviewerconfig.html)
+- [`CaptureViewerConstructorOptions`]({{ site.api }}interface/captureviewerconstructoroptions.html)
+- [`ConfigResult`]({{ site.api }}interface/configresult.html)
+- [`CreateDocumentOptions`]({{ site.api }}interface/createdocumentoptions.html)
+- [`CustomViewerConstructorOptions`]({{ site.api }}interface/customviewerconstructoroptions.html)
+- [`DDVError`]({{ site.api }}interface/ddverror.html)
+- [`DetectResult`]({{ site.api }}interface/detectresult.html)
+- [`DisplayTextConfig`]({{ site.api }}interface/displaytextconfig.html)
+- [`DocumentDetectConfig`]({{ site.api }}interface/documentdetectconfig.html)
+- [`DocumentDetectResult`]({{ site.api }}interface/documentdetectresult.html)
+- [`EditViewerConfig`]({{ site.api }}interface/editviewerconfig.html)
+- [`EditViewerConstructorOptions`]({{ site.api }}interface/editviewerconstructoroptions.html)
+- [`IBrowseViewer`]({{ site.api }}interface/ibrowseviewer.html)
+- [`IImageFilter`]({{ site.api }}interface/iimagefilter.html)
+- [`IPointerEvent`](/api/interface/ipointerevent.md)
+- [`IPageData`](/api/interface/ipagedata.md)
+- [`IQuadModifiedEvent`](/api/interface/iquadmodifiedevent.md)
+- [`ITextSearchedInfo`](/api/interface/itextsearchedinfo.md)
+- [`ITextSelectedInfo`](/api/interface/itextselectedinfo.md)
+- [`IDocumentDetect`]({{ site.api }}interface/idocumentdetect.html)
+- [`ImageFilterItem`]({{ site.api }}interface/imagefilteritem.html)
+- [`MergeDocumentOptions`]({{ site.api }}interface/mergedocumentoptions.html)
+- [`PageImageInfo`](/api/interface/pageimageinfo.md)
+- [`PageVisualInfo`](/api/interface/pagevisualinfo.md)
+- [`PerspectiveViewerConfig`]({{ site.api }}interface/perspectiveviewerconfig.html)
+- [`PerspectiveViewerConstructorOptions`]({{ site.api }}interface/perspectiveviewerconstructoroptions.html)
+- [`PlayCallbackInfo`]({{ site.api }}interface/playcallbackinfo.html)
+- [`Rect`]({{ site.api }}interface/rect.html)
+- [`RectXY`](/api/interface/rectxy.md)
+- [`SearchTextOptions`](/api/interface/searchtextoptions.md)
+- [`TextSearchResult`](/api/interface/textsearchresult.md)
+- [`ThumbnailConfig`]({{ site.api }}interface/thumbnailconfig.html)
+- [`Tooltip`]({{ site.api }}interface/tooltip.html)
+- [`TransferOptions`]({{ site.api }}interface/transferoptions.html)
+- [`UiConfig`]({{ site.api }}interface/uiconfig.html)
+- [`UpdatedPdfSource`](/api/interface/updatedpdfsource.md)
+- [`UpdatedSource`](/api/interface/updatedsource.md)
+- [`VError`]({{ site.api }}interface/verror.html)
+- [`VideoConfig`]({{ site.api }}interface/videoconfig.html)
+- [`VideoDeviceInfo`]({{ site.api }}interface/videodeviceinfo.html)
+- [`VImageData`]({{ site.api }}interface/vimagedata.html)
+- [`ZoomOrigin`]({{ site.api }}interface/zoomorigin.html)
+
+## Enumeration & Type
+
+- [`EnumPdfPageType`]({{ site.api }}enumeration-type/enumpdfpagetype.html)
+- [`EnumPdfCompressionType`]({{ site.api }}enumeration-type/enumpdfcompressiontype.html)
+- [`EnumTiffCompressionType`]({{ site.api }}enumeration-type/enumtiffcompressiontype.html)
+- [`EnumConvertMode`]({{ site.api }}enumeration-type/enumconvertmode.html)
+- [`EnumAnnotationRenderMode`]({{ site.api }}enumeration-type/enumannotationrendermode.html)
+- [`EnumImageDataType`]({{ site.api }}enumeration-type/enumimagedatatype.html)
+- [`EnumImageFilterType`]({{ site.api }}enumeration-type/enumimagefiltertype.html)
+- [`EnumDocumentDetectionStatus`]({{ site.api }}enumeration-type/enumdocumentdetectionstatus.html)
+- [`EnumStampIcon`]({{ site.api }}enumeration-type/enumstampicon.html)
+- [`EnumLineEnding`]({{ site.api }}enumeration-type/enumlineending.html)
+- [`type Quad`]({{ site.api }}enumeration-type/quad.html)
+
+## Error
+
+- [Error List]({{ site.api }}errorlist.html)
\ No newline at end of file
diff --git a/_v4.0/api/interface/idocument/index.md b/_v4.0/api/interface/idocument/index.md
new file mode 100644
index 0000000..1d9323a
--- /dev/null
+++ b/_v4.0/api/interface/idocument/index.md
@@ -0,0 +1,864 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Interface IDocument
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Interface IDocument
+breadcrumbText: Interface IDocument
+description: Dynamsoft Document Viewer Documentation API Reference Interface IDocument Page
+---
+
+# IDocument
+
+This interface that defines a document object.
+
+## Members
+
+| API Name | Description |
+| ------------------- | ------------------------------------------------------------ |
+| [`name`](#name) | Return the name of current document. |
+| [`author`](#author) | Return the author of current document. |
+| [`creationDate`](#creationdate) | Return the creation date of current document. |
+| [`uid`](#uid) | Return the docUid of current document. |
+| [`pages`](#pages) | Return the array of pageUids of current document. |
+| [`loadSource()`](#loadsource) | Load file(s) to current document. |
+| [`getPageData()`](#getpagedata) | Get the data of specified page. |
+| [`updatePage()`](#updatepage) | Update a page specified by the pageUid with the new data. |
+| [`setPageCustomData()`](#setpagecustomdata) | Set the custom data to the specified page. |
+| [`getPageCustomData()`](#getpagecustomdata) | Get the custom data of the specified page. |
+| [`deletePages()`](#deletepages) | Delete the specified pages from current document. |
+| [`deleteAllPages()`](#deleteallpages) | Delete all pages in current document. |
+| [`movePages()`](#movepages) | Move specified page(s) to the target position in current document. |
+| [`switchPage()`](#switchpage) | Swap the position of two pages in current document. |
+| [`insertBlankPage()`](#insertblankpage) | Insert a blank page to current document. |
+| [`isPageModified()`](#ispagemodified) | Check if a page is modified. |
+| [`rename()`](#rename) | Rename current document. |
+| [`saveToPng()`](#savetopng) | Save specified page or current page in current document to a PNG file. |
+| [`saveToJpeg()`](#savetojpeg) | Save specified page or current page in current document to a JPEG file. |
+| [`saveToTiff()`](#savetotiff) | Save specified page(s) or all pages in current document to a TIFF file. |
+| [`saveToPdf()`](#savetopdf) | Save specified page(s) or all pages in current document to a PDF file. |
+| [`print()`](#print) | Use the browser’s built-in print feature to print the specified image(s). |
+| [`createTextSearcher()`](#createtextsearcher) | Create a text searcher. |
+
+### name
+
+Return the name of current document.
+
+**Syntax**
+
+```typescript
+readonly name: string;
+```
+
+**Remark**
+
+- It can be set while creating the document by using [`createDocument()`]({{ site.api }}class/documentmanager.html#createdocument). If it is not set, return the name which is auto generated.
+
+### author
+
+Return the author of current document.
+
+**Syntax**
+
+```typescript
+readonly author: string;
+```
+
+**Remark**
+
+- It can be set while creating the document by using [`createDocument()`]({{ site.api }}class/documentmanager.html#createdocument). If it is not set, return `''`.
+
+### creationDate
+
+Return the creation date of current document.
+
+**Syntax**
+
+```typescript
+readonly creationDate: string;
+```
+
+**Remark**
+
+- It can be set while creating the document by using [`createDocument()`]({{ site.api }}class/documentmanager.html#createdocument). If it is not set, return the actual creation date of the document.
+
+### uid
+
+Return the docUid of current document.
+
+**Syntax**
+
+```typescript
+readonly uid: string;
+```
+
+### pages
+
+Return the array of pageUids of current document.
+
+**Syntax**
+
+```typescript
+readonly pages: string[];
+```
+
+**Remark**
+
+- Returns an array of pageUids.
+
+**Code Snippet**
+
+```typescript
+const firstDoc = Dynamsoft.DDV.documentManager.createDocument({
+ name: "first_document",
+ author: "DDV",
+ creationDate: "D:20230101085959-08'00'",
+ });
+
+const docName = firstDoc.name;
+const docAuthor = firstDoc.author;
+const docCreationDate = firstDoc.creationDate;
+const docUid = firstDoc.uid;
+const docPages = firstDoc.pages;
+```
+
+
+### loadSource()
+
+Load file(s) to current document.
+
+**Syntax**
+
+```typescript
+loadSource(fileData: Blob | Blob[], index?: number): Promise;
+loadSource(sources: Source | PdfSource | (Source | PdfSource)[], index?: number): Promise;
+```
+
+**Parameters**
+
+`fileData`: The blob of the file to be loaded.
+
+`sources`: The target files, it could be a file or a file array. Please refer to [`Source`](/api/interface/idocument/source.md). `Source` can be extended to [`PdfSource`](/api/interface/idocument/pdfsource.md).
+
+`index`: The position in the document where the file(s) will be loaded to. If not set or out of the maximum range, the loaded file(s) will be added from the end of the document.
+
+**Return Value**
+
+A Promise object which will be resolved with the page uids of the loaded pages when the file(s) are successfully loaded.
+
+**Code Snippet**
+
+```typescript
+const firstDoc = Dynamsoft.DDV.documentManager.createDocument({
+ name: "first_document",
+ author: "DDV",
+ creationDate: "D:20230101085959-08'00'",
+ });
+const source = {
+ fileData: /*sampleBlob*/;
+};
+await firstDoc.loadSource([source]);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80200 | File type is not supported.
+ -80202 | Failed to read the PDF file because it's encrypted and the correct password is not provided.
+ -80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
+ -80204 | PDFs containing XFA (XML Forms Architecture) forms are not supported.
+
+### getPageData()
+
+Get the data of specified page.
+
+**Syntax**
+
+```typescript
+getPageData(pageUid: string): IPageData;
+```
+
+**Parameters**
+
+`pageUid`: The uid of the page.
+
+**Return Value**
+
+[`IPageData`](/api/interface/ipagedata.md) object.
+
+**Code Snippet**
+
+```typescript
+const pageData = firstDoc.getPageData(firstDoc.pages[0]);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+
+
+### updatePage()
+
+Update a page specified by the pageUid with the new data.
+
+**Syntax**
+
+```typescript
+updatePage(pageUid: string, source: UpdatedSource | UpdatedPdfSource): Promise;
+```
+
+**Parameters**
+
+`pageUid`: The uid of the page to be updated.
+
+`source`: The new data. Please refer to [`UpdatedSource`](/api/interface/updatedsource.md) and [`UpdatedPdfSource`](/api/interface/updatedpdfsource.md).
+
+**Return Value**
+
+A Promise object which will be resolved with a boolean value.
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const source = {
+ fileIndex: 1, // Using the second page of the new multi-page file, such as PDF or TIFF.
+ fileData: /*sample blob*/
+};
+
+await firstDoc.updatePage(firstDoc.pages[0], source);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80200 | File type is not supported.
+ -80202 | Failed to read the PDF file because it's encrypted and the correct password is not provided.
+ -80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
+ -80204 | PDFs containing XFA (XML Forms Architecture) forms are not supported.
+
+
+### setPageCustomData()
+
+Set the custom data to the specified page.
+
+**Syntax**
+
+```typescript
+setPageCustomData(pageUid: string, data: any): Promise;
+```
+
+**Parameters**
+
+`pageUid`: The uid of the page.
+
+`data`: The custom data to set.
+
+**Return Value**
+
+A Promise object which will be resolved with a boolean value.
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const customData ={
+ hasBarcode: true; // sample custom data
+};
+await firstDoc.setPageCustomData(firstDoc.pages[0], customData);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+
+### getPageCustomData()
+
+Get the custom data of the specified page.
+
+**Syntax**
+
+```typescript
+getPageCustomData(pageUid: string): Promise;
+```
+
+**Parameters**
+
+`pageUid`: The uid of the page.
+
+**Return Value**
+
+A Promise object which will be resolved with the custom data.
+
+**Code Snippet**
+
+```typescript
+const customdata = await firstDoc.getPageCutomData(firstDoc.pages[0]);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80105 | *XXX(API)*: The specified page(s) do not exist.
+
+### deletePages()
+
+Delete the specified pages from current document.
+
+**Syntax**
+
+```typescript
+deletePages(indices: number[]): boolean;
+```
+
+**Parameters**
+
+`indices`: The array of page indices which will be removed.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+// Delete the first and second page.
+firstDoc.deletePages([0,1]);
+```
+
+**Warning**
+
+ Error Code | Error Message | API return value
+-------------|------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+
+### deleteAllPages()
+
+Delete all pages in current document.
+
+**Syntax**
+
+```typescript
+deleteAllPages(): boolean;
+```
+
+**Parameters**
+
+None.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+// Delete all pages from the doc.
+firstDoc.deleteAllPages();
+```
+
+### movePages()
+
+Move specified page(s) to the target position in current document.
+
+**Syntax**
+
+```typescript
+movePages(indices: number[], insertBeforeIndex?: number): void;
+```
+
+**Parameters**
+
+`indices`: The array of page(s) indices to be moved.
+
+`insertBeforeIndex`: Moved pages will be placed before this index. If not set or out of the maximum range, the specified page(s) will be moved after the last page.
+
+**Code Snippet**
+
+```typescript
+// Move the second, fourth, sixth pages to the begining of the doc
+// The moved pages are in (original sixth, fourth, second) order.
+firstDoc.movePages([5,3,1], 0);
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+
+### switchPage()
+
+Swap the position of two pages in current document.
+
+**Syntax**
+
+```typescript
+switchPage(oneIndex: number, anotherIndex: number): void;
+```
+
+**Parameters**
+
+`oneIndex`: The index of one page.
+
+`anotherIndex`: The index of another page.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+// Switch the third and sixth pages.
+firstDoc.switchPage(2, 5);
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### insertBlankPage()
+
+Insert a blank page to current document.
+
+**Syntax**
+
+```typescript
+insertBlankPage(
+ pageWidth: number;
+ pageHeight: number;
+ insertBeforeIndex?: number;
+):string;
+```
+
+**Parameters**
+
+`pageWidth`: The page width of the blank page to insert. The unit is point.
+
+`pageHeight`: The page height of the blank page to insert. The unit is point.
+
+`insertBeforeIndex`: The blank page will be inserted before this index. If not set or out of the maximum range, the blank page will be added after the last page.
+
+*Common page sizes:*
+
+ Page size | pageWidth (pt) | pageHeight (pt)
+-----------|------------------|-------------------
+ Letter | 612 | 792
+ Legal | 612 | 1008
+ A4 | 597.6 | 842.4
+ A3 | 842.4 | 1188
+
+**Return value**
+
+The page uid of the inserted blank page.
+
+**Exception**
+
+ Error Code | Error Message
+-------------|-----------------------------------------------------
+ -80050 | DDV.Core.init() has not been set up yet.
+ -80051 | DDV.Core.init() has not been completed.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### isPageModified()
+
+Check if a page is modified.
+
+**Syntax**
+
+```typescript
+isPageModified(index: number): boolean;
+```
+
+**Parameters**
+
+`index`: The page index.
+
+**Return value**
+
+A boolean value which indicates whether the page is modified.
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### rename()
+
+Rename current document.
+
+**Syntax**
+
+```typescript
+rename(name: string): boolean;
+```
+
+**Parameters**
+
+`name`: The new name of current document.
+
+**Return Value**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+**Code Snippet**
+
+```typescript
+const firstDoc = Dynamsoft.DDV.documentManager.createDocument({
+ name: "first_document",
+ author: "DDV",
+ creationDate: "D:20230101085959-08'00'",
+ });
+firstDoc.rename("my_doc");
+```
+
+**Warning**
+
+ Error Code | Error Message | API return value
+--------|-----------------------------------------------------|---------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
+
+### saveToPng()
+
+Save specified page or current page in current document to a PNG file.
+
+**Syntax**
+
+```typescript
+saveToPng(index: number, savePngSettings?: SavePngSettings): Promise;
+```
+
+**Parameters**
+
+`index`: Specify index of the page to be saved.
+
+`savePngSettings`: Specify the save settings. Please refer to [`SavePngSettings`]({{ site.api }}interface/idocument/savepngsettings.html).
+
+**Return Values**
+
+A Promise object which will be resolved with `Blob` of the saved image.
+
+**Code Snippet**
+
+```typescript
+// Save the first page to a PNG file.
+const result = await firstDoc.saveToPng(0);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### saveToJpeg()
+
+Save specified page or current page in current document to a JPEG file.
+
+**Syntax**
+
+```typescript
+saveToJpeg(index: number, saveJpegSettings?: SaveJpegSettings): Promise;
+```
+
+**Parameters**
+
+`index`: Specify index of the page to be saved.
+
+`saveJpegSettings`: Specify the save settings. Please refer to [`SaveJpegSettings`]({{ site.api }}interface/idocument/savejpegsettings.html).
+
+**Return Values**
+
+A Promise object which will be resolved with `Blob` of the saved image.
+
+**Code Snippet**
+
+```typescript
+// Save the first page as a JPEG file with a JPEG compression quality of 100, and the annotations are saved as part of the JPEG.
+const settings = {
+ quality: 100,
+ saveAnnotation: false,
+};
+const result = await firstDoc.saveToJpeg(0, settings);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80101 | *XXX(API)*: *XXX(ParameterName)* is out of range.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+### saveToTiff()
+
+Save specified page(s) or all pages in current document to a TIFF file.
+
+**Syntax**
+
+```typescript
+saveToTiff(indices: number[], saveTiffSettings?: SaveTiffSettings): Promise;
+saveToTiff(saveTiffSettings?: SaveTiffSettings): Promise;
+```
+
+**Parameters**
+
+`indices`: The array of page indices which will be saved. If not set, will save all pages to a TIFF file by default.
+
+`saveTiffSettings`: Specify the save settings. Please refer to [`SaveTiffSettings`]({{ site.api }}interface/idocument/savetiffsettings.html).
+
+**Return Values**
+
+A Promise object which will be resolved with `Blob` of the saved TIFF file.
+
+**Code Snippet**
+
+```typescript
+// Set custom tag
+const customTag1 = {
+ id: 700,
+ content: "Created By Dynamsoft",
+ contentIsBase64: false,
+}
+
+// Set SaveTiffSettings
+const tiffSettings = {
+ customTag: [customTag1],
+ compression: "tiff/auto",
+}
+
+// Save the fifth, sixth, seventh pages to a multi-page TIFF file with the specified tiff settings.
+const result1 = await firstDoc.saveToTiff([4,5,6], tiffSettings);
+
+// Save the whole document to a multi-page TIFF file with the specified tiff settings.
+const result2 = await firstDoc.saveToTiff(tiffSettings);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80305 | There is no image in the current document.
+
+### saveToPdf()
+
+Save specified page(s) or all pages in current document to a PDF file.
+
+**Syntax**
+
+```typescript
+saveToPdf(indices: number[], savePdfSettings?: SavePdfSettings): Promise;
+saveToPdf(savePdfSettings?: SavePdfSettings): Promise;
+```
+
+**Parameters**
+
+`indices`: The array of page indices which will be saved. If not set, will save all pages to a PDF file by default.
+
+`savePdfSettings`: Specify the save settings. Please refer to [`SavePdfSettings`]({{ site.api }}interface/idocument/savepdfsettings.html).
+
+**Return Values**
+
+A Promise object which will be resolved with `Blob` of the saved PDF file.
+
+**Code Snippet**
+
+```typescript
+const pdfSettings = {
+ author: "Dynamsoft",
+ compression: "pdf/jpeg",
+ pageType: "page/a4",
+ creator: "DDV",
+ creationDate: "D:20230101085959-08'00'",
+ keyWords: "samplepdf",
+ modifiedDate: "D:20230101090101-08'00'",
+ producer: "Dynamsoft Document Viewer",
+ subject: "SamplePdf",
+ title: "SamplePdf",
+ version: "1.5",
+ quality: 90,
+ password: "dynamsoft",
+ saveAnnotation: "annotation",
+ imageScaleFactor: 1,
+};
+
+// Save the fifth, sixth, seventh pages to a multi-page PDF file with the specified pdf settings.
+const result1 = await firstDoc.saveToPdf([4,5,6], pdfSettings);
+
+// Save the whole document to a multi-page PDF file with the specified pdf settings.
+const result2 = await firstDoc.saveToPdf(pdfSettings);
+```
+
+**Promise Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80001 | License string is invalid.
+ -80002 | *XXX(LicenseModuleName)* module license has expired.
+ -80003 | *XXX(LicenseModuleName)* module license is missing.
+ -80004 | *XXX(LicenseModuleName)* module license version does not match.
+ -80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80305 | There is no image in the current document.
+ -80318 | The document contains unsupported fonts, which may result in font loss after saving.
+
+### print()
+
+Use the browser’s built-in print feature to print the specified image(s) and whether printable annotations can be printed
+
+**Syntax**
+
+```typescript
+print(printSettings?: PrintSettings);
+print(indices: number[], printSettings?: PrintSettings);
+```
+
+**Parameters**
+
+`indices`: The array of page indices which will be printed. If not set, will export all pages to the browser’s built-in print window.
+
+`printSettings`: Specify the print settings. Please refer to [`PrintSettings`]({{ site.api }}interface/idocument/printsettings.html).
+
+**Return Values**
+
+`true`: Successfully.
+
+`false`: Failed.
+
+---
+
+**Code Snippet**
+
+```typescript
+// To print the whole doc pages
+firstDoc.print();
+
+// To print the second and third pages
+firstDoc.print([1,2]);
+
+// To print the whole doc pages, including printable annotations.
+firstDoc.print({
+ printAnnotation: true;
+});
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80305 | There is no image in the current document.
+
+### createTextSearcher()
+
+Create a text searcher.
+
+**Syntax**
+
+```typescript
+createTextSearcher(text: string, options?: SearchTextOptions): IDocTextSearcher;
+```
+
+**Parameters**
+
+`text`: Text to search
+
+`options`: Please refer to [`SearchTextOptions`](/api/interface/searchtextoptions.md).
+
+**Return Values**
+
+An [`IDocTextSearcher`](/api/interface/idocument/idoctextsearcher.md) object.
+
+---
+
+**Code Snippet**
+
+```typescript
+const searcher = firstDoc.createTextSearcher("text",{caseSensitive:false})
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
diff --git a/_v4.0/api/namespace/ddv.md b/_v4.0/api/namespace/ddv.md
new file mode 100644
index 0000000..41df5fb
--- /dev/null
+++ b/_v4.0/api/namespace/ddv.md
@@ -0,0 +1,408 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer API Reference - Namespace - Dynamsoft.DDV
+keywords: Documentation, Dynamsoft Document Viewer, API Reference, Namespace, Dynamsoft.DDV
+breadcrumbText: Dynamsoft.DDV
+description: Dynamsoft Document Viewer Documentation API Reference Namespace Dynamsoft.DDV Page
+---
+
+# Dynamsoft.DDV
+
+## Index
+
+**Handler Configuration**
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` setProcessingHandler()`](#static-setprocessinghandler) | Set a processing handler to the DDV system. |
+
+**Members**
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` documentManager`](#static-documentmanager) | [`DocumentManager`]({{ site.api }}class/documentmanager.html) instance. |
+| [` annotationManager`](#static-annotationmanager) | [`AnnotationManager`]({{ site.api }}class/annotationmanager.html) instance. |
+
+**Classes**
+
+- [DocumentManager]({{ site.api }}class/documentmanager.html)
+- [AnnotationManager]({{ site.api }}class/annotationmanager.html)
+- [EditViewer]({{ site.api }}class/editviewer.html)
+- [CaptureViewer]({{ site.api }}class/captureviewer.html)
+- [PerspectiveViewer]({{ site.api }}class/perspectiveviewer.html)
+- [BrowseViewer]({{ site.api }}class/browseviewer.html)
+- [CustomViewer]({{ site.api }}class/customviewer.html)
+
+- Advanced
+ - [ImageFilter]({{ site.api }}class/advanced/imagefilter.html)
+ - [DocumentDetect]({{ site.api }}class/advanced/documentdetect.html)
+
+**Methods**
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` getDefaultUiConfig()`](#static-getdefaultuiconfig) | Get default UiConfig object. |
+| [` addFonts()`](#static-addfonts) | Add font to library. |
+| [` clearLastError()`](#static-clearlasterror) | Clear the last error or warning. |
+| [` unload()`](#static-unload) | Unload all DDV resources. |
+
+**Properties**
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` lastError `](#static-lasterror) | Return the last error or warning. |
+
+**Events**
+
+| API Name | Description |
+| -------- | -------------------------------------------------- |
+| [` on()`](#static-on) | Bind a listener to the specified event. |
+| [` off()`](#static-off) | Unbind event listener(s) from the specified event. |
+
+***Integrated Events***
+
+| Event Name | Description |
+| --------------------- | ------------------------------------ |
+| [`error`](#error) | Triggered when any error occurs. |
+| [`warning`](#warning) | Triggered when any warning occurs . |
+| [`verbose`](#verbose) | Triggered when DDV is running. |
+| [`info`](#info) | Triggered during various operations. |
+
+## Handler Configuration
+
+### `` setProcessingHandler()
+
+Set a processing handler to the DDV system.
+
+**Syntax**
+
+```typescript
+static setProcessingHandler(handlerType: HandlerType, handler: any): void;
+```
+
+**Parameters**
+
+`handlerType`: The type of processing handler.
+
+A `HandlerType` can be one of two types.
+
+```typescript
+type HandlerType = "documentBoundariesDetect"|"imageFilter";
+```
+
+`handler`: The handler to set. Please refer to [IDocumentDetect]({{ site.api }}interface/idocumentdetect.html) and [IImageFilter]({{ site.api }}interface/iimagefilter.html).
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+**Remark**
+
+- Please configure the handler before creating
+- If `documentBoundariesDetect` handler is not set, the default element `Dynamsoft.DDV.Elements.AutoDetect` will be disabled.
+- If `imageFilter` handler is not set, the default element `Dynamsoft.DDV.Elements.Filter` will be disabled.
+- [How to configure image filter]({{ site.features }}advanced/imagefilter.html)
+- [How to configure boundaries detection]({{ site.features }}advanced/documentdetect.html)
+
+## Member
+
+### `` documentManager
+
+[`DocumentManager`]({{ site.api }}class/documentmanager.html) instance.
+
+**Code Snippet**
+
+```typescript
+Dynamsoft.DDV.Core.license = "Your-License-String";
+Dynamsoft.DDV.Core.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-document-viewer@latest/dist/engine"; // lead to a folder containing the distributed WASM files
+await Dynamsoft.DDV.Core.init();
+
+const docManager = Dynamsoft.DDV.documentManager;
+```
+
+### `` annotationManager
+
+[`AnnotationManager`]({{ site.api }}class/annotationmanager.html) instance.
+
+**Code Snippet**
+
+```typescript
+Dynamsoft.DDV.Core.license = "Your-License-String";
+Dynamsoft.DDV.Core.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-document-viewer@latest/dist/engine"; // lead to a folder containing the distributed WASM files
+await Dynamsoft.DDV.Core.init();
+
+const annotManager = Dynamsoft.DDV.annotationManager;
+```
+
+
+## Methods
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` getDefaultUiConfig()`](#static-getdefaultuiconfig) | Get default UiConfig object. |
+| [` clearLastError()`](#static-clearlasterror) | Clear the last error or warning. |
+| [` unload()`](#static-unload) | Unload all DDV resources. |
+
+### `` getDefaultUiConfig()
+
+Get default UiConfig object.
+
+**Syntax**
+
+```typescript
+static getDefaultUiConfig(viewerType: ViewerType): UiConfig | null;
+```
+
+**Parameters**
+
+`viewerType`: A `ViewerType` can be one of four types.
+
+```typescript
+type ViewerType = "editViewer"|"captureViewer"|"perspectiveViewer"|"browseViewer";
+```
+
+
+**Return Values**
+
+The [default UiConfig]({{ site.ui }}default_ui.html) object for each kind of viewer.
+
+**Code Snippet**
+
+```typescript
+const defaultEditUi = Dynamsoft.DDV.getDefaultUiConfig("editViewer");
+```
+
+**Warning**
+
+ Error Code | Error Message | API Return Value
+--------|------------------------------------------------------------------------|----------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `null`
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `null`
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.| `null`
+
+### `` addFonts()
+
+Add font to library. You can fetch a font via an URL or use the [`queryLocalFonts()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/queryLocalFonts) API to get the fonts installed on the local system.
+
+**Syntax**
+
+```typescript
+addFonts(fonts: Blob[]): Promise;
+```
+
+**Parameters**
+
+`fonts`: Specify the fonts to add.
+
+**Return Values**
+
+Array of font names.
+
+**Exception**
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+
+
+### `` clearLastError()
+
+Clear the last error or warning.
+
+**Syntax**
+
+```typescript
+static clearLastError(): void;
+```
+
+**Remark**
+
+- Once called this method, [`lastError`](#static-lasterror) will return `undefined`.
+
+### `` unload()
+
+Unload all DDV resources.
+
+**Syntax**
+
+```typescript
+static unload(): void;
+```
+
+## Properties
+
+| API Name | Description |
+| ------------------------------- | ------------------------------------------------- |
+| [` lastError `](#static-lasterror) | Return the last error or warning. |
+
+### `` lastError
+
+Return the last error or warning.
+
+**Syntax**
+
+```typescript
+static readonly lastError: DDVError;
+```
+
+**Return Values**
+
+A [`DDVError`]({{ site.api }}interface/ddverror.html) object.
+
+## Events
+
+| API Name | Description |
+| -------- | -------------------------------------------------- |
+| [` on()`](#static-on) | Bind a listener to the specified event. |
+| [` off()`](#static-off) | Unbind event listener(s) from the specified event. |
+
+### `` on()
+
+Bind a listener to the specified event.
+
+**Syntax**
+
+```typescript
+static on(eventName: EventName, listener:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It should be [an integrated event name](#integrated-events).
+
+`listener`: Specify the listener.
+
+**Code Snippet**
+
+```typescript
+Dynamsoft.DDV.on("error", (e)=>{
+ console.log(e.message, e.cause);
+});
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+### `` off()
+
+Unbind event listener(s) from the specified event.
+
+**Syntax**
+
+```typescript
+static off(eventName: EventName, listener?:(event:EventObject)=>void): void;
+```
+
+**Parameters**
+
+`eventName`: Specify the event name. It should be [an integrated event name](#integrated-events).
+
+`listener`: Specify the listener. If no listener is specified, unbind all event listeners from the specified event.
+
+**Code Snippet**
+
+```typescript
+Dynamsoft.DDV.off("error");
+```
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+ -80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+
+### Integrated Events
+
+| Event Name | Description |
+| --------------------- | ------------------------------------ |
+| [`error`](#error) | Triggered when any error occurs. |
+| [`warning`](#warning) | Triggered when any warning occurs. |
+| [`verbose`](#verbose) | Triggered when DDV is running. |
+| [`info`](#info) | Triggered during various operations. |
+
+#### error
+
+Triggered when any error occurs.
+
+**Callback**
+
+An EventObject which contains the detailed error info.
+
+**Attributes**
+
+[`DDVError`]({{ site.api }}interface/ddverror.html): Detailed error info.
+
+#### warning
+
+Triggered when any warning occurs.
+
+**Callback**
+
+An EventObject which contains the detailed warning info.
+
+**Attributes**
+
+[`DDVError`]({{ site.api }}interface/ddverror.html): Detailed warning info.
+
+#### verbose
+
+Triggered when DDV is running.
+
+**Callback**
+
+EventObject array which contain the detailed verbose info.
+
+**Example**
+
+```typescript
+Dynamsoft.DDV.on("verbose", (...args) => {
+ console.log(...args);
+ if (args[0].cause) {
+ console.error(args[0].cause);
+ }
+});
+```
+
+#### info
+
+Triggered for any of the following tasks:
+
+- `init`
+- `loadSource`
+- `save`
+- `filter`
+- `perspective`
+- `loadWasm`
+- `printPreparation`
+
+See [`InfoObject`]({{ site.api }}interface/infoobject.html) for details.
+
+**Callback**
+
+[`InfoObject`]({{ site.api }}interface/infoobject.html) which contains different attributes depending on the type of event.
+
+**Example**
+
+```js
+DDV.on("info", (event) => {
+ if(event.type === "loadSource" && event.status === "Pending"){
+ console.log("Begin loading file")
+ }
+})
+```
\ No newline at end of file
diff --git a/_v4.0/features/index.md b/_v4.0/features/index.md
new file mode 100644
index 0000000..15fc325
--- /dev/null
+++ b/_v4.0/features/index.md
@@ -0,0 +1,53 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Features
+keywords: Documentation, Dynamsoft Document Viewer, Features
+breadcrumbText: User Interface
+description: Dynamsoft Document Viewer Documentation Features
+---
+
+# Features
+
+Generally, the key features of DDV are shown as below.
+
+## Data Management
+
+Data management is to manage the data which is imported into DDV.
+
+How does DDV implement data management? First of all, there are two concepts which need to be introduced, document and page.
+
+Page can be understood as a page, currently an image, which is the smallest unit of managing data. Each page has a unique pageUid.
+
+And the pages are placed in the document. Each document also has its unique docUid, one document after another makes up the whole data.
+
+
+
+So manage data is to manage documents and pages.
+
+- [Document management]({{ site.features }}datamanagement/docmanagement.html)
+- [Page management]({{ site.features }}datamanagement/pagemanagement.html)
+
+Actually, if you are using the default UI of DDV, the data has been processed and managed internally.
+
+Starting from version 2.0, DDV supports annotation functionalities, which means that annotation data also needs to be managed.
+
+- [Annotation management]({{ site.features }}datamanagement/annotmanagement.html)
+
+## Viewers
+
+Viewers are used to display the data. According to the different uses of viewers, DDV provides five different viewer types, which are implemented through five viewer classes.
+
+- [Edit Viewer]({{ site.features }}viewers/editviewer.html)
+- [Capture Viewer]({{ site.features }}viewers/captureviewer.html)
+- [Perspective Viewer]({{ site.features }}viewers/perspectiveviewer.html)
+- [Browse Viewer]({{ site.features }}viewers/others.html#browse-viewer)
+- [Custom Viewer]({{ site.features }}viewers/others.html#custom-viewer)
+{% comment %}- [Data synchronisation between viewers]({{ site.features }}viewers/datasync.html){% endcomment %}
+
+## Advanced
+
+- [How to configure image filter]({{ site.features }}advanced/imagefilter.html)
+- [How to configure boundaries detection]({{ site.features }}advanced/documentdetect.html)
\ No newline at end of file
diff --git a/_v4.0/features/viewers/others.md b/_v4.0/features/viewers/others.md
new file mode 100644
index 0000000..c2b5684
--- /dev/null
+++ b/_v4.0/features/viewers/others.md
@@ -0,0 +1,61 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Features - Other Viewers
+keywords: Documentation, Dynamsoft Document Viewer, Features, Other Viewers
+breadcrumbText: Other Viewers
+description: Dynamsoft Document Viewer Documentation Features, Other Viewers
+---
+
+# Other Viewers
+
+## Browse Viewer
+
+Browse Viewer is used to display pages in multiple-mode, pages can be multiple selected in this viewer.
+
+- [Default user interface]({{ site.ui }}default_ui.html#browse-viewer)
+- [Default viewer configuration]({{ site.viewer }}viewerconfig.html#browse-viewer)
+
+```typescript
+const browseViewer = new Dynamsoft.DDV.BrowseViewer({
+ container: document.getElementById("viewer"),
+});
+
+browseViewer.openDocument("docUid"); // Open a document which has pages
+```
+
+### Select page(s) via programming
+
+- Select the second and third pages by using [`selectPages()`]({{ site.api }}class/browseviewer.html#selectpages).
+
+ ```typescript
+ browseViewer.selectPages([1,2]);
+ ```
+
+- Select all pages by using [`selectAllPages()`]({{ site.api }}class/browseviewer.html#selectallpages).
+
+ ```typescript
+ browseViewer.selectAllPages();
+ ```
+
+### Multiple select via UI
+
+To enable multiple select mode, you need to set [`multiselectMode`]({{ site.api }}class/browseviewer.html#multiselectmode) to `true`.
+
+In this case, you can select multiple pages by clicking on them in the viewer without the need to additionally press the Ctrl key.
+
+```typescript
+browseViewer.multiselectMode = true;
+```
+
+## Custom Viewer
+
+Custom Viewer does not have any built-in UI or functionality, it is used for creating your own viewer.
+
+```typescript
+const customViewer = new Dynamsoft.DDV.CustomViewer({
+ container: document.getElementById("viewer"),
+});
+```
\ No newline at end of file
diff --git a/_v4.0/gettingstarted/add_dependency.md b/_v4.0/gettingstarted/add_dependency.md
new file mode 100644
index 0000000..0cb8051
--- /dev/null
+++ b/_v4.0/gettingstarted/add_dependency.md
@@ -0,0 +1,79 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Getting Started - Adding the dependency
+keywords: Documentation, Dynamsoft Document Viewer, Getting Started, Adding the dependency
+breadcrumbText: Adding the dependency
+description: Dynamsoft Document Viewer Documentation Getting Started, Adding the dependency
+---
+
+# Adding the dependency
+
+To use the SDK, we need to include the package below.
+
+- `dynamsoft-document-viewer`: Required, it provides functions to create the viewers.
+
+
+## Use a CDN
+
+The simplest way to include the SDK is to use either the [jsDelivr](https://jsdelivr.com/) or [UNPKG](https://unpkg.com/) CDN.
+
+- jsDelivr
+
+ ```html
+
+
+ ```
+
+- UNPKG
+
+ ```html
+
+
+ ```
+
+## Host the SDK yourself
+
+Besides using the CDN, you can also download the Solution and host related files on your own website/server before including it in your application.
+
+Options to download the SDK:
+
+- From the website
+
+ [Download the JavaScript ZIP package](https://www.dynamsoft.com/document-viewer/downloads)
+
+- yarn
+
+ ```cmd
+ yarn add dynamsoft-document-viewer@latest
+ ```
+
+- npm
+
+ ```cmd
+ npm install dynamsoft-document-viewer@latest
+ ```
+
+Depending on how you downloaded the SDK and where you put it, you can typically include it like this:
+
+ ```html
+
+
+
+ ```
+
+or
+
+ ```html
+
+
+ ```
+
+or
+
+ ```typescript
+ import { DDV } from 'dynamsoft-document-viewer';
+ import "dynamsoft-document-viewer/dist/ddv.css";
+ ```
\ No newline at end of file
diff --git a/_v4.0/gettingstarted/helloworld.md b/_v4.0/gettingstarted/helloworld.md
new file mode 100644
index 0000000..a03bbe9
--- /dev/null
+++ b/_v4.0/gettingstarted/helloworld.md
@@ -0,0 +1,146 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Getting Started - Creating HelloWorld
+keywords: Documentation, Dynamsoft Document Viewer, Getting Started, Creating HelloWorld
+breadcrumbText: Creating HelloWorld
+description: Dynamsoft Document Viewer Documentation Getting Started, Creating HelloWorld
+---
+
+# Creating HelloWorld
+
+In this section, we’ll break down and show all the steps needed to build the HelloWorld.
+
+### Mobile View Mockup
+
+
+
+### Desktop View Mockup
+
+
+
+We’ll build on this skeleton page:
+
+```html
+
+
+
+
+
+
+ DDV - HelloWorld
+
+
+
+
+
+```
+
+## Adding the dependency
+
+Please refer to [Adding the dependency]({{ site.gettingstarted }}add_dependency.html).
+
+## Define necessary HTML elements
+
+For HelloWorld, we define below elements.
+
+- Container to hold the viewer
+
+```html
+
+```
+
+- Container's style
+
+```html
+
+```
+
+## SDK initialization
+
+```javascript
+// Public trial license which is valid for 24 hours
+// You can request a 30-day trial key from https://www.dynamsoft.com/customer/license/trialLicense/?product=ddv
+Dynamsoft.DDV.Core.license = "DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9";
+Dynamsoft.DDV.Core.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-document-viewer@latest/dist/engine";
+// Preload DDV Resource
+Dynamsoft.DDV.Core.loadWasm();
+await Dynamsoft.DDV.Core.init();
+```
+
+## Create an edit viewer
+
+```javascript
+// Create an edit viewer
+const editViewer = new Dynamsoft.DDV.EditViewer({
+ container: "container",
+ uiConfig: Dynamsoft.DDV.getDefaultUiConfig("editViewer"),
+});
+```
+
+## Review the complete code
+
+```html
+
+
+
+
+
+
+ DDV - HelloWorld
+
+
+
+
+
+
+
+
+
+```
diff --git a/_v4.0/gettingstarted/sys_requirements.md b/_v4.0/gettingstarted/sys_requirements.md
new file mode 100644
index 0000000..b3fcf4c
--- /dev/null
+++ b/_v4.0/gettingstarted/sys_requirements.md
@@ -0,0 +1,32 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Getting Started - System Requirements
+keywords: Documentation, Dynamsoft Document Viewer, Getting Started, System Requirements
+breadcrumbText: System Requirements
+description: Dynamsoft Document Viewer Documentation Getting Started, System Requirements
+---
+
+
+# System Requirements
+
+The SDK requires the following features to work:
+
+- `WebAssembly`, `Blob`, `URL`/`createObjectURL`, `Web Workers`
+
+ The above four features are required for the SDK to work.
+
+## Supported Browsers
+
+The following table is a list of supported browsers based on the above requirements:
+
+ | Browser Name | PC | Mobile |
+ | :----------: | :------------------------------: | :---------: |
+ | Chrome | v75+ | v75+ |
+ | Firefox | v69+ | v79+ |
+ | Safari | v14+ | v15+ |
+ | Edge | v79+ | v92+ |
+
+Apart from the browsers, the operating systems may impose some limitations of their own that could restrict the use of the SDKs.
\ No newline at end of file
diff --git a/_v4.0/index.md b/_v4.0/index.md
new file mode 100644
index 0000000..ee7075e
--- /dev/null
+++ b/_v4.0/index.md
@@ -0,0 +1,61 @@
+---
+layout: home-page
+title: Dynamsoft Document Viewer Documentation
+keywords: Dynamsoft Document Viewer, documentation
+description: Dynamsoft Document Viewer Documentation Homepage
+---
+
+# Dynamsoft Document Viewer
+
+
+- [Introduction]({{site.introduction}}index.html)
+- Getting Started
+ - [System Requirements]({{ site.gettingstarted }}sys_requirements.html)
+ - [Adding the dependency]({{ site.gettingstarted }}add_dependency.html)
+ - [SDK Initialization]({{ site.gettingstarted }}sdk_init.html)
+ - [Creating HelloWorld]({{ site.gettingstarted }}helloworld.html)
+ - Libraries and Frameworks
+ - [Angular](/gettingstarted/angular.md)
+ - [React](/gettingstarted/react.md)
+ - [Vue](/gettingstarted/vue.md)
+- [Features]({{ site.features }}index.html)
+ - Data Management
+ - [Document Management]({{ site.features }}datamanagement/docmanagement.html)
+ - [Page Management]({{ site.features }}datamanagement/pagemanagement.html)
+ - [Annotation management]({{ site.features }}datamanagement/annotmanagement.html)
+ - Viewers
+ - [Edit Viewer]({{ site.features}}viewers/editviewer.html)
+ - [Capture Viewer]({{ site.features }}viewers/captureviewer.html)
+ - [Perspective Viewer]({{ site.features }}viewers/perspectiveviewer.html)
+ - [Browse Viewer]({{ site.features }}viewers/others.html#browse-viewer)
+ - [Custom Viewer]({{ site.features }}viewers/others.html#custom-viewer)
+ {% comment %} - [Data synchronisation between viewers]({{ site.features }}viewers/datasync.html){% endcomment %}
+ - Advanced
+ - [Image Filter]({{ site.features }}advanced/imagefilter.html)
+ - [Document Detection]({{ site.features }}advanced/documentdetect.html)
+- [Viewer Configuration]({{ site.viewer }}index.html)
+ - [ViewerConfig]({{ site.viewer }}viewerconfig.html)
+ - [Structure]({{ site.viewer }}viewerconfig.html#structure)
+ - [Default ViewerConfig]({{ site.viewer }}viewerconfig.html#default-viewerconfig)
+ - [How to customize viewer]({{ site.viewer }}customize.html)
+ - [Viewer Style]({{ site.viewer }}customize.html#viewer-style)
+ - [Viewer properties]({{ site.viewer }}customize.html#viewer-properties)
+- [User Interface]({{ site.ui }}index.html)
+ - [UiConfig]({{ site.ui }}uiconfig.html)
+ - [Structure]({{ site.ui }}uiconfig.html#structure)
+ - [How to configure]({{ site.ui }}uiconfig.html#how-to-configure)
+ - [Reference]({{ site.ui }}uiconfig.html#reference)
+ - [Default Elements]({{ site.ui }}default_elements.html)
+ - [Default User Interface]({{ site.ui }}default_ui.html)
+ - [Edit viewer]({{ site.ui }}default_ui.html#edit-viewer)
+ - [Capture viewer]({{ site.ui }}default_ui.html#capture-viewer)
+ - [Perspective viewer]({{ site.ui }}default_ui.html#perspective-viewer)
+ - [Browse viewer]({{ site.ui }}default_ui.html#browse-viewer)
+ - [How to customize UI]({{ site.ui }}customize/index.html)
+ - [Layout]({{ site.ui }}customize/layout.html)
+ - [Elements]({{ site.ui }}customize/elements.html)
+ - [Update UI dynamically]({{ site.ui }}customize/dynamically.html)
+- [API Reference]({{ site.api }}index.html)
+- [Release Notes]({{ site.releasenotes }}index.html)
+- [FAQ]({{ site.faq }}index.html)
+- [Upgrade Guide](/upgrade-guide/index.md)
\ No newline at end of file
diff --git a/_v4.0/introduction/index.md b/_v4.0/introduction/index.md
new file mode 100644
index 0000000..f4465b7
--- /dev/null
+++ b/_v4.0/introduction/index.md
@@ -0,0 +1,69 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: JavaScript PDF Viewer SDK | Dynamsoft Document Viewer
+keywords: Documentation, Dynamsoft Document Viewer, Introduction
+breadcrumbText: Introduction
+description: Powerful JavaScript PDF viewer & document viewer SDK. Integrate seamless document viewing into your web apps with Dynamsoft Document Viewer.
+---
+
+# Introduction to Dynamsoft Document Viewer
+
+Dynamsoft Document Viewer is a browser-based JavaScript SDK designed for viewing and editing images and PDFs. It provides a wide range of functionalities, including PDF annotation, page manipulation, image quality enhancement, and document saving. To see it in action, please visit this [online demo](https://demo.dynamsoft.com/document-viewer/).
+
+## Security
+
+Dynamsoft Document Viewer does not rely on any external third-party JavaScript library. All processing, such as rendering and editing, is securely performed within the browser. This architecture eliminates the need for a server-side backend, ensuring security compliance and scalability.
+
+The SDK's [redaction](/features/datamanagement/annotmanagement.md#redaction) feature goes beyond visual masking - it permanently removes the underlying data from the document. This ensures that sensitive information (PII, classified text, financial data) cannot be recovered or leaked, making it ideal for industries with strict compliance requirements like legal, healthcare, and government.
+
+## Browser and Platform Compatibility
+
+Dynamsoft Document Viewer is designed to work seamlessly across different browsers and platforms. It is compatible with major browsers like Chrome, Firefox, Safari, and Edge, ensuring a consistent user experience. Additionally, it supports various operating systems, including Windows, macOS, Linux, iOS, and Android, allowing users to access documents from any device.
+
+## Supported File Types
+
+Users can open, edit, and save PDFs, as well as images in various formats, such as JPEG, PNG, and TIFF.
+
+## Annotation Types
+
+Dynamsoft Document Viewer supports a variety of annotation types to enhance document interaction and collaboration. Users can add, edit, and delete annotations such as:
+
+- text
+- highlight
+- underline
+- strikeout
+- shape
+- stamp
+- freehand drawing
+- redaction
+
+## Data Management Concepts
+
+Dynamsoft Document Viewer organizes data using two main concepts: "document" and "page." A document can contain one or multiple pages, and each page must belong to a single document.
+
+- Page: The smallest unit of data management. Each page has a unique page ID.
+- Document: A collection of pages, each with a unique doc ID. Documents collectively make up the entire data set.
+
+Managing data, therefore, involves managing documents and pages.
+
+- [Document Management]({{ site.features }}datamanagement/docmanagement.html)
+- [Page Management]({{ site.features }}datamanagement/pagemanagement.html)
+
+If you are using the default UI of DDV, data processing and management are handled internally.
+
+## UI Customization
+
+The SDK offers extensive customization options, enabling developers to tailor the UI to meet specific application needs and branding requirements.
+
+## Designed to Support Diverse Document Workflows
+
+Dynamsoft Document Viewer is built to support a wide range of document-centric workflows with its document viewing, editing, and scanning features. It has four built-in viewer types to suit different use cases:
+
+* **Edit Viewer**: Enables viewing and editing of documents with annotation support.
+* **Capture Viewer**: Integrates camera controls for streamlined, continuous capture workflows.
+* **Perspective Viewer**: Allows document cropping with perspective transformation.
+* **Browse Viewer**: Suitable for previewing multi-page documents or navigating document collections.
+
diff --git a/_v4.0/releasenotes/index.md b/_v4.0/releasenotes/index.md
new file mode 100644
index 0000000..a23ab16
--- /dev/null
+++ b/_v4.0/releasenotes/index.md
@@ -0,0 +1,414 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer - Release Notes
+keywords: Documentation, Dynamsoft Document Viewer, Release Notes
+breadcrumbText: Release Notes
+description: Dynamsoft Document Viewer Documentation Release Notes
+---
+
+# Release Notes
+
+## 4.0 (04/21/2026)
+
+### New Features
+
+* Added support for [redaction annotation](/features/datamanagement/annotmanagement.md#redaction).
+* Changed PDF rendering mode to high-fidelity rendering.
+
+### API Changes
+
+* Added redaction-related interfaces: [`Redaction`](/api/class/annotation/redaction.md), [`RedactionAnnotationOptions`](/api/interface/annotationinterface/redactionannotationoptions.md), [`RedactionStyle`](/api/interface/annotationinterface/redactionstyle.md), [`applyRedactions()`](/api/class/annotationmanager.md#applyredactions).
+* Added redaction-related UI elements.
+* Added `printPreparation` to progress info and renamed attribute `current` to `processed` for `LoadSourceInfo` and `SaveSourceInfo`. See [`InfoObject`](/api/interface/infoobject.md).
+
+### Improvements
+
+Updated third-party libraries to enhance security.
+
+### Bug Fixes
+
+* Fixed loading of interlaced PNGs.
+* Fixed loading of some non-standard PDFs with redundant trailing data.
+
+
+
+## 3.2.1 (03/10/2026)
+
+Updated third-party libraries to enhance security.
+
+## 3.2 (01/13/2026)
+
+### Improvements
+
+* Improved the context of search results, which now display the word before the searched word.
+* Improved the rendering of selected annotations by reducing the number of items to draw.
+* Improved the performance of selecting multiple annotations.
+* Added a consistency check between the JavaScript and resource file versions.
+* Added support for pinch-to-zoom under `textSelection` mode of `EditViewer` for mobile.
+* Updated third-party libraries to enhance security.
+
+### Bug Fixes
+
+Fixed the text overflow issue in custom stamps.
+
+
+## 3.1 (10/16/2025)
+
+### UX Changes
+
+For Edit Viewer:
+
+* Added support for panning images in `textSelection` mode.
+* Text markup annotations can be modified after being cropped.
+* Return to `pan` mode if `textSelection` mode is turned off on mobile by clicking the icon.
+* Added support for returning to `pan` mode by pressing ESC.
+
+For Edit Viewer and Browse Viewer:
+
+When the cursor is around the viewer's edges when selecting text or dragging the thumbnails, auto-scrolling will be triggered. It can be configured using the [`enableAutoScrollForTextSelection`](/api/interface/editviewerconfig.md#enableautoscrollfortextselection) property for Edit Viewer and the [`enableAutoScrollForDragPages`](/api/interface/browseviewerconfig.md#enableautoscrollfordragpages) property for Browse Viewer.
+
+### API Changes
+
+Added interfaces for better UI customizability.
+
+* [`getAnnotationDrawingStyle()`](/api/class/editviewer.md#getannotationdrawingstyle) method for Edit Viewer
+* [`undoRedoStateChanged`](/api/class/editviewer.md#undoredostatechanged) event for Edit Viewer
+* [`annotationDrawingStyleChanged`](/api/class/editviewer.md#annotationdrawingstylechanged) event for Edit Viewer
+* [`scroll`](/api/class/editviewer.md#scroll) event for Edit Viewer and Browse Viewer
+* [`paginationChanged`](/api/class/editviewer.md#paginationchanged) event for all the viewers
+* [`cropMode`](/api/class/editviewer.md#cropmode) property for Edit Viewer. The [`crop()`](/api/class/editviewer.md#crop) method of Edit Viewer will choose which images to crop based on the `cropMode` if no image indices are passed.
+
+### Improvements
+
+* Increased the FPS of rendering documents, especially documents with lots of pages.
+* Optimized the performance of `updateOptions()`.
+* Moved the magnifier into a separate layer to improve the performance and avoid being blocked.
+
+### Bug Fixes
+
+* Fixed a bug where changes of the layout will reset the position of the current document page to its top-left.
+* Fixed a bug where the text is shifted if the PDF's media box has shifts.
+
+## 3.0 (07/08/2025)
+
+### Features Highlights
+
+* Added support for text selection. We can now copy and annotate selected text.
+* Added three text markup annotations: `highlight`, `strikeout` and `underline`.
+* Added support for text search.
+
+### API Changes
+
+* Added classes for text markup annotations.
+ * [`Highlight`](/api/class/annotation/highlight.md)
+ * [`Underline`](/api/class/annotation/underline.md)
+ * [`Strikeout`](/api/class/annotation/strikeout.md)
+* Added interfaces to set up text markup annotations.
+ * [`HighlightAnnotationOptions`](/api/interface/annotationinterface/highlightannotationoptions.md)
+ * [`UnderlineAnnotationOptions`](/api/interface/annotationinterface/underlineannotationoptions.md)
+ * [`StrikeoutAnnotationOptions`](/api/interface/annotationinterface/strikeoutannotationoptions.md)
+ * [`HighlightStyle`](/api/interface/annotationinterface/highlightstyle.md)
+ * [`UnderlineStyle`](/api/interface/annotationinterface/underlinestyle.md)
+ * [`StrikeoutStyle`](/api/interface/annotationinterface/strikeoutstyle.md)
+ * [`RectXY`](/api/interface/rectxy.md)
+* Added new [tool mode](/api/class/editviewer.md#toolmode) for `EditViewer`: `textSelection`.
+* Added new [annotation modes](/api/class/editviewer.md#annotationmode) for `EditViewer`: `highlight`, `strikeout` and `underline`.
+* Added new buttons in [`ToolbarConfig`](/api/interface/annotationinterface/toolbarconfig.md): `copy`, `highlight`, `strikeout` and `underline`.
+* Added new [elements](/ui/default_elements.md) for `EditViewer`:
+ * TextSelectionMode
+ * TextSearchPanelSwitch
+ * TextSearchPanel
+ * HighlightAnnotation
+ * UnderlineAnnotation
+ * StrikeoutAnnotation
+* Added text selection and search methods and events for [`EditViewer`](/api/class/editviewer.md).
+* Added an [`IDocTextSearcher`](/api/interface/idocument/idoctextsearcher.md) interface that can be created using [`createTextSearcher()`](/api/interface/idocument/index.md#createtextsearcher) of [`IDocument`](/api/interface/idocument/index.md).
+* Added [`isPageModified()`](/api/interface/idocument/index.md#ispagemodified) method to detect whether a page has been modified.
+* Added [`getVisiblePagesInfo()`](/api/class/editviewer.md#getvisiblepagesinfo) for viewers.
+* Added new events for viewers.
+* Updated [`IPageData`](/api/interface/ipagedata.md) to use Promise functions for computing-intensive operations.
+* Updated [`updatePage()`](/api/interface/idocument/index.md#updatepage) to allow updating a page with PDF page content that has annotations.
+* Updated [`addFonts()`](/api/namespace/ddv.md#static-addfonts) to return an array of the names of added fonts.
+* Updated [`DisplayTextConfig`](/api/interface/displaytextconfig.md) for new elements.
+* Removed the options parameter of [`getDefaultUiConfig()`](/api/namespace/ddv.md#static-getdefaultuiconfig).
+
+### Improvements
+
+* Fixed the ineffective quality parameter of [`saveToJpeg()`](/api/interface/idocument/index.md#savetojpeg) if a page is unmodified.
+* Improved cursor styles.
+* Improved the performance of resaving a large PDF file.
+
+
+## 2.1 (12/03/2024)
+
+Version 2.1 of Dynamsoft Document Viewer comes with a suite of exciting new features, improvements to existing features, and performance optimizations.
+
+Dynamsoft Document Viewer now comes with **massively improved performance** for working with huge documents with a large number of high resolution images. Users can expect to load, edit, annotate, and export massive documents with ease.
+
+
+
+### New Features
+
+- Added `enableMagnifier`, which provides a corner magnifier in the [Edit Viewer]({{ site.api }}interface/editviewerconfig.html#enablemagnifier) and [Perspective Viewer]({{ site.api }}interface/perspectiveviewerconfig.html#enablemagnifier). This magnifier creates a zoomed-in view of the selected area to allow for more precise adjustments on touchscreen devices.
+
+- Added keyboard shortcuts for document management. These shortcuts are controlled by [`KeyboardInteractionConfig`]({{ site.api }}interface/keyboardinteractionconfig.html). All shortcuts are available for the Edit Viewer, and only the navigation and page selection shortcuts are available for the Browse Viewer:
+ - Undo/redo
+ - Copy/cut/paste
+ - Annotation/page selection
+ - Scrolling/navigation
+ - Cancel/delete
+
+- Added drag-and-drop image loading with the new `enableLoadSourceByDrag` configuration property for the [Edit]({{ site.api }}interface/editviewerconfig.html#enableloadsourcebydrag), [Browse]({{ site.api }}interface/browseviewerconfig.html#enableloadsourcebydrag), and [Perspective]({{ site.api }}interface/perspectiveviewerconfig.html#enableloadsourcebydrag) Viewers (enabled by default).
+
+- The new [`setAnnotationDrawingStyle`]({{ site.api }}class/editviewer.html#setannotationdrawingstyle) method can now be used when creating annotations to set its default drawing style, for example, to set a custom image to use as the default stamp annotation.
+
+- Added the following flags to restrict annotation editing actions: [`noResize`]({{ site.api }}interface/annotationinterface/flags.html#noresize), [`noRotate`]({{ site.api }}interface/annotationinterface/flags.html#norotate), [`noMove`]({{ site.api }}interface/annotationinterface/flags.html#nomove). These flags are preserved when saving to PDF, and respected when importing into DDV from PDF.
+
+- Added a [`flattened`]({{ site.api }}class/annotation/rectangle.html#flattened) property getter/setter to annotation objects, which flattens the **individual** annotation onto the base image layer. This behavior is also preserved upon saving to PDF. For example, a rectangle annotation may be flattened with [`Rectangle.flattened = true`]({{ site.api }}class/annotation/rectangle.html#flattened).
+
+- Added informative task progression messaging using [`InfoObject`]({{ site.api }}interface/infoobject.html) for event listening. `InfoObject` provides different details for different types.
+
+### Improvements
+
+- Improved general performance.
+
+- Added support for processing much larger documents (over 1000 pages). See performance improvements compared to version 2.0:
+
+{% comment %}
+[Performance chart](/assets/imgs/version-2.1-release-performance-chart.png)
+
+
+Win10 i5-7400 CPU @ 3.00GHz
+
+| Document Type | Number of Pages | File Size | Load Time | Peak Memory Use for Loading | Save Time | Peak Memory Use for Saving |
+| --------------- | ------------------| ------------|------------|------------|------------|------------------------------------------------------------ |
+|
+
+- The annotation toolbar and annotation palette in the Edit Viewer are now optional and can be toggled with [`toolbarConfig`]({{ site.api }}interface/annotationinterface/toolbarconfig.html) and [`paletteConfig`]({{ site.api }}interface/annotationinterface/paletteconfig.html) from [`annotationConfig`]({{ site.api }}interface/annotationconfig.html).
+
+- Removed page scrolling with mouse scroll wheel and touchscreen swiping in single page mode.
+
+- Improved page selection performance in the thumbnail gallery.
+
+## 2.0 (08/20/2024)
+
+**We are excited to introduce version 2.0, which focuses on adding a powerful new annotation feature. This release includes comprehensive support for various types of annotations, new APIs for managing annotations, and advanced UI capabilities for seamless interaction.**
+
+Supported Annotation Types:
+
+- [Rectangle]({{ site.api }}class/annotation/rectangle.html)
+- [Ellipse]({{ site.api }}class/annotation/ellipse.html)
+- [Polygon]({{ site.api }}class/annotation/polygon.html)
+- [Polyline]({{ site.api }}class/annotation/polyline.html)
+- [Line]({{ site.api }}class/annotation/line.html)
+- [Ink]({{ site.api }}class/annotation/ink.html)
+- [TextBox]({{ site.api }}class/annotation/textbox.html)
+- [TextTypewriter]({{ site.api }}class/annotation/texttypewriter.html)
+- [Stamp]({{ site.api }}class/annotation/stamp.html)
+
+### Built-in UI for Annotation
+
+#### Direct Annotation Operations in the UI
+
+- Add, select, and delete annotations
+- Drag, resize, and rotate selected annotations
+- Real-time editing of annotation styles using the palette
+
+#### New Built-in Elements
+
+- Added built-in elements to enhance UI configuration flexibility.
+
+### New APIs for Annotation
+
+- Added the namespace [Dynamsoft.DDV.annotationManager]({{ site.api }}class/annotationmanager.html) and APIs for annotation management:
+
+ - Create, delete, and retrieve annotations based on various conditions
+ - Adjust annotation hierarchy
+ - Handle events triggered by annotation operations
+
+- Added the property [annotationConfig]({{ site.api }}interface/editviewerconstructoroptions.html#annotationConfig) to EditViewerConstructorOptions for configuring the annotations in the viewer, including the toolbar, palette, and default annotation style:
+
+ - [annotationSelectionStyle]({{ site.api }}interface/annotationconfig.html#annotationSelectionStyle): Defines the style of annotation selection.
+ - [inkCreateDelay]({{ site.api }}interface/annotationconfig.html#inkCreateDelay): Specifies the delay for ink creation to support annotations created in multiple strokes.
+ - [showOnTopWhenSelected]({{ site.api }}interface/annotationconfig.html#showOnTopWhenSelected): Determines whether the selected annotation should be displayed on the top layer.
+
+- Added the method [` addFonts()`]({{ site.api }}namespace/ddv.html#static-addfonts) to add fonts to the library.
+
+- Added the method [`selectAnnotations()`]({{ site.api }}class/editviewer.html#selectannotations) to select the specified annotation(s) on the current page.
+
+- Added the method [`getSelectedAnnotations()`]({{ site.api }}class/editviewer.html#getselectedannotations) to retrieve selected annotation(s).
+
+- Add properties [`mediaBox`]({{ site.api }}interface/idocument/pagedata.html#mediaBox) and [`cropBox`]({{ site.api }}interface/idocument/pagedata.html#cropBox) to [`PageData`]({{ site.api }}interface/idocument/pagedata.html) for accurate annotation position calculation.
+
+- Added the property [`annotationMode`]({{ site.api }}class/editviewer.html#annotationmode) to specify or return the annotation mode of the viewer.
+
+- Add the property `saveAnnotation` to the interfaces [`SavePngSettings`]({{ site.api }}interface/idocument/savepngsettings.html), [`SaveJpegSettings`]({{ site.api }}interface/idocument/savejpegsettings.html), or [`SaveTiffSettings`]({{ site.api }}interface/idocument/savetiffsettings.html) to determine whether annotations are saved as part of the image when calling [`document.saveToPng()`]({{ site.api }}interface/idocument/index.html#saveToPng), [`document.saveToJpeg()`]({{ site.api }}interface/idocument/index.html#saveToJpeg), or [`document.saveToTiff()`]({{ site.api }}interface/idocument/index.html#saveToTiff).
+
+- Added the property [`saveAnnotation`]({{ site.api }}interface/idocument/savepdfsettings.html#saveAnnotation) to the interface [`SavePdfSettings`]({{ site.api }}interface/idocument/savepdfsettings.html) to configure whether annotations should be saved when [`document.saveToPdf()`]({{ site.api }}interface/idocument/index.html#saveToPdf) is called.
+
+- Add the parameter [`defaultUiConfigOptions`]({{ site.api }}interface/defaultuiconfigoptions.html) to [` getDefaultUiConfig()`]({{ site.api }}namespace/ddv.html#static-getdefaultuiconfig) to retrieve configurations including annotations.
+
+- Add the parameter [`printSettings`]({{ site.api }}interface/idocument/printsettings.html) to the [`document.print()`]({{ site.api }}interface/idocument/index.html#print) to specify whether printable annotations should be included in the print.
+
+- Added the type `annotation` to [`ToolMode`]({{ site.api }}class/editviewer.html#toolMode) to enable a mode that allows annotations to be manipulated via the UI.
+
+- Added the type `annotationSelectionStyle` to [`EditViewerStyleName`]({{ site.api }}class/editviewer.html#getStyle) for retrieving or updating the annotation selection style.
+
+### Other New APIs
+
+Additionally, we've optimized performance and added several new features to enhance the overall user experience.
+
+- Added the property [`password`]({{ site.api }}interface/idocument/savepdfsettings.html#password) to the interface [`SavePdfSettings`]({{ site.api }}interface/idocument/savepdfsettings.html) for configuring the password of the PDF file to save when [`document.saveToPdf()`]({{ site.api }}interface/idocument/index.html#saveToPdf) is called.
+
+- Added the property [`imageScaleFactor`]({{ site.api }}interface/idocument/savepdfsettings.html#imageScaleFactor) to the interface [`SavePdfSettings`]({{ site.api }}interface/idocument/savepdfsettings.html) for configuring the image scale factor of the PDF file to be saved when [`document.saveToPdf()`]({{ site.api }}interface/idocument/index.html#saveToPdf) is called.
+
+### Improved
+
+- Optimize the display effect of images in thumbnails.
+- Optimize the interactive experience of scaling.
+- Modified the type of [`PdfSource.renderOptions.renderAnnotations`]({{ site.api }}interface/idocument/pdfsource.html#renderAnnotations) to support reading annotations.
+- The method `openDocument()` supports the UID or the document object. This affects the `openDocument()` method in the [`EditViewer`]({{ site.api }}class/editviewer.html#openDocument), [`PerspectiveViewer`]({{ site.api }}class/perspectiveviewer.html#openDocument), [`CaptureViewer`]({{ site.api }}class/captureviewer.html#openDocument), and [`BrowseViewer`]({{ site.api }}class/browseviewer.html#openDocument) classes.
+
+### Changed
+
+- Change the length unit from pixel to point for functions and events related to cropping, for example, [`crop()`]({{ site.api }}class/editviewer.html#crop), [`getCropRect()`]({{ site.api }}class/editviewer.html#getCropRect), [`setCropRect()`]({{ site.api }}class/editviewer.html#setCropRect), [`cropRectDrawn`]({{ site.api }}class/editviewer.html#cropRectDrawn), [`cropRectDeleted`]({{ site.api }}class/editviewer.html#cropRectDeleted),[`cropRectModified`]({{ site.api }}class/editviewer.html#cropRectModified).
+- Change the units of the parameters pageWidth and pageHeight in the method [`insertBlankPage`]({{ site.api }}interface/idocument/index.html#insertblankpage) from inches to points.
+- The related date string format change shifts from format D:YYYYMMDDHHmmSS to D:YYYYMMDDHHmmSSOHH'mm'.
+
+## 1.1 (01/12/2024)
+
+### Improved
+
+- Optimized compatibility with browsers. [>> Detail]({{ site.gettingstarted }}sys_requirements.html#supported-browsers)
+
+### Added
+
+- Added the namespace [`Dynamsoft.DDV.Core`]({{ site.api }}namespace/ddv_core.html).
+
+- Added the property [`license`]({{ site.api }}namespace/ddv_core.html#license) to specify the license string.
+
+- Added the property [`engineResourcePath`]({{ site.api }}namespace/ddv_core.html#engineresourcepath) to specify the path leading to a folder containing the distributed WASM files.
+
+- Added the property [`deviceFriendlyName`]({{ site.api }}namespace/ddv_core.html#devicefriendlyname) to specify a human-readable name for the device which corresponds to its UUID.
+
+- Added the method [`loadWasm()`]({{ site.api }}namespace/ddv_core.html#loadwasm) to load WASM modules before initializing.
+
+- Added the method [`init()`]({{ site.api }}namespace/ddv_core.html#init) to initialize DDV.
+
+- Added the method [`insertBlankPage()`]({{ site.api }}interface/idocument/index.html#insertblankpage) to insert a blank page to the document.
+
+### Removed
+
+The following API is removed.
+
+| API Name | Notes |
+| ------------------------- | ------------------------------------------------------------ |
+| `Dynamsoft.DDV.setConfig()` | Use [`Dynamsoft.DDV.Core.license`]({{ site.api }}namespace/ddv_core.html#license), [`Dynamsoft.DDV.Core.engineResource`]({{ site.api }}namespace/ddv_core.html#engineresourcepath), [`Dynamsoft.DDV.Core.deviceFriendlyName`]({{ site.api }}namespace/ddv_core.html#devicefriendlyname), [`Dynamsoft.DDV.Core.init()`]({{ site.api }}namespace/ddv_core.html#init) instead. |
+
+## 1.0.0 (12/26/2023)
+
+Dynamsoft Document Viewer (DDV) is a versatile SDK designed to offer a range of viewers for configuring and executing various document processing workflows.
+
+### Highlights
+
+#### Efficient Data Management
+
+Organize, retrieve, and manage documents and pages efficiently:
+- Document Management: Document creation/deletion/merging, etc.
+- Page management: Pages in documents loading/saving/deleting/moving, etc.
+
+#### Various Viewers
+
+Various kinds of viewers implement different document processing flows:
+- Edit Viewer: Edit the pages in document, such as, rotating, cropping, filtering, etc. and adjust the layout of the display.
+- Capture Viewer: Control camera, play video stream, and capture the images from camera.
+- Perspective Viewer: Do page boundaries manual adjustment & perspective transformation.
+- Browse Viewer: Display pages in multiple-mode, pages can be multiple selected.
+- Custom Viewer: No built-in UI or functionality, which is used for creating your own viewer.
+
+#### Flexible Customization
+
+Besides using the default user interface and viewer directly, developers can easily and flexibly customize them:
+- [User Interface](https://www.dynamsoft.com/document-viewer/docs/ui/index.html): Layout, elements
+- [Viewer](https://www.dynamsoft.com/document-viewer/docs/viewer/index.html): Styles, viewer properties
+
+#### Advanced Features
+
+DDV provides methods to access document boundaries detection and image filter algorithms.
+- [Image filter](https://www.dynamsoft.com/document-viewer/docs/features/advanced/imagefilter.html): Image filter algorithm which is used by Filter element in Edit Viewer.
+- [Document detection](https://www.dynamsoft.com/document-viewer/docs/features/advanced/documentdetect.html): Document boundaries detection algorithm which is used during capturing images. Recommend using [Dynamsoft Document Normalizer](https://www.dynamsoft.com/document-normalizer/docs/web/programming/javascript/api-reference/document-normalizer-module.html?lang=javascript).
diff --git a/_v4.0/upgrade-guide/index.md b/_v4.0/upgrade-guide/index.md
new file mode 100644
index 0000000..0b73968
--- /dev/null
+++ b/_v4.0/upgrade-guide/index.md
@@ -0,0 +1,49 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Upgrade Guide Dynamsoft Document Viewer Documentation
+keywords: Documentation, Dynamsoft Document Viewer, Upgrade
+breadcrumbText: Upgrade Guide
+description: Upgrade guide for Dynamsoft Document Viewer
+---
+
+# Upgrade Guide
+
+Upgrading Dynamsoft Document Viewer from an old version to the latest version (v3.x as of now) is straightforward. You need to pay attention to the following changes:
+
+* Changes of APIs
+* Changes of [`UIConfig`](/api/interface/uiconfig.md)
+
+
+There are some code snippets that are frequently used and we will talk about the changes you have to make.
+
+## Initialization of Edit Viewer
+
+In v2.x, you can use an additional options parameter to enable the annotation icon in the default UI.
+
+```js
+const editViewer = new Dynamsoft.DDV.EditViewer({
+ container: "container",
+ uiConfig: Dynamsoft.DDV.getDefaultUiConfig("editViewer", {includeAnnotationSet: true}),
+});
+```
+
+In v3.x, the option is removed and the annotation icon is included in the default UI. So you can just initialize it with the following code:
+
+```js
+const editViewer = new Dynamsoft.DDV.EditViewer({
+ container: "container"
+});
+```
+
+## Default UI Config
+
+The default UI elements may be different across different versions. Check out [this post](/ui/default_ui.md) to learn about the default configs.
+
+You can try to unify the UI across versions by specifying the [`UIConfig`](/api/interface/uiconfig.md). But pay attention to supported [elements](/ui/default_elements.md) of different versions.
+
+## Getting the Page Data
+
+Before v3.x, [`getPageData()`](/api/interface/idocument/index.md#getpagedata) returns a promise object, which was time consuming as it required getting all the image blobs. In v3.x, it directly returns an [`IPageData`](/api/interface/ipagedata.md) object and you can retrieve image blobs with its functions.
diff --git a/api/class/annotationmanager.md b/api/class/annotationmanager.md
index cb72734..c02bc74 100644
--- a/api/class/annotationmanager.md
+++ b/api/class/annotationmanager.md
@@ -14,6 +14,8 @@ permalink: /api/class/annotationmanager.html
The `Dynamsoft.DDV.annotationManager` instance will be created automatically as soon as DDV is initialized. Please refer to [`annotationManager`]({{ site.api }}namespace/ddv.html#static-annotationmanager).
+Please note that it is `undefined` if the annotation [plugin](/features/plugins-and-on-demand-loading.md) is not installed.
+
## API Index
**Methods**
diff --git a/api/class/captureviewer.md b/api/class/captureviewer.md
index 7de65e7..6b2c803 100644
--- a/api/class/captureviewer.md
+++ b/api/class/captureviewer.md
@@ -14,6 +14,8 @@ permalink: /api/class/captureviewer.html
Capture Viewer is used to control camera, play video stream, and capture the images from camera.
+Please note that you need to load the camera [plugin](/features/plugins-and-on-demand-loading.md) to use Capture Viewer.
+
## API Index
**Create and Destroy Instances**
@@ -123,6 +125,7 @@ const captureViewer = new Dynamsoft.DDV.CaptureViewer({
-80005 | Domain does not match the domain bound to the *XXX(LicenseModuleName)* module license.
-80050 | DDV.Core.init() has not been set up yet.
-80051 | DDV.Core.init() has not been completed.
+ -80500 | The '<%param%>' plugin is not installed.
**Warning**
diff --git a/api/class/editviewer.md b/api/class/editviewer.md
index 7a3b834..791bfab 100644
--- a/api/class/editviewer.md
+++ b/api/class/editviewer.md
@@ -185,11 +185,13 @@ const thumbnailObj = editViewer.thumbnail;
| -80051 | DDV.Core.init() has not been completed. |
| -80302 | minZoom value cannot be larger than maxZoom value. |
+
**Warning**
| Error Code | Error Message |
| ---------- | ------------------------------------------------------------------------------------------------------------ |
| -80316 | ImageFilter needs to be configured by Dynamsoft.DDV.setProcessingHandler to enable the image filter feature. |
+ -80501 | Some elements are ignored because the required plugin is not installed.
**Remark**
@@ -317,6 +319,12 @@ const pageStyle = editViewer.getStyle("pageStyle");
-80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `null`
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `null`
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
+
### getVisiblePagesInfo()
Get the visible pages info.
@@ -391,6 +399,11 @@ type EditViewerStyleName = "canvasStyle" | "pageStyle" | "currentPageStyle" | "q
-80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported. | `false`
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
**Remark**
@@ -452,7 +465,8 @@ editViewer.updateUiConfig(viewerUi);
-80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false`
-80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false`
-80313 | The element *XXX(ElementName)* is not supported in *XXX(ClassName)* class. | `false`
-
+ -80501 | Some elements are ignored because the required plugin is not installed. | `true`
+
**Remark**
- The updates are independent of whether the viewer is displayed and are updated in real time.
@@ -546,6 +560,12 @@ editViewer.toolMode = "crop";
-80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
+
**Remark**
- If `toolMode` is set to `annotation`, can use [`annotationMode`](#annotationmode) to clarify the specific operation.
@@ -580,6 +600,13 @@ editViewer.annotationMode = "select";
-80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
+
+
**Remark**
- It only take effect when [`toolMode`](#toolmode) is `annotation`.
@@ -890,6 +917,12 @@ setAnnotationDrawingStyle(config: AnnotationDrawingStyleConfig): boolean;
| ---------- | -------------------------------------------- | ---------------- |
| -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `false` |
| -80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `false` |
+
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
### selectAnnotations()
@@ -926,6 +959,12 @@ selectAnnotations(annotationUids: string[]): boolean;
| -80320 | Unknown annotation or incomplete annotation cannot be selected. | `false` |
| -80321 | Flattened annotation cannot be selected. | `false` |
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
+
### getSelectedAnnotations()
Get selected annotation(s).
@@ -953,6 +992,12 @@ const selectAnnots = editViewer.getSelectAnnotations();
-80304 | No document opened. | `[]`
-80305 | There is no image in the current document. | `[]`
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
+
### getAnnotationDrawingStyle()
Get the annotation drawing style.
@@ -967,6 +1012,11 @@ getAnnotationDrawingStyle(): AnnotationDrawingStyleConfig;
An [`AnnotationDrawingStyleConfig`](/api/interface/styleinterface/annotationdrawingstyleconfig.md) object.
+**Exception**
+
+ Error Code | Error Message
+--------|-----------------------------------------------------
+ -80500 | The '<%param%>' plugin is not installed.
## Display Control
@@ -1362,7 +1412,7 @@ editViewer.setCropRect(rect);
### undo()
-> *This method takes effect only for [crop](#crop), [rotate](#rotate) operations.*
+> *This method takes effect only for [crop](#crop), [rotate](#rotate) and annotation operations.*
Undo the last editing operation.
@@ -1393,7 +1443,7 @@ editViewer.undo();
### redo()
-> *This method takes effect only for [crop](#crop), [rotate](#rotate) operations.*
+> *This method takes effect only for [crop](#crop), [rotate](#rotate) and annotation operations.*
Redo the last undo operation.
diff --git a/api/class/index.md b/api/class/index.md
index 9edea44..73c6a1e 100644
--- a/api/class/index.md
+++ b/api/class/index.md
@@ -24,7 +24,6 @@ Under the namespace Dynamsoft.DDV, Dynamsoft Document Viewer JavaScript library
- [CaptureViewer](/api/class/captureviewer.md)
- [PerspectiveViewer](/api/class/perspectiveviewer.md)
- [BrowseViewer](/api/class/browseviewer.md)
-- [CustomViewer](/api/class/customviewer.md)
## Annotation
diff --git a/api/enumeration-type/enumannnotationrendermode.md b/api/enumeration-type/enumannnotationrendermode.md
index 712afd6..108455b 100644
--- a/api/enumeration-type/enumannnotationrendermode.md
+++ b/api/enumeration-type/enumannnotationrendermode.md
@@ -16,6 +16,6 @@ permalink: /api/enumeration-type/enumannotationrendermode.html
enum EnumAnnotationRenderMode {
NO_ANNOTATIONS = "noAnnotations", // default, means that the annotations in the PDF file will not be loaded
RENDER_ANNOTATIONS = "renderAnnotations", // means that the annotations in the PDF file will be rendered
- LOAD_ANNOTATIONS = "loadAnnotations", // means that the annotations in the PDF file will be loaded normally, a valid PDF Annotation license is requested
+ LOAD_ANNOTATIONS = "loadAnnotations", // means that the annotations in the PDF file will be loaded normally, a valid PDF Annotation license is requested and the annotation plugin has to be installed
}
```
diff --git a/api/enumeration-type/enumlineending.md b/api/enumeration-type/enumlineending.md
index 8f95dbf..6968646 100644
--- a/api/enumeration-type/enumlineending.md
+++ b/api/enumeration-type/enumlineending.md
@@ -12,6 +12,8 @@ permalink: /api/enumeration-type/enumlineending.html
# EnumLineEnding
+Enumeration for line annotation's ending. Check [LineAnnotationOptions](/api/interface/annotationinterface/lineannotationoptions.md). It is undefined if the annotation plugin is not installed.
+
```typescript
enum EnumLineEnding {
NONE = "none",
diff --git a/api/enumeration-type/enumstampicon.md b/api/enumeration-type/enumstampicon.md
index 27fd89d..cd9c8e7 100644
--- a/api/enumeration-type/enumstampicon.md
+++ b/api/enumeration-type/enumstampicon.md
@@ -12,6 +12,9 @@ permalink: /api/enumeration-type/enumstampicon.html
# EnumStampIcon
+Enumeration for stamp annotation icon. It is undefined if the annotation plugin is not installed.
+
+
```typescript
enum EnumStampIcon {
REJECTED = "rejected",
diff --git a/api/errorlist.md b/api/errorlist.md
index e8b7a3c..9a26416 100644
--- a/api/errorlist.md
+++ b/api/errorlist.md
@@ -58,7 +58,7 @@ permalink: /api/errorlist.html
-80205 | The pageData has been destroyed.
-80206 | The DocTextSearcher has been destroyed.
-## Viewer Releated Errors
+## Viewer Related Errors
Error Code | Error Message
---------- | ------------------------------------------------------------
@@ -90,7 +90,7 @@ permalink: /api/errorlist.html
-80327 | The specified annotation(s) are not on the specified page or do not exist.
-80328 | Rectangle-type redaction requires exactly one rect.
-## Camera Releated Errors
+## Camera Related Errors
Error Code | Error Message
---------- | -------------------------------------------
@@ -103,6 +103,13 @@ permalink: /api/errorlist.html
-80406 | The selected camera is denied by browser.
-80407 | No bound container.
+## Plugin Related Errors
+
+ Error Code | Error Message
+------------|----------------
+ -80500 | The '<%param%>' plugin is not installed.
+ -80501 | Some elements are ignored because the required plugin is not installed.
+
## Wasm Error
diff --git a/api/index.md b/api/index.md
index 58976b3..207a844 100644
--- a/api/index.md
+++ b/api/index.md
@@ -26,7 +26,6 @@ permalink: /api/index.html
- [CaptureViewer]({{ site.api }}class/captureviewer.html)
- [PerspectiveViewer]({{ site.api }}class/perspectiveviewer.html)
- [BrowseViewer]({{ site.api }}class/browseviewer.html)
- - [CustomViewer]({{ site.api }}class/customviewer.html)
- Advanced
- [ImageFilter]({{ site.api }}class/advanced/imagefilter.html)
- [DocumentDetect]({{ site.api }}class/advanced/documentdetect.html)
diff --git a/api/interface/idocument/index.md b/api/interface/idocument/index.md
index 005ed20..0543e82 100644
--- a/api/interface/idocument/index.md
+++ b/api/interface/idocument/index.md
@@ -179,6 +179,7 @@ await firstDoc.loadSource([source]);
-80202 | Failed to read the PDF file because it's encrypted and the correct password is not provided.
-80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
-80204 | PDFs containing XFA (XML Forms Architecture) forms are not supported.
+ -80500 | The '<%param%>' plugin is not installed.
### getPageData()
@@ -265,6 +266,7 @@ await firstDoc.updatePage(firstDoc.pages[0], source);
-80202 | Failed to read the PDF file because it's encrypted and the correct password is not provided.
-80203 | Failed to read some annotations because they are not supported by Dynamsoft Document Viewer so far.
-80204 | PDFs containing XFA (XML Forms Architecture) forms are not supported.
+ -80500 | The '<%param%>' plugin is not installed.
### setPageCustomData()
diff --git a/api/namespace/ddv.md b/api/namespace/ddv.md
index 2cd18b2..da16a03 100644
--- a/api/namespace/ddv.md
+++ b/api/namespace/ddv.md
@@ -49,6 +49,8 @@ permalink: /api/namespace/ddv.html
| [` addFonts()`](#static-addfonts) | Add font to library. |
| [` clearLastError()`](#static-clearlasterror) | Clear the last error or warning. |
| [` unload()`](#static-unload) | Unload all DDV resources. |
+| [` use()`](#static-use) | Load a plugin |
+
**Properties**
@@ -103,6 +105,7 @@ type HandlerType = "documentBoundariesDetect"|"imageFilter";
-80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
-80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.
+ -80500 | The '<%param%>' plugin is not installed.
**Remark**
@@ -130,7 +133,13 @@ const docManager = Dynamsoft.DDV.documentManager;
### `` annotationManager
-[`AnnotationManager`]({{ site.api }}class/annotationmanager.html) instance.
+[`AnnotationManager`]({{ site.api }}class/annotationmanager.html) instance. It is `undefined` if the annotation plugin is not installed.
+
+**Syntax**
+
+```typescript
+annotationManager: AnnotationManager | undefined;
+```
**Code Snippet**
@@ -187,6 +196,8 @@ const defaultEditUi = Dynamsoft.DDV.getDefaultUiConfig("editViewer");
-80100 | *XXX(API)*: *XXX(ParameterName)* is invalid. | `null`
-80102 | *XXX(API)*: *XXX(ParameterName)* is missing. | `null`
-80103 | *XXX(API)*: The value for *XXX(ParameterName)* is not supported.| `null`
+ -80501 | Some elements are ignored because the required plugin is not installed.| `UiConfig`
+
### `` addFonts()
@@ -239,6 +250,33 @@ Unload all DDV resources.
static unload(): void;
```
+
+### `` use()
+
+Load a plugin. See [Plugins and On-Demand Loading](/features/plugins-and-on-demand-loading.md).
+
+**Syntax**
+
+```typescript
+static use(plugin: DDVPlugin): boolean;
+```
+
+**Code Snippet**
+
+```typescript
+Dynamsoft.DDV.use(Dynamsoft.DDV.AnnotationPlugin);
+Dynamsoft.DDV.use(Dynamsoft.DDV.CameraPlugin);
+Dynamsoft.DDV.use(Dynamsoft.DDV.ImagePdfParserPlugin);
+```
+
+**Exception**
+
+ Error Code | Error Message
+ ---------- | ------------------------------------------------------------
+ -80100 | *XXX(API)*: *XXX(ParameterName)* is invalid.
+ -80102 | *XXX(API)*: *XXX(ParameterName)* is missing.
+
+
## Properties
| API Name | Description |
diff --git a/features/index.md b/features/index.md
index 1d8e6fe..f27fbb8 100644
--- a/features/index.md
+++ b/features/index.md
@@ -48,6 +48,10 @@ Viewers are used to display the data. According to the different uses of viewers
- [Custom Viewer]({{ site.features }}viewers/others.html#custom-viewer)
{% comment %}- [Data synchronisation between viewers]({{ site.features }}viewers/datasync.html){% endcomment %}
+## Plugins and On-Demand Loading
+
+[Plugins and on-demand loading](./plugins-and-on-demand-loading.md).
+
## Advanced
- [How to configure image filter]({{ site.features }}advanced/imagefilter.html)
diff --git a/features/plugins-and-on-demand-loading.md b/features/plugins-and-on-demand-loading.md
new file mode 100644
index 0000000..1a23dcd
--- /dev/null
+++ b/features/plugins-and-on-demand-loading.md
@@ -0,0 +1,53 @@
+---
+layout: default-layout
+needAutoGenerateSidebar: true
+needGenerateH3Content: true
+noTitleIndex: true
+title: Dynamsoft Document Viewer Features - Plugins and On-Demand Loading
+keywords: Documentation, Dynamsoft Document Viewer, Features, Plugins, On-Demand Loading
+breadcrumbText: Plugins and On-Demand Loading
+description: Dynamsoft Document Viewer Documentation Features - Plugins and On-Demand Loading
+permalink: /features/plugins-and-on-demand-loading.html
+---
+
+# Plugins and On-Demand Loading
+
+Starting from version 5.0, Dynamsoft Document Viewer adopts a **pluggable architecture**. Features are packaged as standalone plugins, and WASM modules are split for on-demand loading — allowing you to load only what your application needs.
+
+## Plugins
+
+The following feature modules are provided as standalone plugins:
+
+### Camera Plugin
+
+Provides the Capture Viewer's camera functionality, including video stream playback and image capture. Load this plugin only if your application requires camera capture.
+
+### Annotation Plugin
+
+Provides all annotation-related functionality, including creating, editing, and managing annotations. If your application doesn't require annotation editing, you can omit this module to reduce the overall bundle size.
+
+When the annotation plugin is not loaded, annotation-related UI elements in the viewer configuration are automatically ignored.
+
+### Image PDF Parser Plugin
+
+Provides lightweight PDF parsing for pure image-based PDFs (JPEG and JBIG2). Combined with the built-in support for saving image-based PDFs, this plugin enables image PDF workflows without the full PDF WASM module.
+
+## WASM On-Demand Loading
+
+The WASM modules are split so that format-specific modules are loaded only when needed:
+
+- The core WASM module covers common image formats and licensing.
+- The **PDF and TIFF** WASM module (a single file covering both formats) is separated and loaded on demand — only when your application processes TIFF or PDF files.
+- For pure image-based (JPEG and JBIG2) PDFs, the [Image PDF parser plugin](#image-pdf-parser-plugin) can be used instead, eliminating the need to load the full PDF WASM module. For PDFs with vector content or requiring annotation features, the full PDF WASM is still needed.
+- The image processing module is loaded upon performing operations like perspective transform and image filtering.
+- This reduces the initial download size and memory usage, especially for camera-based scanning scenarios where TIFF/vector PDF processing may not be needed.
+
+You can use the following code to preload all the WASM files.
+
+```js
+Dynamsoft.DDV.Core.loadWasm();
+```
+
+## How to Load Plugins
+
+For details on how to include plugins in your project, refer to [Adding the dependency](/gettingstarted/add_dependency.md).
diff --git a/features/viewers/others.md b/features/viewers/others.md
index 70cf6bb..17bf2bc 100644
--- a/features/viewers/others.md
+++ b/features/viewers/others.md
@@ -50,13 +50,3 @@ In this case, you can select multiple pages by clicking on them in the viewer wi
```typescript
browseViewer.multiselectMode = true;
```
-
-## Custom Viewer
-
-Custom Viewer does not have any built-in UI or functionality, it is used for creating your own viewer.
-
-```typescript
-const customViewer = new Dynamsoft.DDV.CustomViewer({
- container: document.getElementById("viewer"),
-});
-```
\ No newline at end of file
diff --git a/gettingstarted/add_dependency.md b/gettingstarted/add_dependency.md
index 3ef4efd..b0f7714 100644
--- a/gettingstarted/add_dependency.md
+++ b/gettingstarted/add_dependency.md
@@ -16,6 +16,7 @@ To use the SDK, we need to include the package below.
- `dynamsoft-document-viewer`: Required, it provides functions to create the viewers.
+It has several plugins that we can load on demand. Check [Plugins and On-Demand Loading](/features//plugins-and-on-demand-loading.md) to learn more.
## Use a CDN
@@ -28,6 +29,14 @@ The simplest way to include the SDK is to use either the [jsDelivr](https://jsde
```
+ With plugins:
+
+ ```html
+
+
+
+ ```
+
- UNPKG
```html
@@ -35,6 +44,14 @@ The simplest way to include the SDK is to use either the [jsDelivr](https://jsde
```
+ With plugins:
+
+ ```html
+
+
+
+ ```
+
## Host the SDK yourself
Besides using the CDN, you can also download the Solution and host related files on your own website/server before including it in your application.
@@ -65,6 +82,14 @@ Depending on how you downloaded the SDK and where you put it, you can typically
```
+ With plugins:
+
+ ```html
+
+
+
+ ```
+
or
```html
@@ -72,9 +97,35 @@ or
```
+ With plugins:
+
+ ```html
+
+
+
+ ```
+
or
```typescript
import { DDV } from 'dynamsoft-document-viewer';
import "dynamsoft-document-viewer/dist/ddv.css";
- ```
\ No newline at end of file
+ ```
+
+ With plugins:
+
+ ```typescript
+ import { CameraPlugin } from 'dynamsoft-document-viewer/camera';
+ import { AnnotationPlugin } from 'dynamsoft-document-viewer/annotation';
+ import { ImagePdfParserPlugin } from 'dynamsoft-document-viewer/imagePdf';
+ ```
+
+## Use Plugins
+
+To actually use the plugins, you also need to run the following JavaScript code:
+
+```js
+Dynamsoft.DDV.use(Dynamsoft.DDV.AnnotationPlugin);
+Dynamsoft.DDV.use(Dynamsoft.DDV.CameraPlugin);
+Dynamsoft.DDV.use(Dynamsoft.DDV.ImagePdfParserPlugin);
+```
diff --git a/gettingstarted/helloworld.md b/gettingstarted/helloworld.md
index 13dfbee..7a72c6b 100644
--- a/gettingstarted/helloworld.md
+++ b/gettingstarted/helloworld.md
@@ -43,7 +43,15 @@ We’ll build on this skeleton page:
## Adding the dependency
-Please refer to [Adding the dependency]({{ site.gettingstarted }}add_dependency.html).
+Add the dependency with the following code:
+
+```html
+
+
+
+```
+
+You can refer to [Adding the dependency]({{ site.gettingstarted }}add_dependency.html).
## Define necessary HTML elements
@@ -82,8 +90,10 @@ For HelloWorld, we define below elements.
// You can request a 30-day trial key from https://www.dynamsoft.com/customer/license/trialLicense/?product=ddv
Dynamsoft.DDV.Core.license = "DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9";
Dynamsoft.DDV.Core.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-document-viewer@latest/dist/engine";
-// Preload DDV Resource
-Dynamsoft.DDV.Core.loadWasm();
+// Wasm files are loaded on demand by default. Uncomment to preload all.
+// Dynamsoft.DDV.Core.loadWasm();
+// Load the annotation plugin.
+Dynamsoft.DDV.use(Dynamsoft.DDV.AnnotationPlugin);
await Dynamsoft.DDV.Core.init();
```
@@ -109,6 +119,7 @@ const editViewer = new Dynamsoft.DDV.EditViewer({
DDV - HelloWorld
+