From a16ca869133606e8fff678afb8f36af096b9335a Mon Sep 17 00:00:00 2001 From: felixindrawan Date: Tue, 25 Jun 2024 15:27:28 -0700 Subject: [PATCH 1/3] feat: update angular sample and docs --- hello-world/angular/README.md | 383 +++++++++++++++++- hello-world/angular/package.json | 4 +- hello-world/angular/src/app/app.component.css | 15 +- .../angular/src/app/app.component.html | 4 +- hello-world/angular/src/app/app.component.ts | 2 +- .../angular/src/app/dynamsoft.config.ts | 31 +- .../image-capture/image-capture.component.css | 9 +- .../image-capture.component.html | 13 +- .../image-capture/image-capture.component.ts | 42 +- .../video-capture/video-capture.component.css | 4 +- .../video-capture.component.html | 6 +- .../video-capture/video-capture.component.ts | 91 ++--- hello-world/angular/src/index.html | 34 +- 13 files changed, 514 insertions(+), 124 deletions(-) diff --git a/hello-world/angular/README.md b/hello-world/angular/README.md index 8dd455f1..5e7c33b7 100644 --- a/hello-world/angular/README.md +++ b/hello-world/angular/README.md @@ -1,10 +1,381 @@ -# DbrjsSampleAngular +# Hello World Sample for Angular + +[Angular](https://angular.dev/) is one of the most popular and mature JavaScript frameworks. Follow this guide to learn how to implement [Dynamsoft Barcode Reader JavaScript SDK](https://www.dynamsoft.com/barcode-reader/sdk-javascript/) (hereafter called "the library") into an Angular application. Note that in this sample, `TypeScript` is used. + +In this guide, we will be using [`dynamsoft-barcode-reader-bundle 10.2.1000`](https://www.npmjs.com/package/dynamsoft-barcode-reader-bundle/v/10.2.1000). + +> Note: +> +> If you’re looking to integrate DBR-JS into a framework that we don't yet have a sample, don't worry! We have a [comprehensive guide](https://www.dynamsoft.com/barcode-reader/docs/web/programming/javascript/user-guide/use-in-framework.html) that provides detailed instruction and best practices for a seamless integration into any frameworks! +> +> Additionally, we're here to help! Please don't hesitate to [contact us](#Support) for any support or questions you might have. + +## Official sample + +* Hello World in Angular - Source Code +* Hello World in Angular - Demo + +## Preparation +Make sure you have [node](https://nodejs.org/) and [Angular CLI](https://cli.angular.io/) installed. This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.7. -## Development server +## Quick Start + +```cmd +ng serve +``` +Then open `https://localhost:4200/` to view the sample app. + +## Creating the sample project + +In this section, we will be creating an Angular application utilizing the Dynamsoft Barcode Reader bundle sdk. + +We'll be exploring how you could create a page that not only enables barcode scanning via a webcam or a built-in camera, but also decode barcodes from local images. + +By the end of this guide, you'll have a good understanding of the SDK and be ready to discover more ways to use it! + +### Create an [Angular](https://angular.dev) Application bootstrapped with [Angular CLI](https://cli.angular.io/) +```cmd +ng new my-app +``` + +On installation, you will be prompted to configure your project.\ +You can customize these options according to your preferences.\ +Below is the configuration used for this sample. + +``` +? Which stylesheet format would you like to use? CSS +? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No +``` + +On installation, you will be prompted to configure your project.\ +You can customize these options according to your preferences.\ +Below is the configuration used for this sample. + +### **CD** to the root directory of the application and install necessary libraries + +```cmd +cd my-app +npm install dynamsoft-barcode-reader-bundle +``` + +## Start to implement + +### Add file "dynamsoft.config.ts" at the root of the app to configure libraries + +```typescript +/* /dynamsoft.config.ts */ +import { CoreModule } from 'dynamsoft-core'; +import { LicenseManager } from 'dynamsoft-license'; +import 'dynamsoft-barcode-reader'; + +// Configures the paths where the .wasm files and other necessary resources for modules are located. +CoreModule.engineResourcePaths = { + std: 'https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-std@1.2.10/dist/', + dip: 'https://cdn.jsdelivr.net/npm/dynamsoft-image-processing@2.2.30/dist/', + core: 'https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.30/dist/', + license: 'https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.21/dist/', + cvr: 'https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.30/dist/', + dbr: 'https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.2.10/dist/', + dce: 'https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.3/dist/', +}; + +/** LICENSE ALERT - README + * To use the library, you need to first specify a license key using the API "initLicense()" as shown below. + */ + +LicenseManager.initLicense('DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9', true); + +/** + * You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=github&product=dbr&package=js to get your own trial license good for 30 days. + * Note that if you downloaded this sample from Dynamsoft while logged in, the above license key may already be your own 30-day trial license. + * For more information, see https://www.dynamsoft.com/barcode-reader/programming/javascript/user-guide/?ver=10.2.10&utm_source=github#specify-the-license or contact support@dynamsoft.com. + * LICENSE ALERT - THE END + */ + +// Optional. Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading. +CoreModule.loadWasm(['DBR']); +``` + +> Note: +> +> * `initLicense()` specify a license key to use the library. You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=sample&product=dbr&package=js to get your own trial license good for 30 days. +> * `engineResourcePaths` tells the library where to get the necessary resources at runtime. + +### Generate and edit the `video-capture` component + +* Generate the `video-capture`. The `video-capture` component helps decode barcodes via camera. + +```cmd +ng generate component video-capture +``` + +* In `video-capture.component.html`, add code to setup the component's HTML + +```html +
+
+Results: +
+``` + +* In `video-capture.component.ts`, add code for initializing and destroying some instances. For our stylesheet (CSS) specification, please refer to our [source code](#Official-Sample). + +```ts +import { Component, ElementRef, ViewChild } from '@angular/core'; +import "../dynamsoft.config"; +import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; +import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; +import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; + +const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; + +@Component({ + selector: 'app-video-capture', + templateUrl: './video-capture.component.html', + styleUrls: ['./video-capture.component.css'], + standalone: true, +}) +export class VideoCaptureComponent { + + @ViewChild('cameraViewContainer') cameraViewContainer?: ElementRef; + @ViewChild('results') resultsContainer?: ElementRef; + + resolveInit?: () => void; + pInit: Promise = new Promise(r => { this.resolveInit = r }); + isDestroyed = false; + + cvRouter?: CaptureVisionRouter; + cameraEnhancer?: CameraEnhancer; + + async ngAfterViewInit(): Promise { -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + try { + // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. + const cameraView = await CameraView.createInstance(); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Check if component is destroyed after every async + this.cameraEnhancer = await CameraEnhancer.createInstance(cameraView); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + + // Get default UI and append it to DOM. + this.cameraViewContainer!.nativeElement.append(cameraView.getUIElement()); + + // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. + this.cvRouter = await CaptureVisionRouter.createInstance(); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + this.cvRouter.setInput(this.cameraEnhancer); + + // Define a callback for results. + this.cvRouter.addResultReceiver({ + onDecodedBarcodesReceived: (result) => { + if (!result.barcodeResultItems.length) return; + + this.resultsContainer!.nativeElement.textContent = ''; + console.log(result); + for (let item of result.barcodeResultItems) { + this.resultsContainer!.nativeElement.textContent += `${item.formatString}: ${item.text}\n\n`; + } + } + }); + + // Filter out unchecked and duplicate results. + const filter = new MultiFrameResultCrossFilter(); + // Filter out unchecked barcodes. + filter.enableResultCrossVerification("barcode", true); + // Filter out duplicate barcodes within 3 seconds. + filter.enableResultDeduplication("barcode", true); + await this.cvRouter.addResultFilter(filter); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + + // Open camera and start scanning single barcode. + await this.cameraEnhancer.open(); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + await this.cvRouter.startCapturing("ReadSingleBarcode"); + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + + } catch (ex: any) { + if ((ex as Error)?.message === componentDestroyedErrorMsg) { + console.log(componentDestroyedErrorMsg); + } else { + let errMsg = ex.message || ex; + console.error(errMsg); + alert(errMsg); + } + } + + // Resolve pInit promise once initialization is complete. + this.resolveInit!(); + } + + // dispose cvRouter when it's no longer needed + async ngOnDestroy() { + this.isDestroyed = true; + try { + // Wait for the pInit to complete before disposing resources. + await this.pInit; + this.cvRouter?.dispose(); + this.cameraEnhancer?.dispose(); + } catch (_) { } + } +} +``` +> Note: +> +> If you're looking to customize the UI, the UI customization feature are provided by the auxiliary SDK "Dynamsoft Camera Enhancer". For more details, refer to our [User Guide](https://www.dynamsoft.com/barcode-reader/docs/web/programming/javascript/user-guide/index.html#customize-the-ui) + + +### Generate and edit the `image-capture` component + +* Generate the `image-capture`. The `image-capture` component helps decode barcodes in an image. + +```cmd +ng generate component image-capture +``` + +* In `image-capture.component.html`, add code to setup the component's HTML + +```html +
+
+ +
+
+
+``` + +* In `image-capture.component.ts`, add code for initializing and destroying some instances. For our stylesheet (CSS) specification, please refer to our [source code](#Official-Sample). + +```ts +import { Component, ViewChild, ElementRef } from '@angular/core'; +import "../dynamsoft.config"; +import { EnumCapturedResultItemType } from "dynamsoft-core"; +import type { BarcodeResultItem } from "dynamsoft-barcode-reader"; +import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; + +@Component({ + selector: 'app-image-capture', + templateUrl: './image-capture.component.html', + styleUrls: ['./image-capture.component.css'], + standalone: true, +}) +export class ImageCaptureComponent { + + @ViewChild('results') resultsContainer?: ElementRef; + + pCvRouter?: Promise; + isDestroyed = false; + + captureImage = async (e: Event) => { + let files = [...(e.target! as HTMLInputElement).files as any as File[]]; + (e.target! as HTMLInputElement).value = ''; // reset input + this.resultsContainer!.nativeElement.innerText = ""; + try { + // ensure cvRouter is created only once + const cvRouter = await (this.pCvRouter = this.pCvRouter || CaptureVisionRouter.createInstance()); + if (this.isDestroyed) return; + + for (let file of files) { + // Decode selected image with 'ReadBarcodes_SpeedFirst' template. + const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); + if (this.isDestroyed) return; + + // Print file name if there's multiple files + if (files.length > 1) { + this.resultsContainer!.nativeElement.innerText += `\n${file.name}:\n`; + } + for (let _item of result.items) { + if (_item.type !== EnumCapturedResultItemType.CRIT_BARCODE) { + continue; // check if captured result item is a barcode + } + let item = _item as BarcodeResultItem; + this.resultsContainer!.nativeElement.innerText += item.text + "\n"; // output the decoded barcode text + console.log(item.text); + } + // If no items are found, display that no barcode was detected + if (!result.items.length) this.resultsContainer!.nativeElement.innerText += 'No barcode found\n'; + } + } catch (ex: any) { + let errMsg = ex.message || ex; + console.error(errMsg); + alert(errMsg); + } + } + + // dispose cvRouter when it's no longer needed + async ngOnDestroy() { + this.isDestroyed = true; + if (this.pCvRouter) { + try { + (await this.pCvRouter).dispose(); + } catch (_) { } + } + } +} +``` + +### Add the `video-capture` and `image-capture` component to the `app` component + +* On the `app` component, we will edit the component so that it offers buttons to switch components between `video-capture` and `image-capture`. + +* In `app.component.html`, add the following code. + +```html +
+
+

Hello World for Angular

+
+
+ + +
+ @if (mode === 'video') { + + } @else { + + } +
+``` + +* In `app.component.ts`, add the following code. For our stylesheet (CSS) specification, please refer to our [source code](#Official-Sample). + +```ts +import { Component } from '@angular/core'; +import { NgStyle } from '@angular/common'; + +import { ImageCaptureComponent } from './image-capture/image-capture.component'; +import { VideoCaptureComponent } from './video-capture/video-capture.component'; + +@Component({ + selector: 'app-root', + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent] +}) +export class AppComponent { + title = 'dbrjs-sample-angular'; + + mode: string = "video"; + + switchMode(value: string) { + this.mode = value; + } +} +``` + +* Try running the project. + +```cmd +ng serve +``` + +If you followed all the steps correctly, you will have a working page that turns one of the cameras hooked to or built in your computer or mobile device into a barcode scanner. Also, if you want to decode a local image, just click the `Decode Image` button and select the image you want to decode. Once barcodes are found, the results will show in a dialog. ## Code scaffolding @@ -22,6 +393,10 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github. Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. -## Further help +## Further help - Angular To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. + +## Support + +If you have any questions, feel free to [contact Dynamsoft Support](https://www.dynamsoft.com/company/contact?utm_source=sampleReadme). \ No newline at end of file diff --git a/hello-world/angular/package.json b/hello-world/angular/package.json index 18bb9825..1feefa5d 100644 --- a/hello-world/angular/package.json +++ b/hello-world/angular/package.json @@ -1,5 +1,5 @@ { - "name": "dbrjs-sample-angular", + "name": "dbrjs-angular-sample", "version": "0.0.0", "scripts": { "ng": "ng", @@ -36,4 +36,4 @@ "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.4.2" } -} +} \ No newline at end of file diff --git a/hello-world/angular/src/app/app.component.css b/hello-world/angular/src/app/app.component.css index cfebba64..3c6341bc 100644 --- a/hello-world/angular/src/app/app.component.css +++ b/hello-world/angular/src/app/app.component.css @@ -1,14 +1,9 @@ - - .title { display: flex; justify-content: center; align-items: center; margin-top: 20px; } -/* .title .title-text { - -} */ .title .title-logo { width: 60px; height: 60px; @@ -36,17 +31,17 @@ border-left: transparent; } -@media screen and (max-width: 500px) { +@media screen and (max-width: 800px) { .top-btns { - width: 70%; + width: 70%; } } @keyframes retate { from { - transform: rotate(0deg); + transform: rotate(0deg); } to { - transform: rotate(360deg); + transform: rotate(360deg); } -} \ No newline at end of file +} diff --git a/hello-world/angular/src/app/app.component.html b/hello-world/angular/src/app/app.component.html index d02a949c..8b8e0de7 100644 --- a/hello-world/angular/src/app/app.component.html +++ b/hello-world/angular/src/app/app.component.html @@ -3,8 +3,8 @@

Hello World for Angular

- - + +
@if (mode === 'video') { diff --git a/hello-world/angular/src/app/app.component.ts b/hello-world/angular/src/app/app.component.ts index e9d3f6c7..4ab77365 100644 --- a/hello-world/angular/src/app/app.component.ts +++ b/hello-world/angular/src/app/app.component.ts @@ -12,7 +12,7 @@ import { VideoCaptureComponent } from './video-capture/video-capture.component'; imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent] }) export class AppComponent { - title = 'dbrjs-sample-angular'; + title = 'dbrjs-angular-sample'; mode: string = "video"; diff --git a/hello-world/angular/src/app/dynamsoft.config.ts b/hello-world/angular/src/app/dynamsoft.config.ts index 8a0d59c1..87d3d287 100644 --- a/hello-world/angular/src/app/dynamsoft.config.ts +++ b/hello-world/angular/src/app/dynamsoft.config.ts @@ -1,12 +1,23 @@ -import { CoreModule } from "dynamsoft-core"; -import { LicenseManager } from "dynamsoft-license"; -import "dynamsoft-barcode-reader"; +import { CoreModule } from 'dynamsoft-core'; +import { LicenseManager } from 'dynamsoft-license'; +import 'dynamsoft-barcode-reader'; + +// Configures the paths where the .wasm files and other necessary resources for modules are located. +CoreModule.engineResourcePaths = { + std: 'https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-std@1.2.10/dist/', + dip: 'https://cdn.jsdelivr.net/npm/dynamsoft-image-processing@2.2.30/dist/', + core: 'https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.30/dist/', + license: 'https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.21/dist/', + cvr: 'https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.30/dist/', + dbr: 'https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.2.10/dist/', + dce: 'https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.3/dist/', +}; /** LICENSE ALERT - README * To use the library, you need to first specify a license key using the API "initLicense()" as shown below. */ -LicenseManager.initLicense("DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9"); +LicenseManager.initLicense('DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9', true); /** * You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=github&product=dbr&package=js to get your own trial license good for 30 days. @@ -15,15 +26,5 @@ LicenseManager.initLicense("DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9"); * LICENSE ALERT - THE END */ -CoreModule.engineResourcePaths = { - std: "https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-std@1.2.10/dist/", - dip: "https://cdn.jsdelivr.net/npm/dynamsoft-image-processing@2.2.30/dist/", - core: "https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.30/dist/", - license: "https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.21/dist/", - cvr: "https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.30/dist/", - dbr: "https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.2.10/dist/", - dce: "https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.3/dist/" -}; - // Optional. Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading. -CoreModule.loadWasm(["DBR"]); +CoreModule.loadWasm(['DBR']); diff --git a/hello-world/angular/src/app/image-capture/image-capture.component.css b/hello-world/angular/src/app/image-capture/image-capture.component.css index e769c603..febb3153 100644 --- a/hello-world/angular/src/app/image-capture/image-capture.component.css +++ b/hello-world/angular/src/app/image-capture/image-capture.component.css @@ -1,10 +1,11 @@ -.capture-img { +.image-capture-container { width: 100%; height: 100%; - font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; + font-family: Consolas, Monaco, Lucida Console, Liberation Mono, + DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; } -.capture-img .img-ipt { +.image-capture-container .input-container { width: 80%; height: 100%; display: flex; @@ -13,6 +14,6 @@ margin: 0 auto; } -.capture-img .result-area { +.image-capture-container .results { margin-top: 20px; } diff --git a/hello-world/angular/src/app/image-capture/image-capture.component.html b/hello-world/angular/src/app/image-capture/image-capture.component.html index dad2d033..5faddf9c 100644 --- a/hello-world/angular/src/app/image-capture/image-capture.component.html +++ b/hello-world/angular/src/app/image-capture/image-capture.component.html @@ -1,4 +1,11 @@ -
-
-
+
+
+ +
+
diff --git a/hello-world/angular/src/app/image-capture/image-capture.component.ts b/hello-world/angular/src/app/image-capture/image-capture.component.ts index 5a0d07ec..8445b6bf 100644 --- a/hello-world/angular/src/app/image-capture/image-capture.component.ts +++ b/hello-world/angular/src/app/image-capture/image-capture.component.ts @@ -12,34 +12,39 @@ import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; }) export class ImageCaptureComponent { - @ViewChild('resDiv') resDiv?: ElementRef; + @ViewChild('results') resultsContainer?: ElementRef; pCvRouter?: Promise; - bDestoried = false; + isDestroyed = false; captureImage = async (e: Event) => { let files = [...(e.target! as HTMLInputElement).files as any as File[]]; - (e.target! as HTMLInputElement).value = ''; - this.resDiv!.nativeElement.innerText = ""; + (e.target! as HTMLInputElement).value = ''; // reset input + this.resultsContainer!.nativeElement.innerText = ""; try { + // ensure cvRouter is created only once const cvRouter = await (this.pCvRouter = this.pCvRouter || CaptureVisionRouter.createInstance()); - if (this.bDestoried) return; - - for(let file of files){ + if (this.isDestroyed) return; + + for (let file of files) { // Decode selected image with 'ReadBarcodes_SpeedFirst' template. const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); - if (this.bDestoried) return; - - if(files.length > 1){ - this.resDiv!.nativeElement.innerText += `\n${file.name}:\n`; + if (this.isDestroyed) return; + + // Print file name if there's multiple files + if (files.length > 1) { + this.resultsContainer!.nativeElement.innerText += `\n${file.name}:\n`; } for (let _item of result.items) { - if(_item.type !== EnumCapturedResultItemType.CRIT_BARCODE) { continue; } + if (_item.type !== EnumCapturedResultItemType.CRIT_BARCODE) { + continue; // check if captured result item is a barcode + } let item = _item as BarcodeResultItem; - this.resDiv!.nativeElement.innerText += item.text + "\n"; + this.resultsContainer!.nativeElement.innerText += item.text + "\n"; // output the decoded barcode text console.log(item.text); } - if (!result.items.length) this.resDiv!.nativeElement.innerText += 'No barcode found\n'; + // If no items are found, display that no barcode was detected + if (!result.items.length) this.resultsContainer!.nativeElement.innerText += 'No barcode found\n'; } } catch (ex: any) { let errMsg = ex.message || ex; @@ -48,12 +53,13 @@ export class ImageCaptureComponent { } } + // dispose cvRouter when it's no longer needed async ngOnDestroy() { - this.bDestoried = true; - if(this.pCvRouter){ - try{ + this.isDestroyed = true; + if (this.pCvRouter) { + try { (await this.pCvRouter).dispose(); - }catch(_){} + } catch (_) { } } } } diff --git a/hello-world/angular/src/app/video-capture/video-capture.component.css b/hello-world/angular/src/app/video-capture/video-capture.component.css index 37aae8a5..465e054e 100644 --- a/hello-world/angular/src/app/video-capture/video-capture.component.css +++ b/hello-world/angular/src/app/video-capture/video-capture.component.css @@ -1,9 +1,9 @@ -.div-ui-container { +.camera-view-container { width: 100%; height: 70vh; } -.div-results-container { +.results { width: 100%; height: 10vh; overflow: auto; diff --git a/hello-world/angular/src/app/video-capture/video-capture.component.html b/hello-world/angular/src/app/video-capture/video-capture.component.html index 7e75ede4..8887901a 100644 --- a/hello-world/angular/src/app/video-capture/video-capture.component.html +++ b/hello-world/angular/src/app/video-capture/video-capture.component.html @@ -1,4 +1,4 @@ -
+
+
Results: -
-
+
diff --git a/hello-world/angular/src/app/video-capture/video-capture.component.ts b/hello-world/angular/src/app/video-capture/video-capture.component.ts index 017070b3..75ef7387 100644 --- a/hello-world/angular/src/app/video-capture/video-capture.component.ts +++ b/hello-world/angular/src/app/video-capture/video-capture.component.ts @@ -4,7 +4,7 @@ import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; -const strErrorDistoryed = 'videoCapture component destoryed'; +const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; @Component({ selector: 'app-video-capture', @@ -14,48 +14,46 @@ const strErrorDistoryed = 'videoCapture component destoryed'; }) export class VideoCaptureComponent { - @ViewChild('uiContainer') uiContainer?: ElementRef; - @ViewChild('resultsContainer') resultsContainer?: ElementRef; - - resolveInit?: ()=>void; - pInit:Promise = new Promise(r=>{this.resolveInit=r}); - bDestoryed = false; - - cvRouter?:CaptureVisionRouter; - cameraEnhancer?:CameraEnhancer; + @ViewChild('cameraViewContainer') cameraViewContainer?: ElementRef; + @ViewChild('results') resultsContainer?: ElementRef; + + resolveInit?: () => void; + pInit: Promise = new Promise(r => { this.resolveInit = r }); + isDestroyed = false; + + cvRouter?: CaptureVisionRouter; + cameraEnhancer?: CameraEnhancer; async ngAfterViewInit(): Promise { - try{ + try { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } // Check if component is destroyed after every async + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Check if component is destroyed after every async this.cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } - + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + // Get default UI and append it to DOM. - this.uiContainer!.nativeElement.append(cameraView.getUIElement()); - + this.cameraViewContainer!.nativeElement.append(cameraView.getUIElement()); + // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. this.cvRouter = await CaptureVisionRouter.createInstance(); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } this.cvRouter.setInput(this.cameraEnhancer); - + // Define a callback for results. - this.cvRouter.addResultReceiver({ onDecodedBarcodesReceived: (result) => { - if (!result.barcodeResultItems.length) return; - - this.resultsContainer!.nativeElement.textContent = ''; - console.log(result); - for (let item of result.barcodeResultItems) { - this.resultsContainer!.nativeElement.append( - `${item.formatString}: ${item.text}`, - document.createElement('br'), - document.createElement('hr'), - ); + this.cvRouter.addResultReceiver({ + onDecodedBarcodesReceived: (result) => { + if (!result.barcodeResultItems.length) return; + + this.resultsContainer!.nativeElement.textContent = ''; + console.log(result); + for (let item of result.barcodeResultItems) { + this.resultsContainer!.nativeElement.textContent += `${item.formatString}: ${item.text}\n\n`; + } } - }}); - + }); + // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); // Filter out unchecked barcodes. @@ -63,35 +61,36 @@ export class VideoCaptureComponent { // Filter out duplicate barcodes within 3 seconds. filter.enableResultDeduplication("barcode", true); await this.cvRouter.addResultFilter(filter); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } - + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + // Open camera and start scanning single barcode. await this.cameraEnhancer.open(); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } await this.cvRouter.startCapturing("ReadSingleBarcode"); - if(this.bDestoryed){ throw Error(strErrorDistoryed); } - - }catch(ex:any){ - - if((ex as Error)?.message === strErrorDistoryed){ - console.log(strErrorDistoryed); - }else{ + if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + + } catch (ex: any) { + if ((ex as Error)?.message === componentDestroyedErrorMsg) { + console.log(componentDestroyedErrorMsg); + } else { let errMsg = ex.message || ex; console.error(errMsg); alert(errMsg); } } - - // distroy function will wait pInit + + // Resolve pInit promise once initialization is complete. this.resolveInit!(); } + // dispose cvRouter when it's no longer needed async ngOnDestroy() { - this.bDestoryed = true; - try{ + this.isDestroyed = true; + try { + // Wait for the pInit to complete before disposing resources. await this.pInit; this.cvRouter?.dispose(); this.cameraEnhancer?.dispose(); - }catch(_){} + } catch (_) { } } } diff --git a/hello-world/angular/src/index.html b/hello-world/angular/src/index.html index 0533df81..4a1660de 100644 --- a/hello-world/angular/src/index.html +++ b/hello-world/angular/src/index.html @@ -1,16 +1,22 @@ - + - - - DbrjsSampleAngular - - - - - - - - - - + + + Hello World for Angular - Dynamsoft Barcode Reader Sample + + + + + + + + + + From da76b4f6d727f1a9f1be3ee3f66fda08cd234938 Mon Sep 17 00:00:00 2001 From: felixindrawan Date: Tue, 25 Jun 2024 15:33:53 -0700 Subject: [PATCH 2/3] fix: formatting --- hello-world/angular/README.md | 85 +++++++++++-------- hello-world/angular/src/app/app.component.css | 5 -- hello-world/angular/src/app/app.component.ts | 4 +- .../image-capture/image-capture.component.ts | 28 +++--- .../video-capture/video-capture.component.ts | 51 ++++++----- 5 files changed, 97 insertions(+), 76 deletions(-) diff --git a/hello-world/angular/README.md b/hello-world/angular/README.md index 5e7c33b7..0bb916b6 100644 --- a/hello-world/angular/README.md +++ b/hello-world/angular/README.md @@ -124,12 +124,12 @@ Results: ```ts import { Component, ElementRef, ViewChild } from '@angular/core'; -import "../dynamsoft.config"; -import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; -import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; -import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; +import '../dynamsoft.config'; +import { CameraEnhancer, CameraView } from 'dynamsoft-camera-enhancer'; +import { CaptureVisionRouter } from 'dynamsoft-capture-vision-router'; +import { MultiFrameResultCrossFilter } from 'dynamsoft-utility'; -const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; +const componentDestroyedErrorMsg = 'VideoCapture Component Destroyed'; @Component({ selector: 'app-video-capture', @@ -138,32 +138,38 @@ const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; standalone: true, }) export class VideoCaptureComponent { - @ViewChild('cameraViewContainer') cameraViewContainer?: ElementRef; @ViewChild('results') resultsContainer?: ElementRef; resolveInit?: () => void; - pInit: Promise = new Promise(r => { this.resolveInit = r }); + pInit: Promise = new Promise((r) => { + this.resolveInit = r; + }); isDestroyed = false; cvRouter?: CaptureVisionRouter; cameraEnhancer?: CameraEnhancer; async ngAfterViewInit(): Promise { - try { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Check if component is destroyed after every async + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Check if component is destroyed after every async this.cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Get default UI and append it to DOM. this.cameraViewContainer!.nativeElement.append(cameraView.getUIElement()); // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. this.cvRouter = await CaptureVisionRouter.createInstance(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } this.cvRouter.setInput(this.cameraEnhancer); // Define a callback for results. @@ -176,24 +182,29 @@ export class VideoCaptureComponent { for (let item of result.barcodeResultItems) { this.resultsContainer!.nativeElement.textContent += `${item.formatString}: ${item.text}\n\n`; } - } + }, }); // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); // Filter out unchecked barcodes. - filter.enableResultCrossVerification("barcode", true); + filter.enableResultCrossVerification('barcode', true); // Filter out duplicate barcodes within 3 seconds. - filter.enableResultDeduplication("barcode", true); + filter.enableResultDeduplication('barcode', true); await this.cvRouter.addResultFilter(filter); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Open camera and start scanning single barcode. await this.cameraEnhancer.open(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } - await this.cvRouter.startCapturing("ReadSingleBarcode"); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } - + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } + await this.cvRouter.startCapturing('ReadSingleBarcode'); + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } } catch (ex: any) { if ((ex as Error)?.message === componentDestroyedErrorMsg) { console.log(componentDestroyedErrorMsg); @@ -216,7 +227,7 @@ export class VideoCaptureComponent { await this.pInit; this.cvRouter?.dispose(); this.cameraEnhancer?.dispose(); - } catch (_) { } + } catch (_) {} } } ``` @@ -253,10 +264,10 @@ ng generate component image-capture ```ts import { Component, ViewChild, ElementRef } from '@angular/core'; -import "../dynamsoft.config"; -import { EnumCapturedResultItemType } from "dynamsoft-core"; -import type { BarcodeResultItem } from "dynamsoft-barcode-reader"; -import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; +import '../dynamsoft.config'; +import { EnumCapturedResultItemType } from 'dynamsoft-core'; +import type { BarcodeResultItem } from 'dynamsoft-barcode-reader'; +import { CaptureVisionRouter } from 'dynamsoft-capture-vision-router'; @Component({ selector: 'app-image-capture', @@ -265,24 +276,24 @@ import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; standalone: true, }) export class ImageCaptureComponent { - @ViewChild('results') resultsContainer?: ElementRef; pCvRouter?: Promise; isDestroyed = false; captureImage = async (e: Event) => { - let files = [...(e.target! as HTMLInputElement).files as any as File[]]; + let files = [...((e.target! as HTMLInputElement).files as any as File[])]; (e.target! as HTMLInputElement).value = ''; // reset input - this.resultsContainer!.nativeElement.innerText = ""; + this.resultsContainer!.nativeElement.innerText = ''; try { // ensure cvRouter is created only once - const cvRouter = await (this.pCvRouter = this.pCvRouter || CaptureVisionRouter.createInstance()); + const cvRouter = await (this.pCvRouter = + this.pCvRouter || CaptureVisionRouter.createInstance()); if (this.isDestroyed) return; for (let file of files) { // Decode selected image with 'ReadBarcodes_SpeedFirst' template. - const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); + const result = await cvRouter.capture(file, 'ReadBarcodes_SpeedFirst'); if (this.isDestroyed) return; // Print file name if there's multiple files @@ -294,18 +305,20 @@ export class ImageCaptureComponent { continue; // check if captured result item is a barcode } let item = _item as BarcodeResultItem; - this.resultsContainer!.nativeElement.innerText += item.text + "\n"; // output the decoded barcode text + this.resultsContainer!.nativeElement.innerText += item.text + '\n'; // output the decoded barcode text console.log(item.text); } // If no items are found, display that no barcode was detected - if (!result.items.length) this.resultsContainer!.nativeElement.innerText += 'No barcode found\n'; + if (!result.items.length) + this.resultsContainer!.nativeElement.innerText += + 'No barcode found\n'; } } catch (ex: any) { let errMsg = ex.message || ex; console.error(errMsg); alert(errMsg); } - } + }; // dispose cvRouter when it's no longer needed async ngOnDestroy() { @@ -313,7 +326,7 @@ export class ImageCaptureComponent { if (this.pCvRouter) { try { (await this.pCvRouter).dispose(); - } catch (_) { } + } catch (_) {} } } } @@ -356,12 +369,12 @@ import { VideoCaptureComponent } from './video-capture/video-capture.component'; standalone: true, templateUrl: './app.component.html', styleUrl: './app.component.css', - imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent] + imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent], }) export class AppComponent { - title = 'dbrjs-sample-angular'; + title = 'dbrjs-angular-sample'; - mode: string = "video"; + mode: string = 'video'; switchMode(value: string) { this.mode = value; diff --git a/hello-world/angular/src/app/app.component.css b/hello-world/angular/src/app/app.component.css index 3c6341bc..e3a585fd 100644 --- a/hello-world/angular/src/app/app.component.css +++ b/hello-world/angular/src/app/app.component.css @@ -4,11 +4,6 @@ align-items: center; margin-top: 20px; } -.title .title-logo { - width: 60px; - height: 60px; - animation: retate 5s infinite linear; -} .top-btns { width: 30%; margin: 20px auto; diff --git a/hello-world/angular/src/app/app.component.ts b/hello-world/angular/src/app/app.component.ts index 4ab77365..ae5c2422 100644 --- a/hello-world/angular/src/app/app.component.ts +++ b/hello-world/angular/src/app/app.component.ts @@ -9,12 +9,12 @@ import { VideoCaptureComponent } from './video-capture/video-capture.component'; standalone: true, templateUrl: './app.component.html', styleUrl: './app.component.css', - imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent] + imports: [NgStyle, ImageCaptureComponent, VideoCaptureComponent], }) export class AppComponent { title = 'dbrjs-angular-sample'; - mode: string = "video"; + mode: string = 'video'; switchMode(value: string) { this.mode = value; diff --git a/hello-world/angular/src/app/image-capture/image-capture.component.ts b/hello-world/angular/src/app/image-capture/image-capture.component.ts index 8445b6bf..fd0bac27 100644 --- a/hello-world/angular/src/app/image-capture/image-capture.component.ts +++ b/hello-world/angular/src/app/image-capture/image-capture.component.ts @@ -1,8 +1,8 @@ import { Component, ViewChild, ElementRef } from '@angular/core'; -import "../dynamsoft.config"; -import { EnumCapturedResultItemType } from "dynamsoft-core"; -import type { BarcodeResultItem } from "dynamsoft-barcode-reader"; -import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; +import '../dynamsoft.config'; +import { EnumCapturedResultItemType } from 'dynamsoft-core'; +import type { BarcodeResultItem } from 'dynamsoft-barcode-reader'; +import { CaptureVisionRouter } from 'dynamsoft-capture-vision-router'; @Component({ selector: 'app-image-capture', @@ -11,24 +11,24 @@ import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; standalone: true, }) export class ImageCaptureComponent { - @ViewChild('results') resultsContainer?: ElementRef; pCvRouter?: Promise; isDestroyed = false; captureImage = async (e: Event) => { - let files = [...(e.target! as HTMLInputElement).files as any as File[]]; + let files = [...((e.target! as HTMLInputElement).files as any as File[])]; (e.target! as HTMLInputElement).value = ''; // reset input - this.resultsContainer!.nativeElement.innerText = ""; + this.resultsContainer!.nativeElement.innerText = ''; try { // ensure cvRouter is created only once - const cvRouter = await (this.pCvRouter = this.pCvRouter || CaptureVisionRouter.createInstance()); + const cvRouter = await (this.pCvRouter = + this.pCvRouter || CaptureVisionRouter.createInstance()); if (this.isDestroyed) return; for (let file of files) { // Decode selected image with 'ReadBarcodes_SpeedFirst' template. - const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); + const result = await cvRouter.capture(file, 'ReadBarcodes_SpeedFirst'); if (this.isDestroyed) return; // Print file name if there's multiple files @@ -40,18 +40,20 @@ export class ImageCaptureComponent { continue; // check if captured result item is a barcode } let item = _item as BarcodeResultItem; - this.resultsContainer!.nativeElement.innerText += item.text + "\n"; // output the decoded barcode text + this.resultsContainer!.nativeElement.innerText += item.text + '\n'; // output the decoded barcode text console.log(item.text); } // If no items are found, display that no barcode was detected - if (!result.items.length) this.resultsContainer!.nativeElement.innerText += 'No barcode found\n'; + if (!result.items.length) + this.resultsContainer!.nativeElement.innerText += + 'No barcode found\n'; } } catch (ex: any) { let errMsg = ex.message || ex; console.error(errMsg); alert(errMsg); } - } + }; // dispose cvRouter when it's no longer needed async ngOnDestroy() { @@ -59,7 +61,7 @@ export class ImageCaptureComponent { if (this.pCvRouter) { try { (await this.pCvRouter).dispose(); - } catch (_) { } + } catch (_) {} } } } diff --git a/hello-world/angular/src/app/video-capture/video-capture.component.ts b/hello-world/angular/src/app/video-capture/video-capture.component.ts index 75ef7387..2e671a7d 100644 --- a/hello-world/angular/src/app/video-capture/video-capture.component.ts +++ b/hello-world/angular/src/app/video-capture/video-capture.component.ts @@ -1,10 +1,10 @@ import { Component, ElementRef, ViewChild } from '@angular/core'; -import "../dynamsoft.config"; -import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; -import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; -import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; +import '../dynamsoft.config'; +import { CameraEnhancer, CameraView } from 'dynamsoft-camera-enhancer'; +import { CaptureVisionRouter } from 'dynamsoft-capture-vision-router'; +import { MultiFrameResultCrossFilter } from 'dynamsoft-utility'; -const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; +const componentDestroyedErrorMsg = 'VideoCapture Component Destroyed'; @Component({ selector: 'app-video-capture', @@ -13,32 +13,38 @@ const componentDestroyedErrorMsg = "VideoCapture Component Destroyed"; standalone: true, }) export class VideoCaptureComponent { - @ViewChild('cameraViewContainer') cameraViewContainer?: ElementRef; @ViewChild('results') resultsContainer?: ElementRef; resolveInit?: () => void; - pInit: Promise = new Promise(r => { this.resolveInit = r }); + pInit: Promise = new Promise((r) => { + this.resolveInit = r; + }); isDestroyed = false; cvRouter?: CaptureVisionRouter; cameraEnhancer?: CameraEnhancer; async ngAfterViewInit(): Promise { - try { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Check if component is destroyed after every async + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Check if component is destroyed after every async this.cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Get default UI and append it to DOM. this.cameraViewContainer!.nativeElement.append(cameraView.getUIElement()); // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. this.cvRouter = await CaptureVisionRouter.createInstance(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } this.cvRouter.setInput(this.cameraEnhancer); // Define a callback for results. @@ -51,24 +57,29 @@ export class VideoCaptureComponent { for (let item of result.barcodeResultItems) { this.resultsContainer!.nativeElement.textContent += `${item.formatString}: ${item.text}\n\n`; } - } + }, }); // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); // Filter out unchecked barcodes. - filter.enableResultCrossVerification("barcode", true); + filter.enableResultCrossVerification('barcode', true); // Filter out duplicate barcodes within 3 seconds. - filter.enableResultDeduplication("barcode", true); + filter.enableResultDeduplication('barcode', true); await this.cvRouter.addResultFilter(filter); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } // Open camera and start scanning single barcode. await this.cameraEnhancer.open(); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } - await this.cvRouter.startCapturing("ReadSingleBarcode"); - if (this.isDestroyed) { throw Error(componentDestroyedErrorMsg); } - + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } + await this.cvRouter.startCapturing('ReadSingleBarcode'); + if (this.isDestroyed) { + throw Error(componentDestroyedErrorMsg); + } } catch (ex: any) { if ((ex as Error)?.message === componentDestroyedErrorMsg) { console.log(componentDestroyedErrorMsg); @@ -91,6 +102,6 @@ export class VideoCaptureComponent { await this.pInit; this.cvRouter?.dispose(); this.cameraEnhancer?.dispose(); - } catch (_) { } + } catch (_) {} } } From e53166075e5570e3635facb5202e41edd70ce1fd Mon Sep 17 00:00:00 2001 From: felixindrawan Date: Tue, 25 Jun 2024 17:05:52 -0700 Subject: [PATCH 3/3] add file names --- hello-world/angular/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hello-world/angular/README.md b/hello-world/angular/README.md index 0bb916b6..c299ec0b 100644 --- a/hello-world/angular/README.md +++ b/hello-world/angular/README.md @@ -114,6 +114,7 @@ ng generate component video-capture * In `video-capture.component.html`, add code to setup the component's HTML ```html +

Results: @@ -123,6 +124,7 @@ Results: * In `video-capture.component.ts`, add code for initializing and destroying some instances. For our stylesheet (CSS) specification, please refer to our [source code](#Official-Sample). ```ts +/* /src/app/video-capture/video-capture.component.ts */ import { Component, ElementRef, ViewChild } from '@angular/core'; import '../dynamsoft.config'; import { CameraEnhancer, CameraView } from 'dynamsoft-camera-enhancer'; @@ -247,6 +249,7 @@ ng generate component image-capture * In `image-capture.component.html`, add code to setup the component's HTML ```html +

Hello World for Angular

@@ -358,6 +363,7 @@ export class ImageCaptureComponent { * In `app.component.ts`, add the following code. For our stylesheet (CSS) specification, please refer to our [source code](#Official-Sample). ```ts +/* /src/app/app.component.ts */ import { Component } from '@angular/core'; import { NgStyle } from '@angular/common';