How to Build Angular Barcode and QR Code Scanner Apps from Scratch

Development Environment

npm install -g @angular/cli

ng --version

Angular CLI: 13.3.7
Node: 16.13.1
Package Manager: npm 8.1.2
OS: win32 x64

Angular: 13.3.10
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1303.7
@angular-devkit/build-angular 13.3.7
@angular-devkit/core 13.3.7
@angular-devkit/schematics 13.3.7
@angular/cli 13.3.7
@schematics/angular 13.3.7
ng-packagr 13.3.1
rxjs 7.5.5
typescript 4.6.4

Steps to Create Angular App for Scanning Barcode and QR Code

Dynamsoft JavaScript barcode SDK provides two primary classes: BarcodeReader and BarcodeScanner. The BarcodeReader class supports reading barcode and QR code from static images, and the BarcodeScanner class supports scanning barcode and QR code from live video feeds. So in our Angular app, we will create two pages to demonstrate their functionalities respectively.

Scaffold and configure Angular project

We create a new Angular project named angular-barcode-qr-code-scanner in terminal:

ng new angular-barcode-qr-code-scanner
npm i dynamsoft-javascript-barcode
"build": 
{
"builder": "@angular-devkit/build-angular:browser",
"options": {
...
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/dynamsoft-javascript-barcode/dist",
"output": "assets/dynamsoft-javascript-barcode"
}
...
],
},
...
},

"test":
{
"builder": "@angular-devkit/build-angular:karma",
"options": {
...
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/dynamsoft-javascript-barcode/dist",
"output": "assets/dynamsoft-javascript-barcode"
}
],
...
}
}
import { BarcodeReader } from 'dynamsoft-javascript-barcode';

BarcodeReader.license =
'DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==';

BarcodeReader.engineResourcePath = 'assets/dynamsoft-javascript-barcode/';

export interface Product {
id: string;
name: string;
description: string;
}

export const products = [
{
id: 'reader',
name: 'Barcode and QR Code Reader',
description: 'Scan barcode and QR code from image files',
},
{
id: 'scanner',
name: 'Barcode and QR Code Scanner',
description: 'Scan barcode and QR code from camera stream',
},
];
  1. Create a top-bar component:
ng generate component top-bar 
<app-top-bar></app-top-bar>
<div class="container">
<router-outlet></router-outlet>
</div>
<a [routerLink]="['/']">
<h1>Dynamsoft Barcode Reader and Scanner</h1>
</a>
  1. Create a product-list component:
ng generate component product-list
import { Component } from '@angular/core';

import { products } from '../products';

@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css'],
})
export class ProductListComponent {
products = products;
}
<h2>Examples</h2>
<div *ngFor="let product of products">
<h3>
<div *ngIf="product.id === 'reader'; else elseBlock">
<a [title]="product.name + ' details'" [routerLink]="['/barcode-reader']"
>>

</a>
</div>
<ng-template #elseBlock
><a
[title]="product.name + ' details'"
[routerLink]="['/barcode-scanner']"
>>

</a></ng-template
>
</h3>

<p *ngIf="product.description">Description: </p>
</div>
import { ProductListComponent } from './product-list/product-list.component';
import { BarcodeReaderComponent } from './barcode-reader/barcode-reader.component';
import { BarcodeScannerComponent } from './barcode-scanner/barcode-scanner.component';

const routes: Routes = [
{ path: '', component: ProductListComponent },
{ path: 'barcode-reader', component: BarcodeReaderComponent },
{ path: 'barcode-scanner', component: BarcodeScannerComponent },
];

Create the Barcode Reader component

  1. Create the barcode-reader component.
ng generate component barcode-reader 
<span id="loading-status" style="font-size:x-large" [hidden]="isLoaded"
>Loading Library...</span
>
<br />

<input type="file" id="file" accept="image/*" (change)="onChange($event)" />
<div>
<a id="result"></a>
</div>

<div id="imageview">
<img id="image" />
<canvas id="overlay"></canvas>
</div>
import { Component, OnInit } from '@angular/core';
import { BarcodeReader } from 'dynamsoft-javascript-barcode';

