From 12e9dc1d3e06fe1e414d0325c6eb567227ac75a6 Mon Sep 17 00:00:00 2001 From: felixindrawan Date: Tue, 18 Jun 2024 12:41:31 -0700 Subject: [PATCH 01/13] feat: updated react sample to follow readme --- hello-world/react-hooks/README.md | 141 +++++++------- hello-world/react-hooks/package.json | 17 +- hello-world/react-hooks/public/index.html | 10 +- hello-world/react-hooks/public/logo192.png | Bin 0 -> 5347 bytes hello-world/react-hooks/public/logo512.png | Bin 0 -> 9664 bytes hello-world/react-hooks/public/manifest.json | 25 +++ hello-world/react-hooks/src/App.css | 48 +---- hello-world/react-hooks/src/App.tsx | 20 +- .../src/components/HelloWorld/HelloWorld.css | 47 +++++ .../src/components/HelloWorld/HelloWorld.tsx | 53 +++++ .../components/ImageCapture/ImageCapture.css | 17 +- .../components/ImageCapture/ImageCapture.tsx | 112 ++++++----- .../components/VideoCapture/VideoCapture.css | 17 +- .../components/VideoCapture/VideoCapture.tsx | 181 +++++++++-------- .../react-hooks/src/dynamsoft.config.ts | 5 +- hello-world/react-hooks/src/index.css | 17 +- hello-world/react-hooks/src/index.tsx | 12 +- hello-world/react/README.md | 182 ++++++++---------- hello-world/react/package.json | 15 +- hello-world/react/public/index.html | 8 +- hello-world/react/public/manifest.json | 2 +- hello-world/react/src/App.css | 48 +---- hello-world/react/src/App.tsx | 33 +--- .../src/components/HelloWorld/HelloWorld.css | 47 +++++ .../src/components/HelloWorld/HelloWorld.tsx | 73 +++++++ .../components/ImageCapture/ImageCapture.css | 17 +- .../components/ImageCapture/ImageCapture.tsx | 97 +++++----- .../components/VideoCapture/VideoCapture.css | 4 +- .../components/VideoCapture/VideoCapture.tsx | 148 +++++++------- hello-world/react/src/dynamsoft.config.ts | 4 +- hello-world/react/src/index.css | 17 +- hello-world/react/src/index.tsx | 16 +- 32 files changed, 792 insertions(+), 641 deletions(-) create mode 100644 hello-world/react-hooks/public/logo192.png create mode 100644 hello-world/react-hooks/public/logo512.png create mode 100644 hello-world/react-hooks/public/manifest.json create mode 100644 hello-world/react-hooks/src/components/HelloWorld/HelloWorld.css create mode 100644 hello-world/react-hooks/src/components/HelloWorld/HelloWorld.tsx create mode 100644 hello-world/react/src/components/HelloWorld/HelloWorld.css create mode 100644 hello-world/react/src/components/HelloWorld/HelloWorld.tsx diff --git a/hello-world/react-hooks/README.md b/hello-world/react-hooks/README.md index 86361228..31fdb26c 100644 --- a/hello-world/react-hooks/README.md +++ b/hello-world/react-hooks/README.md @@ -2,6 +2,8 @@ [React](https://reactjs.org/) is a JavaScript library meant explicitly for creating interactive UIs. Follow this guide to learn how to implement Dynamsoft Barcode Reader JavaScript SDK (hereafter called "the library") into a React application. Note that in this sample we will use `TypeScript` and [Hooks](https://reactjs.org/docs/hooks-intro.html). Also, there is another sample `react` defining components as classes in React. +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). + ## Official Sample * Hello World in React with Hooks - Demo @@ -9,10 +11,24 @@ ## Preparation -Make sure you have [node](https://nodejs.org/) installed. `node 16.20.1` and `react 18.2.0` used in the example below. +Make sure you have [node](https://nodejs.org/) installed. `node 16.20.1` and `react 18.2.0` are used in the example below. + +## Quick Start + +```cmd +npm install +npm start +``` +Then open http://localhost:3000/ to view the sample app. ## Create the sample project +In this section, we will be creating a React 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 React Application with TypeScript ```cmd @@ -23,30 +39,23 @@ npx create-react-app my-app --template typescript ```cmd cd my-app -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"; /** 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"); /** * 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. @@ -55,6 +64,7 @@ LicenseManager.initLicense( * LICENSE ALERT - THE END */ +// 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/", @@ -62,11 +72,11 @@ CoreModule.engineResourcePaths = { 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/" + 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']); +CoreModule.loadWasm(["DBR"]); ``` > Note: @@ -85,13 +95,10 @@ CoreModule.loadWasm(['DBR']); * In `VideoCapture.tsx`, add code for initializing and destroying some instances. ```tsx -import React, { useEffect, useRef } from "react"; -import { EnumCapturedResultItemType } from "dynamsoft-core"; +import { useEffect, useRef } from "react"; +import "../../dynamsoft.config"; import { DecodedBarcodesResult } from "dynamsoft-barcode-reader"; -import { - CameraEnhancer, - CameraView, -} from "dynamsoft-camera-enhancer"; +import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; import { CapturedResultReceiver, CaptureVisionRouter, @@ -100,7 +107,7 @@ import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; import "./VideoCapture.css"; function VideoCapture() { - const uiContainer = useRef(null); + const cameraViewContainer = useRef(null); const resultsContainer = useRef(null); const pInit = useRef( @@ -121,8 +128,8 @@ function VideoCapture() { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); const cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - uiContainer.current!.innerText = ""; - uiContainer.current!.append(cameraView.getUIElement()); // Get default UI and append it to DOM. + cameraViewContainer.current!.innerText = ""; + cameraViewContainer.current!.append(cameraView.getUIElement()); // Get default UI and append it to DOM. // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. const cvRouter = await CaptureVisionRouter.createInstance(); @@ -135,33 +142,20 @@ function VideoCapture() { ) => { if (!result.barcodeResultItems.length) return; - resultsContainer.current!.textContent = ''; + resultsContainer.current!.textContent = ""; console.log(result); for (let item of result.barcodeResultItems) { - resultsContainer.current!.append( - `${item.formatString}: ${item.text}`, - document.createElement('br'), - document.createElement('hr'), - ); + resultsContainer.current!.textContent += `${item.formatString}: ${item.text}\n\n`; } }; cvRouter.addResultReceiver(resultReceiver); // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); - filter.enableResultCrossVerification( - "barcode", - true - ); // Filter out unchecked barcodes. + // Filter out unchecked barcodes. + filter.enableResultCrossVerification("barcode", true); // Filter out duplicate barcodes within 3 seconds. - filter.enableResultDeduplication( - "barcode", - true - ); - filter.setDuplicateForgetTime( - "barcode", - 3000 - ); + filter.enableResultDeduplication("barcode", true); await cvRouter.addResultFilter(filter); // Open camera and start scanning single barcode. @@ -210,10 +204,10 @@ function VideoCapture() { return (
-
+
Results:
-
+
); } @@ -223,17 +217,17 @@ export default VideoCapture; > Note: > -> * The component should never update (check the code for `shouldComponentUpdate()`) so that events bound to the UI stay valid. +> * The component should never update so that events bound to the UI stay valid. In this copmonent, the useEffect() hook is used to handle the component’s mount and unmount lifecycle events, and there are no state updates that would cause a re-render. * Define the style of the element in `VideoCapture.css` ```css -.div-ui-container { +.camera-view-container { width: 100%; height: 70vh; } -.div-results-container { +.results-container { width: 100%; height: 10vh; overflow: auto; @@ -248,9 +242,9 @@ export default VideoCapture; ```tsx import React, { useRef, useEffect } from "react"; +import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on. import { BarcodeResultItem } from "dynamsoft-barcode-reader"; import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; -import "../../cvr"; // import side effects. The license, engineResourcePath, so on. import "./ImageCapture.css"; function ImageCapture() { @@ -277,12 +271,17 @@ function ImageCapture() { e.target.files![0], "ReadBarcodes_SpeedFirst" ); + + // Initialize an empty string to hold the decoded barcode texts let texts = ""; for (let item of result.items) { console.log((item as BarcodeResultItem).text); texts += (item as BarcodeResultItem).text + "\n"; } + // If the 'texts' string is not empty, display an alert with all barcode texts if (texts !== "") alert(texts); + + // If no items are found, alert the user that no barcode was detected if (!result.items.length) alert("No barcode found"); } catch (ex: any) { let errMsg = ex.message || ex; @@ -312,7 +311,7 @@ function ImageCapture() { }, []); return ( -
+
{ - setBShowVideoCapture(true); - setBShowImageCapture(false); - }; + const showVideoCapture = () => setMode(Modes.VIDEO_CAPTURE); - const showImageCapture = () => { - setBShowVideoCapture(false); - setBShowImageCapture(true); - }; + const showImageCapture = () => setMode(Modes.IMAGE_CAPTURE); return ( -
+

Hello World for React(Hooks)

- {bShowVideoCapture ? : ""} - {bShowImageCapture ? : ""} + {mode === Modes.VIDEO_CAPTURE ? : }
); @@ -400,7 +398,7 @@ export default HelloWorld; * Define the style of the element in `HelloWorld.css` ```css -.div-hello-world { +.hello-world-page { display: flex; flex-direction: column; align-items: center; @@ -420,6 +418,7 @@ button { border: 1px solid black; background-color: white; color: black; + cursor: pointer; } .container { @@ -472,7 +471,7 @@ It correctly bundles React in production mode and optimizes the build for the be The build is minified and the filenames include the hashes.\ Your app is ready to be deployed! -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +See the section about [deployment](https://create-react-app.dev/docs/deployment/) for more information. ## Support diff --git a/hello-world/react-hooks/package.json b/hello-world/react-hooks/package.json index c41c8e1e..4a7e6c34 100644 --- a/hello-world/react-hooks/package.json +++ b/hello-world/react-hooks/package.json @@ -1,19 +1,18 @@ { "name": "dbrjs-react-sample", - "version": "0.0.0", + "version": "0.1.0", "private": true, - "homepage": "./", "dependencies": { - "@testing-library/jest-dom": "^5.16.5", + "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", - "@types/node": "^16.18.12", - "@types/react": "^18.0.27", - "@types/react-dom": "^18.0.10", + "@types/node": "^16.18.99", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "dynamsoft-barcode-reader-bundle": "10.2.1000", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -42,4 +41,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/hello-world/react-hooks/public/index.html b/hello-world/react-hooks/public/index.html index c9a80cda..ab650d8e 100644 --- a/hello-world/react-hooks/public/index.html +++ b/hello-world/react-hooks/public/index.html @@ -7,9 +7,15 @@ + + + - read-video-react + Hello World for React - Dynamsoft Barcode Reader Sample diff --git a/hello-world/react-hooks/public/logo192.png b/hello-world/react-hooks/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..fc44b0a3796c0e0a64c3d858ca038bd4570465d9 GIT binary patch literal 5347 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 b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN literal 0 HcmV?d00001 diff --git a/hello-world/react-hooks/public/manifest.json b/hello-world/react-hooks/public/manifest.json new file mode 100644 index 00000000..080d6c77 --- /dev/null +++ b/hello-world/react-hooks/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/hello-world/react-hooks/src/App.css b/hello-world/react-hooks/src/App.css index f3fee6a1..49316133 100644 --- a/hello-world/react-hooks/src/App.css +++ b/hello-world/react-hooks/src/App.css @@ -1,47 +1,3 @@ -.title { - display: flex; - justify-content: center; - align-items: center; - margin-top: 20px; +.App { + text-align: center; } -.title .title-logo { - width: 60px; - height: 60px; - animation: retate 5s infinite linear; -} -.top-btns { - width: 30%; - margin: 20px auto; -} -.top-btns button { - display: inline-block; - border: 1px solid black; - padding: 5px 15px; - background-color: transparent; - cursor: pointer; -} -.top-btns button:first-child { - border-top-left-radius: 10px; - 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) { - .top-btns { - width: 70%; - } -} - -@keyframes retate { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} \ No newline at end of file diff --git a/hello-world/react-hooks/src/App.tsx b/hello-world/react-hooks/src/App.tsx index bd21f205..9af0a082 100644 --- a/hello-world/react-hooks/src/App.tsx +++ b/hello-world/react-hooks/src/App.tsx @@ -1,22 +1,10 @@ -import { useState } from 'react'; -import './App.css'; -import reactLogo from './assets/logo.svg'; -import VideoCapture from './components/VideoCapture/VideoCapture'; -import ImageCapture from './components/ImageCapture/ImageCapture'; +import "./App.css"; +import HelloWorld from "./components/HelloWorld/HelloWorld"; function App() { - const [mode, setMode] = useState("video"); return ( -
-
-

Hello World for React

- logo -
-
- - -
- { mode === "video" ? : } +
+
); } diff --git a/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.css b/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.css new file mode 100644 index 00000000..98a260a0 --- /dev/null +++ b/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.css @@ -0,0 +1,47 @@ +.title { + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; +} +.title .title-logo { + width: 60px; + height: 60px; + animation: retate 5s infinite linear; +} +.buttons-container { + width: 30%; + margin: 20px auto; +} +.buttons-container button { + display: inline-block; + border: 1px solid black; + padding: 5px 15px; + background-color: transparent; + cursor: pointer; +} +.buttons-container button:first-child { + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + border-right: transparent; +} +.buttons-container button:nth-child(2) { + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; + border-left: transparent; +} + +@media screen and (max-width: 500px) { + .buttons-container { + width: 70%; + } +} + +@keyframes retate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.tsx b/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.tsx new file mode 100644 index 00000000..7e0a3de7 --- /dev/null +++ b/hello-world/react-hooks/src/components/HelloWorld/HelloWorld.tsx @@ -0,0 +1,53 @@ +import { useState } from "react"; +import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on. +import reactLogo from "../../assets/logo.svg"; +import VideoCapture from "../VideoCapture/VideoCapture"; +import ImageCapture from "../ImageCapture/ImageCapture"; +import "./HelloWorld.css"; + +enum Modes { + VIDEO_CAPTURE = "video", + IMAGE_CAPTURE = "image", +} + +function HelloWorld() { + const [mode, setMode] = useState(Modes.VIDEO_CAPTURE); + + const showVideoCapture = () => setMode(Modes.VIDEO_CAPTURE); + + const showImageCapture = () => setMode(Modes.IMAGE_CAPTURE); + + return ( +
+
+

Hello World for React

+ logo +
+
+ + +
+
+ {mode === Modes.VIDEO_CAPTURE ? : } +
+
+ ); +} + +export default HelloWorld; diff --git a/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.css b/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.css index 4b689a19..b89c6525 100644 --- a/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.css +++ b/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.css @@ -1,18 +1,7 @@ -.capture-img { - width: 100%; - height: 100%; - font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; -} - -.capture-img .img-ipt { - width: 80%; - height: 100%; +.image-capture-container { display: flex; justify-content: center; + align-items: center; + width: 100%; border: 1px solid black; - margin: 0 auto; } - -.capture-img .result-area { - margin-top: 20px; -} \ No newline at end of file diff --git a/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.tsx b/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.tsx index 363cc0e3..c733851a 100644 --- a/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.tsx +++ b/hello-world/react-hooks/src/components/ImageCapture/ImageCapture.tsx @@ -1,67 +1,81 @@ -import { useEffect, useRef, MutableRefObject, useCallback, ChangeEvent } from "react"; -import "../../dynamsoft.config"; -import { EnumCapturedResultItemType } from "dynamsoft-core"; -import type { BarcodeResultItem } from "dynamsoft-barcode-reader"; +import React, { useRef, useEffect } from "react"; +import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on. +import { BarcodeResultItem } from "dynamsoft-barcode-reader"; import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; import "./ImageCapture.css"; -export default () => { - const resDiv: MutableRefObject = useRef(null); +function ImageCapture() { + const pInit = useRef(null as null | Promise); + const pDestroy = useRef(null as null | Promise); - const pCvRouter: MutableRefObject | null> = useRef(null); - const bDestoried = useRef(false); + const init = async (): Promise => { + const cvRouter = await CaptureVisionRouter.createInstance(); + return cvRouter; + }; - const captureImage = useCallback(async(e: ChangeEvent)=>{ - let files = [...(e.target.files as any as File[])]; - e.target.value = ''; - resDiv.current!.innerText = ""; + const destroy = async (): Promise => { + if (pInit.current) { + const cvRouter = (await pInit.current)!; + cvRouter.dispose(); + } + }; + + const decodeImg = async (e: React.ChangeEvent) => { try { - const cvRouter = await (pCvRouter.current = pCvRouter.current || CaptureVisionRouter.createInstance()); - if (bDestoried.current) return; - - for(let file of files){ - // Decode selected image with 'ReadBarcodes_SpeedFirst' template. - const result = await cvRouter.capture(file, "ReadBarcodes_SpeedFirst"); - if (bDestoried.current) return; - - if(files.length > 1){ - resDiv.current!.innerText += `\n${file.name}:\n`; - } - for (let _item of result.items) { - if(_item.type !== EnumCapturedResultItemType.CRIT_BARCODE) { continue; } - let item = _item as BarcodeResultItem; - resDiv.current!.innerText += item.text + "\n"; - console.log(item.text); - } - if (!result.items.length) resDiv.current!.innerText += 'No barcode found\n'; + const cvRouter = (await pInit.current)!; + // Decode selected image with 'ReadBarcodes_SpeedFirst' template. + const result = await cvRouter.capture( + e.target.files![0], + "ReadBarcodes_SpeedFirst" + ); + + // Initialize an empty string to hold the decoded barcode texts + let texts = ""; + for (let item of result.items) { + console.log((item as BarcodeResultItem).text); + texts += (item as BarcodeResultItem).text + "\n"; } + // If the 'texts' string is not empty, display an alert with all barcode texts + if (texts !== "") alert(texts); + + // If no items are found, alert the user that no barcode was detected + if (!result.items.length) alert("No barcode found"); } catch (ex: any) { let errMsg = ex.message || ex; console.error(errMsg); alert(errMsg); } - }, []); + e.target.value = ""; + }; - useEffect((): any => { - // reset value so works in React.StrictMode - bDestoried.current = false; - // onBeforeUnmount - return async () => { - bDestoried.current = true; - if(pCvRouter.current){ - try{ - (await pCvRouter.current).dispose(); - }catch(_){} + useEffect(() => { + (async () => { + // In 'development', React runs setup and cleanup one extra time before the actual setup in Strict Mode. + if (pDestroy) { + await pDestroy; + pInit.current = init(); + } else { + pInit.current = init(); } - } + })(); + + return () => { + (async () => { + await (pDestroy.current = destroy()); + console.log("ImageCapture Component Unmount"); + })(); + }; }, []); return ( -
-
- -
-
+
+
- ) -}; + ); +} + +export default ImageCapture; diff --git a/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.css b/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.css index 810b49cb..173e88ce 100644 --- a/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.css +++ b/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.css @@ -1,11 +1,10 @@ -.div-ui-container { - width: 100%; - height: 70vh; - background: #eee; +.camera-view-container { + width: 100%; + height: 70vh; } -.div-results-container { - width: 100%; - height: 10vh; - overflow: auto; -} \ No newline at end of file +.results-container { + width: 100%; + height: 10vh; + overflow: auto; +} diff --git a/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.tsx b/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.tsx index c370eca3..17657949 100644 --- a/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.tsx +++ b/hello-world/react-hooks/src/components/VideoCapture/VideoCapture.tsx @@ -1,101 +1,118 @@ -import { useEffect, useRef, MutableRefObject } from 'react'; +import { useEffect, useRef } from "react"; import "../../dynamsoft.config"; +import { DecodedBarcodesResult } from "dynamsoft-barcode-reader"; import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; -import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; +import { + CapturedResultReceiver, + CaptureVisionRouter, +} from "dynamsoft-capture-vision-router"; import { MultiFrameResultCrossFilter } from "dynamsoft-utility"; import "./VideoCapture.css"; -const strErrorDistoryed = 'videoCapture component destoryed'; +function VideoCapture() { + const cameraViewContainer = useRef(null); + const resultsContainer = useRef(null); -export default () => { - const uiContainer: MutableRefObject = useRef(null); - const resultsContainer: MutableRefObject = useRef(null); + const pInit = useRef( + null as Promise<{ + cameraView: CameraView; + cameraEnhancer: CameraEnhancer; + cvRouter: CaptureVisionRouter; + }> | null + ); + const pDestroy = useRef(null as Promise | null); + + const init = async (): Promise<{ + cameraView: CameraView; + cameraEnhancer: CameraEnhancer; + cvRouter: CaptureVisionRouter; + }> => { + try { + // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. + const cameraView = await CameraView.createInstance(); + const cameraEnhancer = await CameraEnhancer.createInstance(cameraView); + cameraViewContainer.current!.innerText = ""; + cameraViewContainer.current!.append(cameraView.getUIElement()); // Get default UI and append it to DOM. + + // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. + const cvRouter = await CaptureVisionRouter.createInstance(); + cvRouter.setInput(cameraEnhancer); - useEffect((): any => { - let resolveInit:()=>void; - const pInit:Promise = new Promise(r=>{resolveInit=r}); - let bDestoryed = false; - - let cvRouter:CaptureVisionRouter; - let cameraEnhancer:CameraEnhancer; - - (async()=>{ - 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 - cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - if(bDestoryed){ throw Error(strErrorDistoryed); } - - // Get default UI and append it to DOM. - uiContainer.current!.append(cameraView.getUIElement()); - - // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. - cvRouter = await CaptureVisionRouter.createInstance(); - if(bDestoryed){ throw Error(strErrorDistoryed); } - cvRouter.setInput(cameraEnhancer); - - // Define a callback for results. - cvRouter.addResultReceiver({ onDecodedBarcodesReceived: (result) => { - if (!result.barcodeResultItems.length) return; - - resultsContainer.current!.textContent = ''; - console.log(result); - for (let item of result.barcodeResultItems) { - resultsContainer.current!.append( - `${item.formatString}: ${item.text}`, - document.createElement('br'), - document.createElement('hr'), - ); - } - }}); - - // 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 cvRouter.addResultFilter(filter); - if(bDestoryed){ throw Error(strErrorDistoryed); } - - // Open camera and start scanning single barcode. - await cameraEnhancer.open(); - if(bDestoryed){ throw Error(strErrorDistoryed); } - await cvRouter.startCapturing("ReadSingleBarcode"); - if(bDestoryed){ throw Error(strErrorDistoryed); } - - }catch(ex:any){ - - if((ex as Error)?.message === strErrorDistoryed){ - console.log(strErrorDistoryed); - }else{ - let errMsg = ex.message || ex; - console.error(errMsg); - alert(errMsg); + // Define a callback for results. + const resultReceiver = new CapturedResultReceiver(); + resultReceiver.onDecodedBarcodesReceived = ( + result: DecodedBarcodesResult + ) => { + if (!result.barcodeResultItems.length) return; + + resultsContainer.current!.textContent = ""; + console.log(result); + for (let item of result.barcodeResultItems) { + resultsContainer.current!.textContent += `${item.formatString}: ${item.text}\n\n`; } + }; + cvRouter.addResultReceiver(resultReceiver); + + // 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 cvRouter.addResultFilter(filter); + + // Open camera and start scanning single barcode. + await cameraEnhancer.open(); + await cvRouter.startCapturing("ReadSingleBarcode"); + return { + cameraView, + cameraEnhancer, + cvRouter, + }; + } catch (ex: any) { + let errMsg = ex.message || ex; + console.error(errMsg); + alert(errMsg); + throw ex; + } + }; + + const destroy = async (): Promise => { + if (pInit.current) { + const { cameraView, cameraEnhancer, cvRouter } = await pInit.current; + cvRouter.dispose(); + cameraEnhancer.dispose(); + cameraView.dispose(); + } + }; + + useEffect(() => { + (async () => { + // In 'development', React runs setup and cleanup one extra time before the actual setup in Strict Mode. + if (pDestroy.current) { + await pDestroy.current; + pInit.current = init(); + } else { + pInit.current = init(); } })(); - // distroy function will wait pInit - resolveInit!(); - - // onBeforeUnmount - return async () => { - bDestoryed = true; - try{ - await pInit; - cvRouter?.dispose(); - cameraEnhancer?.dispose(); - }catch(_){} + return () => { + (async () => { + await (pDestroy.current = destroy()); + console.log("VideoCapture Component Unmount"); + })(); }; }, []); return (
-
- Results:
-
+
+ Results: +
+
); } + +export default VideoCapture; diff --git a/hello-world/react-hooks/src/dynamsoft.config.ts b/hello-world/react-hooks/src/dynamsoft.config.ts index 8a0d59c1..2968571a 100644 --- a/hello-world/react-hooks/src/dynamsoft.config.ts +++ b/hello-world/react-hooks/src/dynamsoft.config.ts @@ -15,6 +15,7 @@ LicenseManager.initLicense("DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9"); * LICENSE ALERT - THE END */ +// 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/", @@ -22,8 +23,8 @@ CoreModule.engineResourcePaths = { 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/" + 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. +// Preload "BarcodeReader" module for reading barcodes. It will save time on the initial decoding by skipping the module loading. CoreModule.loadWasm(["DBR"]); diff --git a/hello-world/react-hooks/src/index.css b/hello-world/react-hooks/src/index.css index 5cf73443..ec2585e8 100644 --- a/hello-world/react-hooks/src/index.css +++ b/hello-world/react-hooks/src/index.css @@ -1,10 +1,13 @@ -* { +body { margin: 0; - padding: 0; - box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } -html, body { - text-align: center; - min-width: 350px; -} \ No newline at end of file +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/hello-world/react-hooks/src/index.tsx b/hello-world/react-hooks/src/index.tsx index 652531e4..cfd77849 100644 --- a/hello-world/react-hooks/src/index.tsx +++ b/hello-world/react-hooks/src/index.tsx @@ -1,9 +1,11 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; -const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); +const root = ReactDOM.createRoot( + document.getElementById("root") as HTMLElement +); root.render( diff --git a/hello-world/react/README.md b/hello-world/react/README.md index d4a9e3d6..820f219d 100644 --- a/hello-world/react/README.md +++ b/hello-world/react/README.md @@ -2,6 +2,8 @@ [React](https://reactjs.org/) is a JavaScript library meant explicitly for creating interactive UIs. Follow this guide to learn how to implement Dynamsoft Barcode Reader JavaScript SDK (hereafter called "the library") into a React application. Note that in this sample we will use `TypeScript` and define components as classes. Also, there is another sample `react-hooks` using `Hooks` in React. +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). + ## Official Sample * Hello World in React - Demo @@ -11,82 +13,49 @@ Make sure you have [node](https://nodejs.org/) installed. `node 16.20.1` and `react 18.2.0` are used in the example below. -## Create the sample project - -### Create a Bootstrapped Raw React Application with TypeScript - -```cmd -npx create-react-app my-app --template typescript -``` - -### **CD** to the root directory of the application and install necessary libraries +## Quick Start ```cmd -cd my-app -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 +npm start ``` +Then open http://localhost:3000/ to view the sample app. -## Start to implement - -### Add file "cvr.ts" under "/src/" to configure libraries +## Creating the sample project -```typescript -# Hello World Sample for NuxtJS - -[Nuxt](https://nuxtjs.org/) is a higher-level framework that builds on top of [Vue](https://vuejs.org/). Check out the following guide on how to implement Dynamsoft Barcode Reader JavaScript SDK (hereafter called "the library") into a Nuxt application. Note that in this sample `TypeScript` is used. - -## Official Sample +In this section, we will be creating a React application utilizing the Dynamsoft Barcode Reader bundle sdk. -* Hello World in Nuxt - Source Code +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. -## Preparation - -Make sure you have [node](https://nodejs.org/) installed. `node 16.20.1` and `nuxt 3.2.3` are used in this article. - -## Create the sample project - -### Create a Bootstrapped Nuxt Application +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 React Application with TypeScript ```cmd -npx nuxi@latest init my-app +npx create-react-app my-app --template typescript ``` -You will be asked to configure quite a few things for the application during the creation. In our example, we chose the default one in every step. - -### **CD** to the root directory of the application and install the dependencies +### **CD** to the root directory of the application and install necessary libraries ```cmd cd my-app -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" at the root of the app to configure libraries +### Add file "dynamsoft.config.ts" at the root of the app 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"; /** 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"); /** * 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. @@ -95,6 +64,7 @@ LicenseManager.initLicense( * LICENSE ALERT - THE END */ +// 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/", @@ -102,11 +72,11 @@ CoreModule.engineResourcePaths = { 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/" + 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']); +CoreModule.loadWasm(["DBR"]); ``` > Note: @@ -114,6 +84,7 @@ CoreModule.loadWasm(['DBR']); > * `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. + ### Build directory structure * Create a directory "components" under "/src/", and then create another three directories "HelloWorld", "VideoCapture" and "ImageCapture" under "/src/components/". @@ -126,12 +97,9 @@ CoreModule.loadWasm(['DBR']); ```tsx import React from "react"; -import { EnumCapturedResultItemType } from "dynamsoft-core"; +import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on. import { DecodedBarcodesResult } from "dynamsoft-barcode-reader"; -import { - CameraEnhancer, - CameraView, -} from "dynamsoft-camera-enhancer"; +import { CameraEnhancer, CameraView } from "dynamsoft-camera-enhancer"; import { CapturedResultReceiver, CaptureVisionRouter, @@ -147,7 +115,7 @@ class VideoCapture extends React.Component { }> | null = null; pDestroy: Promise | null = null; - uiContainer: React.RefObject = React.createRef(); + cameraViewContainer: React.RefObject = React.createRef(); resultsContainer: React.RefObject = React.createRef(); async init(): Promise<{ @@ -159,8 +127,8 @@ class VideoCapture extends React.Component { // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control. const cameraView = await CameraView.createInstance(); const cameraEnhancer = await CameraEnhancer.createInstance(cameraView); - this.uiContainer.current!.innerText = ""; - this.uiContainer.current!.append(cameraView.getUIElement()); // Get default UI and append it to DOM. + this.cameraViewContainer.current!.innerText = ""; + this.cameraViewContainer.current!.append(cameraView.getUIElement()); // Get default UI and append it to DOM. // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source. const cvRouter = await CaptureVisionRouter.createInstance(); @@ -173,33 +141,20 @@ class VideoCapture extends React.Component { ) => { if (!result.barcodeResultItems.length) return; - this.resultsContainer.current!.textContent = ''; + this.resultsContainer.current!.textContent = ""; console.log(result); for (let item of result.barcodeResultItems) { - this.resultsContainer.current!.append( - `${item.formatString}: ${item.text}`, - document.createElement('br'), - document.createElement('hr'), - ); + this.resultsContainer.current!.textContent += `${item.formatString}: ${item.text}\n\n`; } }; cvRouter.addResultReceiver(resultReceiver); // Filter out unchecked and duplicate results. const filter = new MultiFrameResultCrossFilter(); - filter.enableResultCrossVerification( - "barcode", - true - ); // Filter out unchecked barcodes. + // Filter out unchecked barcodes. + filter.enableResultCrossVerification("barcode", true); // Filter out duplicate barcodes within 3 seconds. - filter.enableResultDeduplication( - "barcode", - true - ); - filter.setDuplicateForgetTime( - "barcode", - 3000 - ); + filter.enableResultDeduplication("barcode", true); await cvRouter.addResultFilter(filter); // Open camera and start scanning single barcode. @@ -250,10 +205,13 @@ class VideoCapture extends React.Component { render() { return (
-
+
Results:

