Skip to content

Commit 0f6e381

Browse files
committed
Added document detector for image files
1 parent d1c6817 commit 0f6e381

16 files changed

+319
-10
lines changed

angular.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@
5959
"glob": "**/*",
6060
"input": "./node_modules/dynamsoft-camera-enhancer/dist",
6161
"output": "assets/dynamsoft-camera-enhancer"
62+
},
63+
{
64+
"glob": "**/*",
65+
"input": "./node_modules/dynamsoft-document-normalizer/dist",
66+
"output": "assets/dynamsoft-document-normalizer"
6267
}
6368
],
6469
"styles": [

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"dynamsoft-barcode-reader-bundle": "10.2.1000",
2222
"dynamsoft-camera-enhancer": "^4.0.2",
2323
"dynamsoft-capture-vision-std": "^1.2.10",
24+
"dynamsoft-document-normalizer": "^2.2.10",
2425
"dynamsoft-image-processing": "^2.2.30",
2526
"rxjs": "~7.5.0",
2627
"tslib": "^2.3.0",

src/app/app-routing.module.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { RouterModule, Routes } from '@angular/router';
33
import { ProductListComponent } from './product-list/product-list.component';
44
import { BarcodeReaderComponent } from './barcode-reader/barcode-reader.component';
55
import { BarcodeScannerComponent } from './barcode-scanner/barcode-scanner.component';
6+
import { FileDetectionComponent } from './file-detection/file-detection.component';
7+
import { CameraDetectionComponent } from './camera-detection/camera-detection.component';
68

79
const routes: Routes = [
810
{ path: '', component: ProductListComponent },
9-
{ path: 'barcode-reader', component: BarcodeReaderComponent },
10-
{ path: 'barcode-scanner', component: BarcodeScannerComponent },
11+
{ path: 'barcode-reader', component: BarcodeReaderComponent },
12+
{ path: 'barcode-scanner', component: BarcodeScannerComponent },
13+
{ path: 'file-detection', component: FileDetectionComponent },
14+
{ path: 'camera-detection', component: CameraDetectionComponent },
1115
];
1216

1317
@NgModule({

src/app/app.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { BarcodeReaderComponent } from './barcode-reader/barcode-reader.componen
88
import { BarcodeScannerComponent } from './barcode-scanner/barcode-scanner.component';
99
import { ProductListComponent } from './product-list/product-list.component';
1010
import { TopBarComponent } from './top-bar/top-bar.component';
11+
import { FileDetectionComponent } from './file-detection/file-detection.component';
12+
import { CameraDetectionComponent } from './camera-detection/camera-detection.component';
1113

1214
// import {NgxBarcodeQrcodeModule} from 'ngx-barcode-qrcode';
1315

@@ -18,6 +20,8 @@ import { TopBarComponent } from './top-bar/top-bar.component';
1820
BarcodeScannerComponent,
1921
ProductListComponent,
2022
TopBarComponent,
23+
FileDetectionComponent,
24+
CameraDetectionComponent,
2125

2226
],
2327
imports: [

src/app/camera-detection/camera-detection.component.css

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>camera-detection works!</p>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { CameraDetectionComponent } from './camera-detection.component';
4+
5+
describe('CameraDetectionComponent', () => {
6+
let component: CameraDetectionComponent;
7+
let fixture: ComponentFixture<CameraDetectionComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ CameraDetectionComponent ]
12+
})
13+
.compileComponents();
14+
});
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(CameraDetectionComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Component, OnInit } from '@angular/core';
2+
3+
@Component({
4+
selector: 'app-camera-detection',
5+
templateUrl: './camera-detection.component.html',
6+
styleUrls: ['./camera-detection.component.css']
7+
})
8+
export class CameraDetectionComponent implements OnInit {
9+
10+
constructor() { }
11+
12+
ngOnInit(): void {
13+
}
14+
15+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#imageview {
2+
position: relative;
3+
width: 20vw;
4+
}
5+
6+
#image {
7+
position: relative;
8+
width: 100%;
9+
height: 100%;
10+
}
11+
12+
#overlay {
13+
position: absolute;
14+
top: 0;
15+
left: 0;
16+
width: 100%;
17+
height: 100%;
18+
object-fit: contain;
19+
}
20+
21+
.container {
22+
align-items: center;
23+
border: 3px solid orange;
24+
}
25+
26+
/* #normalizedImage {
27+
width: 20vw;
28+
} */
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<span id="loading-status" style="font-size:x-large" [hidden]="isLoaded">Loading Library...</span>
2+
<br />
3+
4+
<div class="row">
5+
6+
<label for="binary"> <input type="radio" name="templates" value="binary" (change)="onRadioChange($event)" />Black &
7+
White </label>
8+
9+
10+
<label for="grayscale"><input type="radio" name="templates" value="grayscale" (change)="onRadioChange($event)" />
11+
Grayscale </label>
12+
13+
<label for="color"><input type="radio" name="templates" value="color" [checked]="true"
14+
(change)="onRadioChange($event)" /> Color </label>
15+
</div>
16+
17+
<input type="file" title="file" id="file" accept="image/*" (change)="onChange($event)" />
18+
19+
<div class="container">
20+
<div id="imageview">
21+
<img id="image" alt="" />
22+
<canvas id="overlay"></canvas>
23+
</div>
24+
25+
<div id="resultview">
26+
<canvas id="normalizedImage"></canvas>
27+
</div>
28+
29+
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { FileDetectionComponent } from './file-detection.component';
4+
5+
describe('FileDetectionComponent', () => {
6+
let component: FileDetectionComponent;
7+
let fixture: ComponentFixture<FileDetectionComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ FileDetectionComponent ]
12+
})
13+
.compileComponents();
14+
});
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(FileDetectionComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { OverlayManager } from '../overlay';
3+
import { CapturedResult, CaptureVisionRouter, SimplifiedCaptureVisionSettings } from 'dynamsoft-barcode-reader-bundle';
4+
import { DetectedQuadResultItem, EnumImageColourMode, NormalizedImageResultItem } from 'dynamsoft-document-normalizer';
5+
6+
@Component({
7+
selector: 'app-file-detection',
8+
templateUrl: './file-detection.component.html',
9+
styleUrls: ['./file-detection.component.css']
10+
})
11+
export class FileDetectionComponent implements OnInit {
12+
isLoaded = false;
13+
overlay: HTMLCanvasElement | undefined;
14+
context: CanvasRenderingContext2D | undefined;
15+
cvr: CaptureVisionRouter | undefined;
16+
overlayManager: OverlayManager;
17+
points: any[] = [];
18+
currentFile: File | undefined;
19+
NormalizeDocument_Color: string = "NormalizeDocument_Color";
20+
NormalizeDocument_Binary: string = "NormalizeDocument_Binary";
21+
NormalizeDocument_Gray: string = "NormalizeDocument_Gray";
22+
23+
constructor() {
24+
this.overlayManager = new OverlayManager();
25+
}
26+
27+
ngOnDestroy() {
28+
}
29+
30+
ngOnInit(): void {
31+
this.overlayManager.initOverlay(document.getElementById('overlay') as HTMLCanvasElement);
32+
(async () => {
33+
this.cvr = await CaptureVisionRouter.createInstance();
34+
this.isLoaded = true;
35+
})();
36+
}
37+
38+
onRadioChange(event: Event) {
39+
if (!this.cvr) {
40+
return;
41+
}
42+
43+
let target = event.target as HTMLInputElement;
44+
let colorMode = EnumImageColourMode.ICM_COLOUR;
45+
if (target.value === 'binary') {
46+
colorMode = EnumImageColourMode.ICM_BINARY;
47+
} else if (target.value === 'grayscale') {
48+
colorMode = EnumImageColourMode.ICM_GRAYSCALE;
49+
} else if (target.value === 'color') {
50+
colorMode = EnumImageColourMode.ICM_COLOUR;
51+
}
52+
53+
let cvr = this.cvr;
54+
(async () => {
55+
let settings: SimplifiedCaptureVisionSettings = await cvr.getSimplifiedSettings('NormalizeDocument_Default');
56+
settings.documentSettings.colourMode = colorMode;
57+
await this.cvr!.updateSettings('NormalizeDocument_Default', settings);
58+
this.normalize(this.currentFile!, this.points);
59+
})();
60+
}
61+
62+
async normalize(file: File, points: any) {
63+
if (this.cvr) {
64+
let settings: SimplifiedCaptureVisionSettings = await this.cvr.getSimplifiedSettings('NormalizeDocument_Default');
65+
settings.roi.points = points;
66+
settings.roiMeasuredInPercentage = false;
67+
await this.cvr!.updateSettings('NormalizeDocument_Default', settings);
68+
69+
this.cvr.capture(file, 'NormalizeDocument_Default').then((normalizedImagesResult: CapturedResult) => {
70+
if (normalizedImagesResult.items.length === 0) { return; }
71+
let result = normalizedImagesResult.items[0] as NormalizedImageResultItem;
72+
let image = document.getElementById('normalizedImage') as HTMLCanvasElement;
73+
image.width = result.imageData.width;
74+
image.height = result.imageData.height;
75+
const destinationContext = image.getContext('2d');
76+
destinationContext?.drawImage(result.toCanvas(), 0, 0);
77+
});
78+
}
79+
}
80+
81+
onChange(event: Event) {
82+
const element = event.currentTarget as HTMLInputElement;
83+
let fileList: FileList | null = element.files;
84+
if (fileList) {
85+
let file = fileList.item(0) as any;
86+
if (file) {
87+
this.currentFile = file;
88+
let fr = new FileReader();
89+
fr.onload = (event: any) => {
90+
let image = document.getElementById('image') as HTMLImageElement;
91+
if (image) {
92+
image.src = event.target.result;
93+
const img = new Image();
94+
95+
img.onload = async (event: any) => {
96+
this.overlayManager.updateOverlay(img.width, img.height);
97+
if (this.cvr) {
98+
let capturedResult: CapturedResult = await this.cvr.capture(file, 'DetectDocumentBoundaries_Default');
99+
if (capturedResult.items.length > 0) {
100+
let result = capturedResult.items[0] as DetectedQuadResultItem;
101+
this.points = result.location.points;
102+
this.overlayManager.drawOverlay(
103+
result.location,
104+
''
105+
);
106+
this.normalize(file, this.points);
107+
}
108+
}
109+
};
110+
img.src = event.target.result;
111+
}
112+
};
113+
fr.readAsDataURL(file);
114+
}
115+
}
116+
}
117+
118+
}

src/app/product-list/product-list.component.html

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,38 @@
1010
<h2>Examples</h2>
1111
<div *ngFor="let product of products">
1212
<h3>
13-
<div *ngIf="product.id === 'reader'; else elseBlock">
14-
<a [title]="product.name + ' details'" [routerLink]="['/barcode-reader']">>
15-
{{ product.name }}
16-
</a>
13+
<div>
14+
<ng-template [ngIf]="product.id === 'reader'">
15+
<a [title]="product.name + ' details'" [routerLink]="['/barcode-reader']">>
16+
{{ product.name }}
17+
</a>
18+
</ng-template>
1719
</div>
18-
<ng-template #elseBlock><a [title]="product.name + ' details'" [routerLink]="['/barcode-scanner']">>
19-
{{ product.name }}
20-
</a></ng-template>
20+
21+
<div>
22+
<ng-template [ngIf]="product.id === 'scanner'">
23+
<a [title]="product.name + ' details'" [routerLink]="['/barcode-scanner']">>
24+
{{ product.name }}
25+
</a>
26+
</ng-template>
27+
</div>
28+
29+
<div>
30+
<ng-template [ngIf]="product.id === 'file-detection'">
31+
<a [title]="product.name + ' details'" [routerLink]="['/file-detection']">>
32+
{{ product.name }}
33+
</a>
34+
</ng-template>
35+
</div>
36+
37+
<div>
38+
<ng-template [ngIf]="product.id === 'camera-detection'">
39+
<a [title]="product.name + ' details'" [routerLink]="['/camera-detection']">>
40+
{{ product.name }}
41+
</a>
42+
</ng-template>
43+
</div>
44+
2145
</h3>
2246

2347
<p *ngIf="product.description">Description: {{ product.description }}</p>

0 commit comments

Comments
 (0)