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/
を参照。
ようやく、開発中のアプリに機能を組み込むことが出来そう!