@Component({
selector: 'app-barcode-reader',
templateUrl: './barcode-reader.component.html',
styleUrls: ['./barcode-reader.component.css'],
})
export class BarcodeReaderComponent implements OnInit {
isLoaded = false;
overlay: HTMLCanvasElement | undefined;
context: CanvasRenderingContext2D | undefined;
reader: BarcodeReader | undefined;

constructor() {}

ngOnInit(): void {
this.initOverlay();
(async () => {
this.reader = await BarcodeReader.createInstance();
this.isLoaded = true;
})();
}
}
onChange(event: Event) {
const element = event.currentTarget as HTMLInputElement;
let fileList: FileList | null = element.files;
if (fileList) {
let file = fileList.item(0) as any;
if (file) {
let fr = new FileReader();
fr.onload = (event: any) => {
let image = document.getElementById('image') as HTMLImageElement;
if (image) {
image.src = event.target.result;
const img = new Image();

img.onload = (event: any) => {
this.updateOverlay(img.width, img.height);
if (this.reader) {
this.reader.decode(file).then((results: any) => {
console.log(results);
let txts: any = [];
let elem = document.getElementById('result');
try {
let localization;
if (results.length > 0) {
for (var i = 0; i < results.length; ++i) {
txts.push(results[i].barcodeText);
localization = results[i].localizationResult;
this.drawOverlay(
localization,
results[i].barcodeText
);
}

if (elem) {
elem.innerHTML = txts.join(', ');
}
} else {
if (elem) {
elem.innerHTML = txts.join(', ');
}
}
} catch (e) {
alert(e);
}
});
}
};
img.src = event.target.result;
}
};
fr.readAsDataURL(file);
}
}
}

Create the Barcode Scanner component

  1. Create the barcode-scanner component:
ng generate component barcode-scanner 
<span id="loading-status" style="font-size:x-large" [hidden]="isLoaded"
>Loading Library...</span
>
<br />

<div class="select">
<label for="videoSource">Video source: </label>
<select id="videoSource" (change)="openCamera()"></select>
</div>

<div id="videoview">
<div class="dce-video-container" id="videoContainer"></div>
<canvas id="overlay"></canvas>
</div>
import { Component, OnInit } from '@angular/core';
import { BarcodeScanner } from 'dynamsoft-javascript-barcode';

@Component({
selector: 'app-barcode-scanner',
templateUrl: './barcode-scanner.component.html',
styleUrls: ['./barcode-scanner.component.css'],
})
export class BarcodeScannerComponent implements OnInit {
isLoaded = false;
overlay: HTMLCanvasElement | undefined;
context: CanvasRenderingContext2D | undefined;
scanner: BarcodeScanner | undefined;
cameraInfo: any = {};
videoSelect: HTMLSelectElement | undefined;

constructor() { }

ngOnInit(): void {
this.videoSelect = document.querySelector('select#videoSource') as HTMLSelectElement;
this.initOverlay();
(async () => {
await this.initBarcodeScanner();
})();
}

async initBarcodeScanner(): Promise<void> {
this.scanner = await BarcodeScanner.createInstance();
this.isLoaded = true;
await this.scanner.updateRuntimeSettings("speed");
let uiElement = document.getElementById('videoContainer');
if (uiElement) {
await this.scanner.setUIElement(uiElement);
let cameras = await this.scanner.getAllCameras();
this.listCameras(cameras);
await this.openCamera();
this.scanner.onFrameRead = results => {
this.clearOverlay();

let txts = [];
let resultElement = document.getElementById('result');
try {
let localization;
if (results.length > 0) {
for (var i = 0; i < results.length; ++i) {
txts.push(results[i].barcodeText);
localization = results[i].localizationResult;
this.drawOverlay(localization, results[i].barcodeText);
}
if (resultElement) {
resultElement.innerHTML = txts.join(', ');
}
}
else {
if (resultElement) {
resultElement.innerHTML = "No barcode found";
}
}

} catch (e) {
alert(e);
}
};
this.scanner.onPlayed = () => {
this.updateResolution();
}
await this.scanner.show();
}
}

Run the Angular project with SSL

Web camera access requires HTTPS protocol. Therefore, we use the ng serve --ssl command to run the Angular project. Without ssl, the NotAllowedError: Permission denied error is thrown:

GitHub Page Deployment

After pushing the source code to GitHub, we can deploy the Angular project to GitHub pages with GitHub actions.

  1. Create a custom workflow file including Angular Deploy gh-pages Actions:
name: Build and Deploy
on:
push:
branches:
- main
jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: All things angular
uses: AhsanAyaz/angular-deploy-gh-pages-actions@v1.3.2
with:
github_access_token: $
build_configuration: production
base_href: /angular-barcode-qr-code-scanner/
deploy_branch: gh-pages
angular_dist_build_folder: dist/angular-barcode-qr-code-scanner

Source Code

https://github.com/yushulx/angular-barcode-qr-code-scanner

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Xiao Ling

Xiao Ling

Manager of Dynamsoft Open Source Projects | Tech Lover