diff --git a/_data/product_version.yml b/_data/product_version.yml
index eb28c62..2af94fa 100644
--- a/_data/product_version.yml
+++ b/_data/product_version.yml
@@ -4,8 +4,10 @@ version_info_list:
- value: latest version
- value: 2.x
child:
- - 2.0.20_android
- - 2.0.20_ios
+ - 2.2.10_ios
+ - 2.0.20
+ - 2.0.10_android
+ - 2.0.10_ios
- value: 1.x
child:
- 1.0.30_android
diff --git a/assets/js/ddnMobileVersionSearch.json b/assets/js/ddnMobileVersionSearch.json
index 5e57d69..735de31 100644
--- a/assets/js/ddnMobileVersionSearch.json
+++ b/assets/js/ddnMobileVersionSearch.json
@@ -1,5 +1,60 @@
[
{
+ "version": "2.2.11",
+ "matchList": {
+ "ios":{
+ "dcvRepoMobile": [
+ {
+ "path": "/programming/objectivec-swift/api-reference/utility",
+ "version": "1.2.11"
+ }, {
+ "path": "/programming/objectivec-swift/api-reference/license",
+ "version": "3.2.11"
+ }, {
+ "path": "/programming/objectivec-swift/api-reference/capture-vision-router",
+ "version": "2.2.11"
+ }, {
+ "path": "/programming/objectivec-swift/api-reference/core",
+ "version": "3.2.11"
+ }, {
+ "path": "/programming/objectivec-swift/api-reference/image-processing",
+ "version": "2.2.11"
+ }
+ ],
+ "dcvRepoCore": [
+ {
+ "path": "/introduction/",
+ "version": "2.2.11"
+ }, {
+ "path": "/enums/capture-vision-router",
+ "version": "2.2.11"
+ }, {
+ "path": "/enums/core",
+ "version": "3.2.11"
+ },{
+ "path": "/parameters/reference/capture-vision-template",
+ "version": "2.2.11"
+ },{
+ "path": "/parameters/reference/target-roi-def",
+ "version": "2.2.11"
+ },{
+ "path": "/parameters/reference/document-normalizer-task-settings",
+ "version": "2.2.11"
+ },{
+ "path": "/parameters/reference/image-parameter",
+ "version": "2.2.11"
+ },{
+ "path": "/parameters/reference/image-source-options",
+ "version": "3.2.11"
+ },{
+ "path": "/parameters/reference/global-parameter",
+ "version": "2.2.11"
+ }
+ ],
+ "dce": "4.2.1"
+ }
+ }
+ },{
"version": "2.2.10",
"matchList": {
"android":{
diff --git a/programming/android/upgrade-instruction-v2.0.20.md b/programming/android/upgrade-instruction-v2.0.20.md
new file mode 100644
index 0000000..8babc7c
--- /dev/null
+++ b/programming/android/upgrade-instruction-v2.0.20.md
@@ -0,0 +1,131 @@
+---
+layout: default-layout
+title: Upgrade Instructions - Dynamsoft Document Normalizer Android Edition
+keywords: android, document normalizer, upgrade
+description: This page introduces how to upgrade Dynamsoft Document Normalizer Android Edition from 1.x to 2.x
+needAutoGenerateSidebar: false
+permalink: /programming/android/upgrade-instruction.html
+---
+
+# How to Upgrade
+
+## From version 1.x to 2.x
+
+`DynamsoftDocumentNormalizer` SDK has been revamped to integrate with `DynamsoftCaptureVision (DCV)` architecture. To upgrade from version 1.x to 2.x, we recommend that you follow the [`User Guide`](user-guide.md) and re-write your code to match what is in the guide.
+
+Here are some of the main actions you may take:
+
+### Update the Dependencies
+
+Since the SDK architecture has changed, you have to change your `build.gradle` to include the following libraries:
+
+```groovy
+dependencies {
+ implementation 'com.dynamsoft:dynamsoftcapturevisionrouter:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftdocumentnormalizer:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftcameraenhancer:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftcore:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftlicense:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftimageprocessing:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftutility:{version-number}'
+}
+```
+
+>Note: Please view [user guide](user-guide.md#add-the-library-via-maven) for the most up-to-date version number.
+
+### Migrate from Class DocumentNormalizer to Class CaptureVisionRouter
+
+The `CaptureVisionRouter` class serves as the central class of DCV's execution flow. It encompasses the following functionalities:
+
+- Retrieving images from the `ImageSourceAdapter`.
+- Updating templates and configuring settings.
+- Dynamically loading the `DynamsoftDocumentNormalizer` module for document detection and normalization.
+- Dispatching the results to registered receivers of type `CapturedResultReceiver`.
+
+### Convert Parameter Templates
+
+The parameter system has been restructured and the template you used for v1.x cannot be directly recognized by v2.x (and beyond). Please contact us to upgrade your parameter template.
+
+### Update Your Codes
+
+#### Single Image Processing
+
+You should now utilize the provided `capture` API methods instead of the previous `detectQuad` and `normalize` API methods. These `capture` API methods directly return results for boundary detection or document normalization.
+
+```java
+CapturedResult capture(String filePath, String templateName) throws CaptureVisionRouterException
+CapturedResult capture(byte[] fileBytes, String templateName) throws CaptureVisionRouterException
+CapturedResult capture(Bitmap bitmap, String templateName) throws CaptureVisionRouterException
+CapturedResult capture(ImageData imageData, String templateName) throws CaptureVisionRouterException
+```
+
+#### Batch Image Processing
+
+The DCV architecture allows you to conveniently and continuously obtain frames from the `CameraEnhancer`, and then detect or normalize them. The key steps are as follows:
+
+- Set a `CameraEnhancer` object as the input of the `CaptureVisionRouter` object via the `setInput` API method.
+- Register a `CapturedResultReceiver` object as the output of the `CaptureVisionRouter` object via the `addResultReceiver` API method.
+- Open/Close camera via `CameraEnhancer.open` and `CameraEnhancer.close` API methods.
+- Start/Stop capturing via `CaptureVisionRouter.startCapturing` and `CaptureVisionRouter.stopCapturing` API methods.
+
+```java
+public class MainActivity extends AppCompatActivity {
+
+ private CaptureVisionRouter mRouter;
+ private CameraView mCameraView;
+ private CameraEnhancer mCamera;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Add camera view for previewing video.
+ mCameraView = findViewById(R.id.camera_view);
+
+ // Create an instance of Dynamsoft Camera Enhancer for video streaming.
+ mCamera = new CameraEnhancer(mCameraView, this);
+
+ PermissionUtil.requestCameraPermission(MainActivity.this);
+
+ // Create an instance of Capture Vision Router.
+ mRouter = new CaptureVisionRouter(this);
+
+ try {
+ mRouter.setInput(mCamera);
+ } catch (CaptureVisionRouterException e) {
+ e.printStackTrace();
+ }
+
+ mRouter.addResultReceiver(new CapturedResultReceiver() {
+ @Override
+ public void onNormalizedImagesReceived(NormalizedImagesResult result) {
+ //TODO:...
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ try {
+ mCamera.open();
+ mRouter.startCapturing(EnumPresetTemplate.PT_DETECT_AND_NORMALIZE_DOCUMENT);
+ } catch (CameraEnhancerException | CaptureVisionRouterException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ try {
+ mCamera.close();
+ } catch (CameraEnhancerException e) {
+ e.printStackTrace();
+ }
+
+ mRouter.stopCapturing();
+ }
+}
+```
diff --git a/programming/android/upgrade-instruction.md b/programming/android/upgrade-instruction.md
index 8babc7c..0974243 100644
--- a/programming/android/upgrade-instruction.md
+++ b/programming/android/upgrade-instruction.md
@@ -21,13 +21,7 @@ Since the SDK architecture has changed, you have to change your `build.gradle` t
```groovy
dependencies {
- implementation 'com.dynamsoft:dynamsoftcapturevisionrouter:{version-number}'
- implementation 'com.dynamsoft:dynamsoftdocumentnormalizer:{version-number}'
- implementation 'com.dynamsoft:dynamsoftcameraenhancer:{version-number}'
- implementation 'com.dynamsoft:dynamsoftcore:{version-number}'
- implementation 'com.dynamsoft:dynamsoftlicense:{version-number}'
- implementation 'com.dynamsoft:dynamsoftimageprocessing:{version-number}'
- implementation 'com.dynamsoft:dynamsoftutility:{version-number}'
+ implementation 'com.dynamsoft:dynamsoftdocumentnormalizerbundle:{version-number}'
}
```
diff --git a/programming/android/user-guide.md b/programming/android/user-guide.md
index fcdbdcc..a5aeaf3 100644
--- a/programming/android/user-guide.md
+++ b/programming/android/user-guide.md
@@ -117,13 +117,7 @@ There are two ways to add the SDK into your project - **Manually** and **Maven**
```groovy
dependencies {
- implementation 'com.dynamsoft:dynamsoftcapturevisionrouter:2.2.10'
- implementation 'com.dynamsoft:dynamsoftdocumentnormalizer:2.2.10'
- implementation 'com.dynamsoft:dynamsoftcameraenhancer:4.2.0'
- implementation 'com.dynamsoft:dynamsoftcore:3.2.10'
- implementation 'com.dynamsoft:dynamsoftlicense:3.2.10'
- implementation 'com.dynamsoft:dynamsoftimageprocessing:2.2.10'
- implementation 'com.dynamsoft:dynamsoftutility:1.2.10'
+ implementation 'com.dynamsoft:dynamsoftdocumentnormalizerbundle:2.2.10'
}
```
diff --git a/programming/ios/release-notes/index.md b/programming/ios/release-notes/index.md
index 919b7d3..f2ec14e 100644
--- a/programming/ios/release-notes/index.md
+++ b/programming/ios/release-notes/index.md
@@ -10,6 +10,7 @@ permalink: /programming/ios/release-notes/index.html
# Release Notes - iOS Edition
+- [2.2.11 (04/17/2024)]({{ site.ios_release_notes }}ios-2.html#2211-04172024)
- [2.2.10.1 (03/11/2024)]({{ site.ios_release_notes }}ios-2.html#22101-03112024)
- [2.2.10 (03/07/2024)]({{ site.ios_release_notes }}ios-2.html#2210-03072024)
- [2.0.20 (12/12/2023)]({{ site.ios_release_notes }}ios-2.html#2020-12122023)
diff --git a/programming/ios/release-notes/ios-2.md b/programming/ios/release-notes/ios-2.md
index 35bbed0..a31e5e2 100644
--- a/programming/ios/release-notes/ios-2.md
+++ b/programming/ios/release-notes/ios-2.md
@@ -11,8 +11,14 @@ permalink: /programming/ios/release-notes/ios-2.html
# Release Notes for iOS SDK - v2.x
+## 2.2.11 (04/17/2024)
+
+- Updated the privacy list of `DynamsoftDocumentNormalizer.xcframework` and other related libraries.
+
## 2.2.10.1 (03/11/2024)
+### Fixed
+
- Fixed a bug where license error is misreported when method [`getIntermediateResultManager`]({{ site.dcv_ios_api }}capture-vision-router/intermediate-result.html#getintermediateresultmanager) is triggered.
## 2.2.10 (03/07/2024)
diff --git a/programming/ios/upgrade-instruction-v2.2.10.md b/programming/ios/upgrade-instruction-v2.2.10.md
new file mode 100644
index 0000000..8e10fb9
--- /dev/null
+++ b/programming/ios/upgrade-instruction-v2.2.10.md
@@ -0,0 +1,193 @@
+---
+layout: default-layout
+title: Upgrade Instructions - Dynamsoft Document Normalizer iOS Edition
+keywords: ios, document normalizer, upgrade
+description: This page introduces how to upgrade Dynamsoft Document Normalizer iOS Edition from 1.x to 2.x
+needAutoGenerateSidebar: false
+permalink: /programming/ios/upgrade-instruction.html
+---
+
+# How to Upgrade
+
+## From version 1.x to 2.x
+
+`DynamsoftDocumentNormalizer` SDK has been revamped to integrate with `DynamsoftCaptureVision (DCV)` architecture. To upgrade from version 1.x to 2.x, we recommend that you follow the [`User Guide`](user-guide.md) and re-write your code to match what is in the guide.
+
+Here are some of the main actions you may take:
+
+### Update the Dependencies
+
+Since the SDK architecture has changed, you have to change your `Podfile` to include the following libraries:
+
+```sh
+pod 'DynamsoftCaptureVisionRouter','{version-number}'
+pod 'DynamsoftDocumentNormalizer','{version-number}'
+pod 'DynamsoftCameraEnhancer','{version-number}'
+pod 'DynamsoftCore','{version-number}'
+pod 'DynamsoftLicense','{version-number}'
+pod 'DynamsoftImageProcessing','{version-number}'
+pod 'DynamsoftUtility','{version-number}'
+```
+
+>Note: Please view [user guide](user-guide.md#add-the-frameworks-via-cocoapodsn) for the most up-to-date version number.
+
+### Migrate from Class DynamsoftDocumentNormalizer to Class DSCaptureVisionRouter
+
+The `DSCaptureVisionRouter` class serves as the central class of DCV's execution flow. It encompasses the following functionalities:
+
+- Retrieving images from the `DSImageSourceAdapter`.
+- Updating templates and configuring settings.
+- Dynamically loading the `DynamsoftDocumentNormalizer` module for document detection and normalization.
+- Dispatching the results to registered receivers of type `DSCapturedResultReceiver`.
+
+### Convert Parameter Templates
+
+The parameter system has been restructured and the template you used for v1.x cannot be directly recognized by v2.x (and beyond). Please contact us to upgrade your parameter template.
+
+### Update the Code
+
+#### Single Image Processing
+
+You should now utilize the provided multiple `capture` API methods instead of the previous `detectQuad` and `normalize` API methods. These `capture` API methods directly return results for boundary detection or document normalization.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+- (nullable DSCapturedResult *)captureFromFile:(NSString *)file
+ templateName:(nonnull NSString*)templateName
+ error:(NSError *_Nullable *_Nullable)error;
+- (nullable DSCapturedResult *)captureFromFileBytes:(NSData *)fileBytes
+ templateName:(nonnull NSString*)templateName
+ error:(NSError *_Nullable *_Nullable)error;
+- (nullable DSCapturedResult *)captureFromBuffer:(DSImageData *)buffer
+ templateName:(nonnull NSString*)templateName
+ error:(NSError * _Nullable * _Nullable)error;
+- (nullable DSCapturedResult *)captureFromImage:(UIImage *)image
+ templateName:(nonnull NSString*)templateName
+ error:(NSError *_Nullable *_Nullable)error;
+```
+2.
+```swift
+func captureFromFile(_ file:String, templateName:String) throws -> CapturedResult
+func captureFromFileBytes(_ fileBytes:Data, templateName:String) throws -> CapturedResult
+func captureFromBuffer(_ buffer:DSImageData, templateName:String) throws -> CapturedResult
+func captureFromImage(_ image:UIImage, templateName:String) throws -> CapturedResult
+```
+
+#### Batch Image Processing
+
+The DCV architecture allows you to conveniently and continuously obtain frames from the `DSCameraEnhancer`, and then detect or normalize them. The key steps are as follows:
+
+- Set a `DSCameraEnhancer` object as the input of the `DSCaptureVisionRouter` object via the `setInput` API method.
+- Register a `DSCapturedResultReceiver` object as the output of the `DSCaptureVisionRouter` object via the `addResultReceiver` API method.
+- Open/Close camera via `DSCameraEnhancer.open` and `DSCameraEnhancer.close` API methods.
+- Start/Stop capturing via `DSCaptureVisionRouter.startCapturing` and `DSCaptureVisionRouter.stopCapturing` API methods.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+@interface ViewController ()
+@property (nonatomic, strong) DSCaptureVisionRouter *cvr;
+@property (nonatomic, strong) DSCameraEnhancer *dce;
+@property (nonatomic, strong) DSCameraView *cameraView;
+@end
+@implementation ViewController
+- (void)viewDidLoad {
+ NSLog(@"View Did load");
+ [super viewDidLoad];
+ [self setUpCamera];
+ [self setUpCvr];
+ _implementCapture = false;
+ [self setUpUI];
+}
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+ [_dce open];
+ NSError *cvrError;
+ [_cvr startCapturing:DSPresetTemplateDetectAndNormalizeDocument error:&cvrError];
+}
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+ [_dce close];
+}
+- (void)setUpCamera
+{
+ _cameraView = [[DSCameraView alloc] initWithFrame:self.view.bounds];
+ [_cameraView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
+ [self.view addSubview:_cameraView];
+ [_cameraView addSubview:_captureButton];
+ _dce = [[DSCameraEnhancer alloc] init];
+ [_dce setCameraView:_cameraView];
+ DSDrawingLayer * layer = [_cameraView getDrawingLayer:DSDrawingLayerIdDDN];
+ [layer setVisible:true];
+}
+- (void)setUpCvr
+{
+ _cvr = [[DSCaptureVisionRouter alloc] init];
+ _allCornersInOneScan = [[NSMutableArray alloc] init];
+ NSError *cvrError;
+ [_cvr setInput:_dce error:&cvrError];
+ [_cvr addResultReceiver:self error:&cvrError];
+ DSMultiFrameResultCrossFilter *filter = [[DSMultiFrameResultCrossFilter alloc] init];
+ [filter enableResultCrossVerification:DSCapturedResultItemTypeNormalizedImage isEnabled:true];
+ [_cvr addResultFilter:filter error:&cvrError];
+}
+- (void)setUpUI {
+ [self.view addSubview:self.captureButton];
+}
+-(void)onNormalizedImagesReceived:(DSNormalizedImagesResult *)result
+{
+ // Add your code to do when NormalizedImagesResult is receive.
+}
+@end
+```
+2.
+```swift
+class ViewController: UIViewController, CapturedResultReceiver {
+ var cameraView:CameraView!
+ var dce:CameraEnhancer!
+ var cvr:CaptureVisionRouter!
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setUpCamera()
+ setUpDCV()
+ addCaptureButton()
+ }
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ dce.open()
+ try? cvr.startCapturing(PresetTemplate.detectAndNormalizeDocument.rawValue)
+ }
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ dce.close()
+ }
+ func setUpCamera() {
+ cameraView = .init(frame: view.bounds)
+ cameraView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ view.insertSubview(cameraView, at: 0)
+ // Bind the camera enhancer with the camera view.
+ dce = CameraEnhancer()
+ dce.cameraView = cameraView
+ // Additional step: Highlight the detected document boundary.
+ let layer = cameraView.getDrawingLayer(DrawingLayerId.DDN.rawValue)
+ layer?.visible = true
+ }
+ func setUpDCV() {
+ cvr = CaptureVisionRouter()
+ try? cvr.setInput(dce)
+ try? cvr.addResultReceiver(self)
+ }
+ func onNormalizedImagesReceived(_ result: NormalizedImagesResult) {
+ // Add your code to do when NormalizedImagesResult is receive.
+ }
+}
+```
diff --git a/programming/ios/upgrade-instruction.md b/programming/ios/upgrade-instruction.md
index 8e10fb9..eb03a6c 100644
--- a/programming/ios/upgrade-instruction.md
+++ b/programming/ios/upgrade-instruction.md
@@ -20,13 +20,7 @@ Here are some of the main actions you may take:
Since the SDK architecture has changed, you have to change your `Podfile` to include the following libraries:
```sh
-pod 'DynamsoftCaptureVisionRouter','{version-number}'
-pod 'DynamsoftDocumentNormalizer','{version-number}'
-pod 'DynamsoftCameraEnhancer','{version-number}'
-pod 'DynamsoftCore','{version-number}'
-pod 'DynamsoftLicense','{version-number}'
-pod 'DynamsoftImageProcessing','{version-number}'
-pod 'DynamsoftUtility','{version-number}'
+pod 'DynamsoftDocumentNormalizerBundle','{version-number}'
```
>Note: Please view [user guide](user-guide.md#add-the-frameworks-via-cocoapodsn) for the most up-to-date version number.
diff --git a/programming/ios/user-guide-v2.2.10.md b/programming/ios/user-guide-v2.2.10.md
new file mode 100644
index 0000000..4d13c75
--- /dev/null
+++ b/programming/ios/user-guide-v2.2.10.md
@@ -0,0 +1,587 @@
+---
+layout: default-layout
+title: Dynamsoft Document Normalizer for iOS - User Guide
+description: This is the user guide of Dynamsoft Document Normalizer for iOS SDK.
+keywords: user guide, iOS
+needAutoGenerateSidebar: true
+needGenerateH4Content: true
+noTitleIndex: true
+multiProgrammingLanguage: true
+enableLanguageSelection: true
+permalink: /programming/ios/user-guide.html
+---
+
+# Getting Started with iOS
+
+- [System Requirements](#system-requirements)
+- [Build Your First Application](#build-your-first-application)
+ - [Create a New Project](#create-a-new-project)
+ - [Add the SDK](#add-the-sdk)
+ - [Add the Frameworks Manually](#add-the-frameworks-manually)
+ - [Add the Frameworks via CocoaPods](#add-the-frameworks-via-cocoapods)
+ - [Add the Frameworks via Swift Package Manager](#add-the-xcframeworks-via-swift-package-manager)
+ - [Main ViewController for Realtime Document Normalization](#main-viewcontroller-for-realtime-detection-of-quads)
+ - [Initialize License](#initialize-license)
+ - [Get Prepared with the Camera Module](#get-prepared-with-the-camera-module)
+ - [Initialize Capture Vision Router](#initialize-capture-vision-router)
+ - [Set up Result Receiver](#set-up-result-receiver)
+ - [Configure the methods viewDidLoad, viewWillAppear, and viewWillDisappear](#configure-the-methods-viewdidload-viewwillappear-and-viewwilldisappear)
+ - [Display the Normalized Image](#display-the-normalized-image)
+ - [Build and Run the Project](#build-and-run-the-project)
+
+## System Requirements
+
+- Supported OS: iOS 11 or higher (iOS 13 and higher recommended).
+- Supported ABI: arm64 and x86_64.
+- Development Environment: Xcode 13 and above (Xcode 14.1+ recommended).
+
+## Build Your First Application
+
+This guide will walk you through the process of creating a HelloWorld app for normalizing documents via a camera video input.
+
+>Note:
+>
+> - Xcode 14.0 is used in this guide.
+> - You can get the source code of the HelloWord app from the following link
+> - [Objective-C](https://github.com/Dynamsoft/document-normalizer-mobile-samples/tree/main/ios/HelloWorld/AutoNormalizeObjc){:target="_blank"}.
+> - [Swift](https://github.com/Dynamsoft/document-normalizer-mobile-samples/tree/main/ios/HelloWorld/AutoNormalize){:target="_blank"}.
+
+### Create a New Project
+
+1. Open Xcode and select create a new project.
+
+2. Select **iOS -> App** for your application.
+
+3. Input your product name (HelloWorld), interface (StoryBoard) and language (Objective-C/Swift).
+
+4. Click on the **Next** button and select the location to save the project.
+
+5. Click on the **Create** button to finish.
+
+### Add the SDK
+
+There are three ways to add the SDK into your project - **Manually**, via **CocoaPods**, or via **Swift Package Manager**.
+
+#### Add the Frameworks Manually
+
+1. Download the SDK package from the Dynamsoft website. After unzipping, you can find the following **xcframeworks** under the **Dynamsoft\Frameworks** directory:
+
+ | File | Description |
+ | ---- | ----------- |
+ | `DynamsoftDocumentNormalizer.xcframework` | The Dynamsoft Document Normalizer SDK which includes the document normalizer related APIs. |
+ | `DynamsoftCore.xcframework` | The core library of the Dynamsoft Capture Vision SDK which includes basic structures and intermediate result related APIs. |
+ | `DynamsoftCaptureVisionRouter.xcframework` | The CaptureVisionRouter is used to coordinate the image-processing and semantic-processing products that are being used in the application. It accepts an image source and returns processing results which may contain final results or intermediate results. |
+ | `DynamsoftImageProcessing.xcframework` | The image processing library of the Dynamsoft Capture Vision SDK, and so includes the image processing algorithms and APIs. |
+ | `DynamsoftLicense.xcframework` | This module includes the licensing API. |
+ | `DynamsoftCameraEnhancer.xcframework` | The [Dynamsoft Camera Enhancer SDK]({{ site.dce_ios_api }}) defines the camera control and frame preprocessing API. |
+ | `DynamsoftUtility.xcframework (Optional)` | The module includes functional APIs that support you to integrate the input, filtering the results, generating result images, etc. |
+
+2. Drag and drop the above six (seven if the Utility framework is included) **xcframeworks** into your Xcode project. Make sure to check *Copy items if needed* and *Create groups* to properly copy the framework into your project's folder.
+
+3. Click on the project settings then go to **General –> Frameworks, Libraries, and Embedded Content**. Set the **Embed** field to **Embed & Sign** for all included **xcframeworks**.
+
+#### Add the Frameworks via CocoaPods
+
+1. Add the frameworks in your **Podfile**.
+
+ ```sh
+ target 'HelloWorld' do
+ use_frameworks!
+
+ pod 'DynamsoftCaptureVisionRouter','2.2.11'
+ pod 'DynamsoftDocumentNormalizer','2.2.10'
+ pod 'DynamsoftCameraEnhancer','4.2.0'
+ pod 'DynamsoftCore','3.2.10'
+ pod 'DynamsoftLicense','3.2.10'
+ pod 'DynamsoftImageProcessing','2.2.10'
+ pod 'DynamsoftUtility','1.2.10'
+
+ end
+ ```
+
+2. Execute the pod command to install the frameworks and generate workspace(**HelloWorld.xcworkspace**):
+
+ ```sh
+ pod install
+ ```
+
+#### Add the xcframeworks via Swift Package Manager
+
+1. In your Xcode project, go to **File --> AddPackages**.
+
+2. In the top-right section of the window, search "https://github.com/Dynamsoft/document-normalizer-spm"
+
+3. Select `document-normalizer-spm`, then click **Add Package**.
+
+4. Check all the frameworks and add.
+
+
+
+### Initialize License
+
+Initialize the license first. It is suggested to initialize the license in `AppDelegate` file.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+// Import the DynamsoftLicense module to init license
+#import
+// Add LicenseVerificationListener to the interface
+@interface AppDelegate ()
+@end
+@implementation AppDelegate
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ // Override point for customization after application launch.
+ [DSLicenseManager initLicense:@"Put your" verificationDelegate:self];
+ return YES;
+}
+-(void)onLicenseVerified:(BOOL)isSuccess error:(NSError *)error
+{
+ // Add your code to do when license server returns.
+}
+...
+@end
+```
+2.
+```swift
+// Import the DynamsoftLicense module to init license
+import DynamsoftLicense
+// Add LicenseVerificationListener to the interface
+class AppDelegate: UIResponder, UIApplicationDelegate, LicenseVerificationListener {
+ var window: UIWindow?
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ // Override point for customization after application launch.
+ LicenseManager.initLicense("Put your license key here.", verificationDelegate: self)
+ return true
+ }
+ // Implement the callback method of LicenseVerificationListener.
+ func onLicenseVerified(_ isSuccess: Bool, error: Error?) {
+ // Add your code to do when license server returns.
+ }
+ ...
+}
+```
+
+>Note:
+>
+>- Network connection is required for the license to work.
+>- The license string here will grant you a time-limited trial license.
+>- If the license has expired, you can go to the customer portal to request for an extension.
+
+
+
+### Main ViewController for Realtime Detection of Quads
+
+In the main view controller, your app will scan documents via video streaming and display the detect quadrilateral area on the screen. First of all, import the headers in the ViewController file.
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ #import
+ #import
+ #import
+ #import
+ #import
+ ```
+ 2.
+ ```swift
+ import DynamsoftCore
+ import DynamsoftCaptureVisionRouter
+ import DynamsoftDocumentNormalizer
+ import DynamsoftUtility
+ import DynamsoftCameraEnhancer
+ ```
+
+#### Get Prepared with the Camera Module
+
+Create the instances of `CameraEnhancer` and `CameraView`.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+@property (nonatomic, strong) DSCameraEnhancer *dce;
+@property (nonatomic, strong) DSCameraView *cameraView;
+...
+- (void)setUpCamera
+{
+ _cameraView = [[DSCameraView alloc] initWithFrame:self.view.bounds];
+ [_cameraView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
+ [self.view addSubview:_cameraView];
+ [_cameraView addSubview:_captureButton];
+ _dce = [[DSCameraEnhancer alloc] init];
+ [_dce setCameraView:_cameraView];
+ DSDrawingLayer * layer = [_cameraView getDrawingLayer:DSDrawingLayerIdDDN];
+ [layer setVisible:true];
+ // You can enable the frame filter feature of Dynamsoft Camera Enhancer.
+ //[_dce enableEnhancedFeatures:DSEnhancerFeatureFrameFilter];
+}
+```
+2.
+```swift
+var cameraView:CameraView!
+let dce:CameraEnhancer!
+...
+func setUpCamera() {
+ // Create a camera view and add it as a sub view of the current view.
+ cameraView = .init(frame: view.bounds)
+ cameraView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ view.insertSubview(cameraView, at: 0)
+ // Bind the camera enhancer with the camera view.
+ dce = CameraEnhancer()
+ dce.cameraView = cameraView
+ // Additional step: Highlight the detected document boundary.
+ let layer = cameraView.getDrawingLayer(DrawingLayerId.DDN.rawValue)
+ layer?.visible = true
+ // You can enable the frame filter feature of Dynamsoft Camera Enhancer.
+ // dce.enableEnhancedFeatures(.frameFilter)
+}
+```
+
+#### Initialize Capture Vision Router
+
+Once the camera component is set up, declare and create an instance of `CaptureVisionRouter` and set its input to the Camera Enhancer object you created in the last step.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+@property (nonatomic, strong) DSCaptureVisionRouter *cvr;
+...
+- (void)setUpCvr
+{
+ _cvr = [[DSCaptureVisionRouter alloc] init];
+}
+```
+2.
+```swift
+let cvr:CaptureVisionRouter!
+func setUpDCV() {
+ cvr = CaptureVisionRouter()
+}
+```
+
+Bind your `CaptureVisionRouter` instance with the created `CameraEnhancer` instance.
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+- (void)setUpCvr
+{
+ ...
+ NSError *cvrError;
+ [_cvr setInput:_dce error:&cvrError];
+}
+```
+2.
+```swift
+func setUpCvr() {
+ try? cvr.setInput(dce)
+}
+```
+
+#### Set up Result Receiver
+
+1. Add `CapturedResultReceiver` to your ViewController.
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ @interface ViewController ()
+ ```
+ 2.
+ ```swift
+ class ViewController: UIViewController, CapturedResultReceiver {
+ ...
+ }
+ ```
+
+2. Implement `onNormalizedImagesReceived` method to receive the normalized images as the captured results.
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ -(void)onNormalizedImagesReceived:(DSNormalizedImagesResult *)result
+ {
+ if (_implementCapture && result!=nil && result.items[0].imageData!=nil)
+ {
+ _implementCapture = false;
+ ImageViewController *imageViewController = [[ImageViewController alloc] init];
+ NSError * error;
+ imageViewController.resultUIImage = [result.items[0].imageData toUIImage:&error];
+ dispatch_async(dispatch_get_main_queue(), ^{ [self.navigationController pushViewController:imageViewController animated:YES];
+ });
+ }
+ }
+ ```
+ 2.
+ ```swift
+ func onNormalizedImagesReceived(_ result: NormalizedImagesResult) {
+ print("Normalized image received")
+ if let items = result.items, items.count > 0 {
+ guard let data = items[0].imageData else {
+ return
+ }
+ let resultView = ImageViewController()
+ resultView.data = data
+ if implementCapture
+ {
+ DispatchQueue.main.async {
+ self.present(resultView, animated: true)
+ }
+ }
+ }
+ }
+ ```
+
+3. Add the result receiver to the `CaptureVisionRouter`.
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ - (void)setUpCvr
+ {
+ ...
+ NSError *cvrError;
+ [_cvr addResultReceiver:self error:&cvrError];
+ DSMultiFrameResultCrossFilter *filter = [[DSMultiFrameResultCrossFilter alloc] init];
+ [filter enableResultCrossVerification:DSCapturedResultItemTypeNormalizedImage isEnabled:true];
+ [_cvr addResultFilter:filter error:&cvrError];
+ }
+ ```
+ 2.
+ ```swift
+ func setUpCvr() {
+ try? cvr.addResultReceiver(self)
+ let filter = MultiFrameResultCrossFilter.init()
+ filter.enableResultCrossVerification(.normalizedImage, isEnabled: true)
+ try? cvr.addResultFilter(filter)
+ }
+ ```
+
+4. Add a `confirmCapture` button to confirm the result.
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ @property (nonatomic, strong) UIButton *captureButton;
+ ...
+ - (void)addCaptureButton {
+ [self.view addSubview:self.captureButton];
+ }
+ - (UIButton *)captureButton {
+ NSLog(@"Start adding button");
+ CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
+ CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
+ if (!_captureButton) {
+ _captureButton = [UIButton buttonWithType:UIButtonTypeCustom];
+ _captureButton.frame = CGRectMake((screenWidth - 150) / 2.0, screenHeight - 100, 150, 50);
+ _captureButton.backgroundColor = [UIColor grayColor];
+ _captureButton.layer.cornerRadius = 10;
+ _captureButton.layer.borderColor = [UIColor darkGrayColor].CGColor;
+ [_captureButton setTitle:@"Capture" forState:UIControlStateNormal];
+ [_captureButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [_captureButton addTarget:self action:@selector(setCapture) forControlEvents:UIControlEventTouchUpInside];
+ }
+ return _captureButton;
+ }
+ ```
+ 2.
+ ```swift
+ var captureButton:UIButton!
+ var implementCapture:Bool = false
+ ...
+ func addCaptureButton()
+ {
+ let w = UIScreen.main.bounds.size.width
+ let h = UIScreen.main.bounds.size.height
+ let SafeAreaBottomHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height > 20 ? 34 : 0
+ let photoButton = UIButton(frame: CGRect(x: w / 2 - 60, y: h - 100 - SafeAreaBottomHeight, width: 120, height: 60))
+ photoButton.setTitle("Capture", for: .normal)
+ photoButton.backgroundColor = UIColor.green
+ photoButton.addTarget(self, action: #selector(confirmCapture), for: .touchUpInside)
+ DispatchQueue.main.async(execute: { [self] in
+ view.addSubview(photoButton)
+ })
+ }
+ @objc func confirmCapture()
+ {
+ implementCapture = true
+ }
+ ```
+
+#### Configure the methods viewDidLoad, viewWillAppear, and viewWillDisappear
+
+
+>- Objective-C
+>- Swift
+>
+>1.
+```objc
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ [self setUpCamera];
+ [self setUpCvr];
+ [self addCaptureButton];
+}
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+ [_dce open];
+ NSError *cvrError;
+ [_cvr startCapturing:DSPresetTemplateDetectAndNormalizeDocument error:&cvrError];
+}
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+ [_dce close];
+}
+```
+2.
+```swift
+override func viewDidLoad() {
+ super.viewDidLoad()
+ setUpCamera()
+ setUpCvr()
+ addCaptureButton()
+}
+override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ dce.open()
+ try? cvr.startCapturing(PresetTemplate.detectAndNormalizeDocument.rawValue)
+}
+override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ dce.close()
+}
+```
+
+#### Display the Normalized Image
+
+1. Create a new `UIViewController` class `ImageViewController`.
+
+2. Add a property `normalizedImage` to the header file of `ImageViewController` (Objective-C only).
+
+ ```objc
+ @property (nonatomic, strong) UIImage * normalizedImage;
+ ```
+
+2. Configure the `ImageViewController` to display the normalized image..
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ #import "ImageViewController.h"
+ #import
+ @interface ImageViewController()
+ @property (nonatomic, strong) UIImageView *imageView;
+ @end
+ @implementation ImageViewController
+ -(void)viewDidLoad
+ {
+ NSLog(@"ImageViewController loaded");
+ [super viewDidLoad];
+ [self setUpView];
+ }
+ - (void)setUpView
+ {
+ _imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
+ [self.view addSubview:_imageView];
+ NSError *coreError;
+ [_imageView setContentMode:UIViewContentModeScaleAspectFit];
+ [_imageView setImage:self.normalizedImage];
+ }
+ @end
+ ```
+ 2.
+ ```swift
+ class ImageViewController: UIViewController{
+ var normalizedImage:UIImage!
+ var imageView:UIImageView!
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setUpView()
+ }
+ func setUpView() {
+ imageView = UIImageView.init(frame: view.bounds)
+ imageView.contentMode = .scaleAspectFit
+ view.addSubview(imageView)
+ DispatchQueue.main.async { [self] in
+ imageView.image = normalizedImage
+ }
+ }
+ }
+ ```
+
+
+
+### Configure Camera Permissions
+
+Add **Privacy - Camera Usage Description** to the `info.plist` of your project to request camera permission. An easy way to do this is to access your project settings, go to *Info* and then add this Privacy property to the iOS target properties list.
+
+### Additional Steps for iOS 12.x or Lower Versions
+
+If your iOS version is 12.x or lower, please add the following additional steps:
+
+1. Remove the methods `application:didDiscardSceneSessions:` and `application:configurationForConnectingSceneSession:options:` from your `AppDelegate` file.
+2. Remove the `SceneDelegate.Swift` file (`SceneDelegate.h` & `SceneDelegate.m` for Objective-C).
+3. Remove the `Application Scene Manifest` from your info.plist file.
+4. Declaire the window in your `AppDelegate.Swift` file (`AppDelegate.h` for Objective-C).
+
+
+ >- Objective-C
+ >- Swift
+ >
+ >1.
+ ```objc
+ @interface AppDelegate : UIResponder
+ @property (strong, nonatomic) UIWindow *window;
+ @end
+ ```
+ 2.
+ ```swift
+ import UIKit
+ @main
+ class AppDelegate: UIResponder, UIApplicationDelegate {
+ var window: UIWindow?
+ }
+ ```
+
+### Build and Run the Project
+
+1. Select the device that you want to run your app on.
+2. Run the project, then your app will be installed on your device.
+
+> Note:
+>
+> - You can get the source code of the HelloWord app from the following link
+> - [Objective-C](https://github.com/Dynamsoft/document-normalizer-mobile-samples/tree/main/ios/HelloWorld/AutoNormalizeObjc){:target="_blank"}.
+> - [Swift](https://github.com/Dynamsoft/document-normalizer-mobile-samples/tree/main/ios/HelloWorld/AutoNormalize){:target="_blank"}.
diff --git a/programming/ios/user-guide.md b/programming/ios/user-guide.md
index 4d13c75..7626a6f 100644
--- a/programming/ios/user-guide.md
+++ b/programming/ios/user-guide.md
@@ -88,13 +88,7 @@ There are three ways to add the SDK into your project - **Manually**, via **Coco
target 'HelloWorld' do
use_frameworks!
- pod 'DynamsoftCaptureVisionRouter','2.2.11'
- pod 'DynamsoftDocumentNormalizer','2.2.10'
- pod 'DynamsoftCameraEnhancer','4.2.0'
- pod 'DynamsoftCore','3.2.10'
- pod 'DynamsoftLicense','3.2.10'
- pod 'DynamsoftImageProcessing','2.2.10'
- pod 'DynamsoftUtility','1.2.10'
+ pod 'DynamsoftDocumentNormalizerBundle','2.2.11'
end
```