Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
534 changes: 225 additions & 309 deletions hello-world/react-hooks/README.md

Large diffs are not rendered by default.

17 changes: 8 additions & 9 deletions hello-world/react-hooks/package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -42,4 +41,4 @@
"last 1 safari version"
]
}
}
}
11 changes: 9 additions & 2 deletions hello-world/react-hooks/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
content="Dynamsoft Barcode Reader in a React Application, helps read barcodes from camera or images."
/>
<meta name="keywords" content="barcodes, camera, images, React" />
<link rel="canonical" href="https://demo.dynamsoft.com/samples/dbr/js/hello-world/react-hooks/build/" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Expand All @@ -19,7 +26,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>read-video-react</title>
<title>Hello World for React - Dynamsoft Barcode Reader Sample</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
Binary file added hello-world/react-hooks/public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added hello-world/react-hooks/public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions hello-world/react-hooks/public/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
25 changes: 14 additions & 11 deletions hello-world/react-hooks/src/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.hello-world-page {
text-align: center;
}
.title {
display: flex;
justify-content: center;
Expand All @@ -9,39 +12,39 @@
height: 60px;
animation: retate 5s infinite linear;
}
.top-btns {
width: 30%;
.buttons-container {
text-align: center;
margin: 20px auto;
}
.top-btns button {
.buttons-container button {
display: inline-block;
border: 1px solid black;
padding: 5px 15px;
background-color: transparent;
cursor: pointer;
}
.top-btns button:first-child {
.buttons-container button:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-right: transparent;
}
.top-btns button:nth-child(2) {
.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) {
.top-btns {
width: 70%;
@media screen and (max-width: 800px) {
.buttons-container {
width: 70%;
}
}

@keyframes retate {
from {
transform: rotate(0deg);
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
transform: rotate(360deg);
}
}
}
52 changes: 38 additions & 14 deletions hello-world/react-hooks/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
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 { useState } from "react";
import reactLogo from "./assets/logo.svg";
import VideoCapture from "./components/VideoCapture/VideoCapture";
import ImageCapture from "./components/ImageCapture/ImageCapture";
import "./App.css";

enum Modes {
VIDEO_CAPTURE = "video",
IMAGE_CAPTURE = "image",
}

function App() {
const [mode, setMode] = useState("video");
const [mode, setMode] = useState(Modes.VIDEO_CAPTURE);

const showVideoCapture = () => setMode(Modes.VIDEO_CAPTURE);

const showImageCapture = () => setMode(Modes.IMAGE_CAPTURE);

return (
<div className='App'>
<div className='title'>
<h2 className='title-text'>Hello World for React</h2>
<img className='title-logo' src={reactLogo} alt="logo"></img>
<div className="hello-world-page">
<div className="title">
<h2 className="title-text">Hello World for React</h2>
<img className="title-logo" src={reactLogo} alt="logo"></img>
</div>
<div className='top-btns'>
<button onClick={()=>{setMode("video")}} style={{backgroundColor: mode === "video" ? "rgb(255, 174, 55)" : "#fff"}}>Video Capture</button>
<button onClick={()=>{setMode("image")}} style={{backgroundColor: mode === "image" ? "rgb(255, 174, 55)" : "#fff"}}>Image Capture</button>
<div className="buttons-container">
<button
style={{
backgroundColor: mode === Modes.VIDEO_CAPTURE ? "rgb(255,174,55)" : "white",
}}
onClick={showVideoCapture}
>
Decode Video
</button>
<button
style={{
backgroundColor: mode === Modes.IMAGE_CAPTURE ? "rgb(255,174,55)" : "white",
}}
onClick={showImageCapture}
>
Decode Image
</button>
</div>
{ mode === "video" ? <VideoCapture /> : <ImageCapture /> }
<div className="container">{mode === Modes.VIDEO_CAPTURE ? <VideoCapture /> : <ImageCapture />}</div>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,6 +14,7 @@
margin: 0 auto;
}

.capture-img .result-area {
.image-capture-container .results {
margin-top: 20px;
}
height: 100%;
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
import { useEffect, useRef, MutableRefObject, useCallback, ChangeEvent } from "react";
import "../../dynamsoft.config";
import React, { useRef, useEffect, MutableRefObject, useCallback } from "react";
import "../../dynamsoft.config"; // import side effects. The license, engineResourcePath, so on.
import { EnumCapturedResultItemType } from "dynamsoft-core";
import type { BarcodeResultItem } from "dynamsoft-barcode-reader";
import { BarcodeResultItem } from "dynamsoft-barcode-reader";
import { CaptureVisionRouter } from "dynamsoft-capture-vision-router";
import "./ImageCapture.css";

export default () => {
const resDiv: MutableRefObject<HTMLDivElement | null> = useRef(null);
function ImageCapture() {
const resultsContainer: MutableRefObject<HTMLDivElement | null> = useRef(null);

const pCvRouter: MutableRefObject<Promise<CaptureVisionRouter> | null> = useRef(null);
const bDestoried = useRef(false);
let pCvRouter: MutableRefObject<Promise<CaptureVisionRouter> | null> = useRef(null);
let isDestroyed = useRef(false);

const captureImage = useCallback(async(e: ChangeEvent<HTMLInputElement>)=>{
const captureImage = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
let files = [...(e.target.files as any as File[])];
e.target.value = '';
resDiv.current!.innerText = "";
e.target.value = ""; // reset input
resultsContainer.current!.innerText = "";

try {
// ensure cvRouter is created only once
const cvRouter = await (pCvRouter.current = pCvRouter.current || CaptureVisionRouter.createInstance());
if (bDestoried.current) return;
for(let file of files){
if (isDestroyed.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`;
if (isDestroyed.current) return;

// Print file name if there's multiple files
if (files.length > 1) {
resultsContainer.current!.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.current!.innerText += item.text + "\n";
resultsContainer.current!.innerText += item.text + "\n"; // output the decoded barcode text
console.log(item.text);
}
if (!result.items.length) resDiv.current!.innerText += 'No barcode found\n';
// If no items are found, display that no barcode was detected
if (!result.items.length) resultsContainer.current!.innerText += "No barcode found";
}
} catch (ex: any) {
let errMsg = ex.message || ex;
Expand All @@ -43,25 +49,28 @@ export default () => {
}, []);

useEffect((): any => {
// reset value so works in React.StrictMode
bDestoried.current = false;
// onBeforeUnmount
// In 'development', React runs setup and cleanup one extra time before the actual setup in Strict Mode.
isDestroyed.current = false;

// componentWillUnmount. dispose cvRouter when it's no longer needed
return async () => {
bDestoried.current = true;
if(pCvRouter.current){
try{
isDestroyed.current = true;
if (pCvRouter.current) {
try {
(await pCvRouter.current).dispose();
}catch(_){}
} catch (_) {}
}
}
};
}, []);

return (
<div className="capture-img">
<div className="img-ipt">
<input type="file" multiple onChange={captureImage} accept=".jpg,.jpeg,.icon,.gif,.svg,.webp,.png,.bmp"/>
<div className="image-capture-container">
<div className="input-container">
<input type="file" multiple accept=".jpg,.jpeg,.icon,.gif,.svg,.webp,.png,.bmp" onChange={captureImage} />
</div>
<div className="result-area" ref={resDiv}></div>
<div className="results" ref={resultsContainer}></div>
</div>
)
};
);
}

export default ImageCapture;
Original file line number Diff line number Diff line change
@@ -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;
}
.results {
width: 100%;
height: 10vh;
overflow: auto;
}
Loading