diff --git a/hello-world/vue/README.md b/hello-world/vue/README.md index 3bad4eb0..3290dab2 100644 --- a/hello-world/vue/README.md +++ b/hello-world/vue/README.md @@ -1,53 +1,94 @@ # Hello World Sample for Vue3 -[Vue 3](https://v3.vuejs.org/) is version 3 of Vue which is a progressive framework for building user interfaces. Check out the following guide on how to implement Dynamsoft Barcode Reader JavaScript SDK (hereafter called "the library") into a Vue 3 application. Note that in this sample, `TypeScript` is used. +[Vue 3](https://v3.vuejs.org/) is version 3 of Vue which is a progressive framework for building user interfaces. Check out the following guide on how to implement [Dynamsoft Barcode Reader JavaScript SDK](https://www.dynamsoft.com/barcode-reader/sdk-javascript/) (hereafter called "the library") into a Vue 3 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 Vue 3 - Demo +* Hello World in Vue 3 - Demo * Hello World in Vue 3 - Source Code ## Preparation Make sure you have [node](https://nodejs.org/) installed. `node 16.20.1` and `vue 3.3.4` are used in the example below. -## Create the sample project +## Quick Start + +```cmd +npm install +npm run dev +``` +Then open http://localhost:5173/ to view the sample app. + +## Creating the sample project + +In this section, we will be creating a Vue 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 a Bootstrapped Raw Vue Application ```cmd npm create vue@3 -# When asked 'Add TypeScript?', select 'Yes'. +``` + +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. + +``` +√ Project name: ... vue-project +√ Add TypeScript? ... Yes +√ Add JSX Support? ... No +√ Add Vue Router for Single Page Application development? ... No +√ Add Pinia for state management? ... No +√ Add Vitest for Unit Testing? ... No +√ Add an End-to-End Testing Solution? » No +√ Add ESLint for code quality? ... No +√ Add Vue DevTools 7 extension for debugging? (experimental) ... No ``` ### **CD** to the root directory of the application and install necessary libraries ```cmd npm install -npm install dynamsoft-core -npm install dynamsoft-license -npm install dynamsoft-utility -npm install dynamsoft-barcode-reader -npm install dynamsoft-capture-vision-router -npm install dynamsoft-camera-enhancer +npm install dynamsoft-barcode-reader-bundle ``` ## Start to implement -### Add file "cvr.ts" under "/src/" to configure libraries +### Add file "dynamsoft.config.ts" under "/src/" to configure libraries ```typescript -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. @@ -56,18 +97,8 @@ LicenseManager.initLicense( * 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/" -}; - -// Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading. -CoreModule.loadWasm(['DBR']); +// Optional. Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading. +CoreModule.loadWasm(["DBR"]); ``` > Note: @@ -77,304 +108,313 @@ CoreModule.loadWasm(['DBR']); ### Create and edit the `VideoCapture` component -* Add a file `VideoCapture.vue` under "/components/" as the `VideoCapture` component. The `VideoCapture` component helps decode barcodes via camera. +* Create `VideoCapture.vue` under `/components/`. The VideoCapture component helps decode barcodes via camera. * In `VideoCapture.vue`, add the following code for initializing and destroying some instances. ```vue + ``` +> 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) ### Create and edit the `ImageCapture` component -* Add a file `ImageCapture.vue` under "/components/" as the `ImageCapture` component. The `ImageCapture` component helps decode barcodes in an image. +* Create `ImageCapture.vue` under `/components/`. The `ImageCapture` component helps decode barcodes in an image. * In `ImageCapture.vue`, add code for initializing and destroying `CaptureVisionRouter` instance. ```vue + ``` -### Add `VideoCapture` and `ImageCapture` components in `HelloWorld.vue` +### Add the `VideoCapture` and `ImageCapture` component to `App.vue` + +* On `/src/App.vue`, we will edit the component so that it offers buttons to switch components between `VideoCapture` and `ImageCapture`. + +* Add following code to `App.vue`. ```vue + -``` - -### Add the `HelloWorld` component to `App.vue` - -Edit the file `App.vue` to be like this -```vue - - - - - ``` +> Note: +> +> With Vue's `defineAsyncComponent` we can improve the initial load speed and performance of the application. +> +> `defineAsyncComponent` allows us to load components such as `VideoCapture` and `ImageCapture` asynchronously, which means that the component's code is only loaded when it's needed. This will result in a faster initial load times. +> +> However, if you're implementing server-side rendering with Vue, using `defineAsyncComponent` might cause issues while loading `VideoCapture` and `ImageCapture` as we use the window/document object. Make sure to load these components on the client-side! +> +> Read more: https://vuejs.org/guide/components/async.html * Try running the project. ```cmd npm run dev ``` - -If you have followed all the steps correctly, you should now have a functioning page that allows you to scan barcodes from a webcam or a built-in camera. Additionally, if you want to decode a local image, click the `Decode Image` button and select the image you want to decode. Any barcodes that are detected will be displayed in a dialog. +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. ### Comment out the following code in `assets/main.css`. (optional) diff --git a/hello-world/vue/index.html b/hello-world/vue/index.html index 962d379d..e9c29d99 100644 --- a/hello-world/vue/index.html +++ b/hello-world/vue/index.html @@ -1,10 +1,16 @@ - - - - read-video-vue3 + + + + + + + Hello World for Vue 3 - Dynamsoft Barcode Reader Sample
diff --git a/hello-world/vue/package.json b/hello-world/vue/package.json index 53d4b78e..77fc7a23 100644 --- a/hello-world/vue/package.json +++ b/hello-world/vue/package.json @@ -23,4 +23,4 @@ "vite": "^4.0.0", "vue-tsc": "^1.0.12" } -} +} \ No newline at end of file diff --git a/hello-world/vue/src/App.vue b/hello-world/vue/src/App.vue index 3c4c188a..4f59da75 100644 --- a/hello-world/vue/src/App.vue +++ b/hello-world/vue/src/App.vue @@ -5,6 +5,7 @@ import VideoCapture from "./components/VideoCapture.vue"; import ImageCapture from "./components/ImageCapture.vue"; const mode: Ref = ref("video"); + @@ -29,6 +32,7 @@ const mode: Ref = ref("video"); align-items: center; margin-top: 20px; } + .title .title-logo { width: 30px; height: 30px; @@ -53,13 +57,14 @@ const mode: Ref = ref("video"); border-bottom-left-radius: 10px; border-right: transparent; } + .top-btns button:nth-child(2) { border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-left: transparent; } -@media screen and (max-width: 500px) { +@media screen and (max-width: 800px) { .top-btns { width: 70%; } diff --git a/hello-world/vue/src/components/ImageCapture.vue b/hello-world/vue/src/components/ImageCapture.vue index a9a85f85..25392c19 100644 --- a/hello-world/vue/src/components/ImageCapture.vue +++ b/hello-world/vue/src/components/ImageCapture.vue @@ -5,34 +5,39 @@ import { EnumCapturedResultItemType } from "dynamsoft-core"; import type { BarcodeResultItem } from "dynamsoft-barcode-reader"; import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; -const resDiv: Ref = ref(null); +const resultContainer: Ref = ref(null); let pCvRouter: Promise; -let bDestoried = false; +let isDestroyed = false; const captureImage = async (e: Event) => { let files = [...(e.target! as HTMLInputElement).files!]; - (e.target! as HTMLInputElement).value = ''; - resDiv.value!.innerText = ""; + (e.target! as HTMLInputElement).value = ''; // reset input + resultContainer.value!.innerText = ""; try { + // ensure cvRouter is created only once const cvRouter = await (pCvRouter = pCvRouter || CaptureVisionRouter.createInstance()); - if (bDestoried) return; - - for(let file of files){ + if (isDestroyed) return; + + for (let file of files) { // Decode selected image with 'ReadBarcodes_SpeedFirst' template. const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); - if (bDestoried) return; + if (isDestroyed) return; - if(files.length > 1){ - resDiv.value!.innerText += `\n${file.name}:\n`; + // Print file name if there's multiple files + if (files.length > 1) { + resultContainer.value!.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; - resDiv.value!.innerText += item.text + "\n"; + resultContainer.value!.innerText += item.text + "\n"; // output the decoded barcode text console.log(item.text); } - if (!result.items.length) resDiv.value!.innerText += 'No barcode found\n'; + // If no items are found, display that no barcode was detected + if (!result.items.length) resultContainer.value!.innerText += 'No barcode found\n'; } } catch (ex: any) { let errMsg = ex.message || ex; @@ -42,32 +47,32 @@ const captureImage = async (e: Event) => { } onBeforeUnmount(async () => { - bDestoried = true; - if(pCvRouter){ - try{ + isDestroyed = true; + if (pCvRouter) { + try { (await pCvRouter).dispose(); - }catch(_){} + } catch (_) { } } }); - + \ No newline at end of file diff --git a/hello-world/vue/src/components/VideoCapture.vue b/hello-world/vue/src/components/VideoCapture.vue index 456457ef..6f32d162 100644 --- a/hello-world/vue/src/components/VideoCapture.vue +++ b/hello-world/vue/src/components/VideoCapture.vue @@ -5,49 +5,48 @@ 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"; -const uiContainer: Ref = ref(null); +const cameraViewContainer: Ref = ref(null); const resultsContainer: Ref = ref(null); -let resolveInit:()=>void; -const pInit:Promise = new Promise(r=>{resolveInit=r}); -let bDestoryed = false; +let resolveInit: () => void; +const pInit: Promise = new Promise(r => { resolveInit = r }); +let isDestroyed = false; -let cvRouter:CaptureVisionRouter; -let cameraEnhancer:CameraEnhancer; +let cvRouter: CaptureVisionRouter; +let cameraEnhancer: CameraEnhancer; onMounted(async () => { - try{ + try { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); - if(bDestoryed){ throw Error(strErrorDistoryed); } // Check if component is destroyed after every async + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Check if component is destroyed after every async + cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - if(bDestoryed){ throw Error(strErrorDistoryed); } + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Get default UI and append it to DOM. - uiContainer.value!.append(cameraView.getUIElement()); + cameraViewContainer.value!.append(cameraView.getUIElement()); // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. cvRouter = await CaptureVisionRouter.createInstance(); - if(bDestoryed){ throw Error(strErrorDistoryed); } + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } cvRouter.setInput(cameraEnhancer); // Define a callback for results. - cvRouter.addResultReceiver({ onDecodedBarcodesReceived: (result) => { - if (!result.barcodeResultItems.length) return; - - resultsContainer.value!.textContent = ''; - console.log(result); - for (let item of result.barcodeResultItems) { - resultsContainer.value!.append( - `${item.formatString}: ${item.text}`, - document.createElement('br'), - document.createElement('hr'), - ); + cvRouter.addResultReceiver({ + onDecodedBarcodesReceived: (result) => { + if (!result.barcodeResultItems.length) return; + + resultsContainer.value!.textContent = ''; + console.log(result); + for (let item of result.barcodeResultItems) { + resultsContainer.value!.textContent += `${item.formatString}: ${item.text}\n\n`; + } } - }}); + }); // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); @@ -56,55 +55,57 @@ onMounted(async () => { // Filter out duplicate barcodes within 3 seconds. filter.enableResultDeduplication("barcode", true); await cvRouter.addResultFilter(filter); - if(bDestoryed){ throw Error(strErrorDistoryed); } + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } // Open camera and start scanning single barcode. await cameraEnhancer.open(); - if(bDestoryed){ throw Error(strErrorDistoryed); } + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } await cvRouter.startCapturing("ReadSingleBarcode"); - if(bDestoryed){ throw Error(strErrorDistoryed); } + if (isDestroyed) { throw Error(componentDestroyedErrorMsg); } + + } catch (ex: any) { - }catch(ex:any){ - - if((ex as Error)?.message === strErrorDistoryed){ - console.log(strErrorDistoryed); - }else{ + 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. resolveInit!(); }); +// dispose cvRouter when it's no longer needed onBeforeUnmount(async () => { - bDestoryed = true; - try{ - await pInit; + isDestroyed = true; + try { + await pInit; // Wait for the pInit to complete before disposing resources. cvRouter?.dispose(); cameraEnhancer?.dispose(); - }catch(_){} + } catch (_) { } }); - +