-
+
); } @@ -269,12 +227,12 @@ export default VideoCapture; * Define the style of the element in `VideoCapture.css` ```css -.div-ui-container { +.camera-view-container { width: 100%; height: 70vh; } -.div-results-container { +.results-container { width: 100%; height: 10vh; overflow: auto; @@ -289,9 +247,9 @@ export default VideoCapture; ```tsx import React from "react"; +import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on. import { BarcodeResultItem } from "dynamsoft-barcode-reader"; import { CaptureVisionRouter } from "dynamsoft-capture-vision-router"; -import "../../cvr"; // import side effects. The license, engineResourcePath, so on. import "./ImageCapture.css"; class ImageCapture extends React.Component { @@ -318,12 +276,17 @@ class ImageCapture extends React.Component { e.target.files![0], "ReadBarcodes_SpeedFirst" ); + + // Initialize an empty string to hold the decoded barcode texts let texts = ""; for (let item of result.items) { console.log((item as BarcodeResultItem).text); texts += (item as BarcodeResultItem).text + "\n"; } + // If the 'texts' string is not empty, display an alert with all barcode texts if (texts !== "") alert(texts); + + // If no items are found, alert the user that no barcode was detected if (!result.items.length) alert("No barcode found"); } catch (ex: any) { let errMsg = ex.message || ex; @@ -350,7 +313,7 @@ class ImageCapture extends React.Component { render() { return ( -
+
{ this.setState({ - bShowVideoCapture: true, - bShowImageCapture: false, + mode: Modes.VIDEO_CAPTURE, }); }; showImageCapture = () => { this.setState({ - bShowVideoCapture: false, - bShowImageCapture: true, + mode: Modes.IMAGE_CAPTURE, }); }; render() { return ( -
+

Hello World for React

- {this.state.bShowVideoCapture ? : ""} - {this.state.bShowImageCapture ? : ""} + {this.state.mode === Modes.VIDEO_CAPTURE ? ( + + ) : ( + + )}
); @@ -451,7 +420,7 @@ export default HelloWorld; * Define the style of the element in `HelloWorld.css` ```css -.div-hello-world { +.hello-world-page { display: flex; flex-direction: column; align-items: center; @@ -471,6 +440,7 @@ button { border: 1px solid black; background-color: white; color: black; + cursor: pointer; } .container { @@ -523,7 +493,7 @@ It correctly bundles React in production mode and optimizes the build for the be The build is minified and the filenames include the hashes.\ Your app is ready to be deployed! -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +See the section about [deployment](https://create-react-app.dev/docs/deployment/) for more information. ## Support diff --git a/hello-world/react/package.json b/hello-world/react/package.json index 102c2b0d..84e11d02 100644 --- a/hello-world/react/package.json +++ b/hello-world/react/package.json @@ -2,18 +2,17 @@ "name": "dbrjs-react-sample", "version": "0.1.0", "private": true, - "homepage": "./", "dependencies": { - "dynamsoft-barcode-reader-bundle": "10.2.1000", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", - "@types/node": "^16.18.59", - "@types/react": "^18.2.31", - "@types/react-dom": "^18.2.14", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "@types/node": "^16.18.98", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "dynamsoft-barcode-reader-bundle": "10.2.1000", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -42,4 +41,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/hello-world/react/public/index.html b/hello-world/react/public/index.html index 70592c1d..ab650d8e 100644 --- a/hello-world/react/public/index.html +++ b/hello-world/react/public/index.html @@ -5,9 +5,11 @@ - - - + +