Angular からドラッグでファイルをFunctionsにアップロードしてOCR
Angular からファイルを選択し、Cloud Functions 経由で Cloud Vision を呼び出して OCRの結果を表示するところまでの疎通確認ができた。
あと、ドラッグでファイルを登録できるようにできれば、アプリに組み込むための素材はそろう感じ。
これまでの経緯。
- Functions試す
- Functions環境構築
- Firestore連携
- ファイルアップロード
- Cloud Vision連携
- Cloud Functions アプリ呼び出し
- AngularからBase64化したファイルでCloud Functiono呼び出しOCR
出来上がったデモは、こんな感じ。
1.手順
Angular用に、ドラッグ&ドロップをサポートした、ファイルアップロード パッケージはいくつかあった(ちょっと試してみたのは、ng2-file-upload)
しかしながら、ファイルのアップロード自体は、Base64でJSONにのっけて送ることにしたため、まぁファイルのアップロード自体の機能は不要。
なので、ファイルのドロップに特化した以下のパッケージを使用する。
2.ドロップパッケージのインストール
ngx-dropzone
npm install ng2-file-upload --save
3.実装
3.1 app.module.ts
抜粋
import { BrowserModule } from '@angular/platform-browser';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireFunctionsModule, REGION } from '@angular/fire/functions';
import { NgxDropzoneModule } from 'ngx-dropzone';
:
@NgModule({
declarations: [
AppComponent,
:
],
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFirestoreModule,
AngularFireFunctionsModule,
NgxDropzoneModule,
:
],
providers: [
{ provide: REGION, useValue: 'us-central1' }
],
bootstrap: [AppComponent]
})
export class AppModule { }
3.2 Angular ページ
ngx-dropzoneのでもページを参考にしながら。
<h1>Fileupload</h1>
<div>
<div style="padding:20px;">
<textarea cols="60" rows="5" [(ngModel)]="ocrText"></textarea>
</div>
<div class="custom-dropzone" ngx-dropzone [accept]="'image/*'" (change)="onFileChanged($event)">
<ngx-dropzone-label>
<div>
<h2>ファイルをドラッグするかクリックしてファイル選択</h2>
</div>
</ngx-dropzone-label>
<ngx-dropzone-image-preview ngProjectAs="ngx-dropzone-preview" *ngFor="let f of files" [file]="f" [removable]="true" (removed)="onRemove(f)">
<ngx-dropzone-label>{{ f.name }} ({{ f.type }})</ngx-dropzone-label>
</ngx-dropzone-image-preview>
</div>
<button (click)="onUpload()">Upload!</button>
</div>
3.3 Angular CSS
ドロップゾーンのデザインをカスタマイズできる。
ngx-dropzone,
.custom-dropzone {
margin: 20px;
}
.custom-dropzone {
height: 140px;
//background: #333;
//color: #fff;
border: 2px dashed rgb(235, 79, 79);
border-radius: 8px;
font-size: 12px;
}
.custom-dropzone.ngx-dz-hovered {
border: 2px solid rgb(235, 79, 79);
}
3.4 Angular コンポーネント
基本的に、前回と同じ。選択されたファイルの取り扱いを少し変える。
import { Component, OnInit } from '@angular/core';
import { AngularFireFunctions } from '@angular/fire/functions';
import { Observable, from } from 'rxjs';
@Component({
selector: 'app-management',
templateUrl: './management.component.html',
styleUrls: ['./management.component.scss']
})
export class ManagementComponent implements OnInit {
addMessageCallable: any;
visionsCallable: any;
ocrText: string = "";
files: File[] = [];
constructor(private fns: AngularFireFunctions) {
this.visionsCallable = fns.httpsCallable('sampleOnCallVisions');
}
ngOnInit(): void {
}
onFileChanged(event) {
console.log(event);
this.files.push(...event.addedFiles);
}
onRemove(event) {
console.log(event);
this.files.splice(this.files.indexOf(event), 1);
}
async onUpload() {
const reader = new FileReader();
const promise = new Promise(function(resolve, reject){
reader.onload = (function(){
return function(e){
// data:text/plain;base64,xxxxx
var fileBase64 = e.target.result.split(',')[1];
resolve(fileBase64);
};
})();
});
const selectedFile = this.files[0];
console.log(selectedFile);
reader.readAsDataURL(selectedFile);
const fileBase64 = await promise.then();
console.log(fileBase64);
const observer = this.visionsCallable(
{
filename: selectedFile.name,
base64encodedFile: fileBase64
}) as Observable<any>;
try {
const res = await observer.toPromise();
this.ocrText = res.result;
} catch(e) {
console.log(e);
}
}
}
3.5 Functions
こちらは完全に、前回と同じ。
https://www.typea.info/blog/index.php/2020/08/11/angular-cloud-functions-ocr/
を参照。
ようやく、開発中のアプリに機能を組み込むことが出来そう!