114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
// src/app/upload-image-modal.component.ts
|
|
import { Component, Input, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
|
|
import { Box, DeckImage, DeckService, OcrResult } from '../deck.service';
|
|
import { CommonModule } from '@angular/common';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { Modal } from 'flowbite';
|
|
|
|
@Component({
|
|
selector: 'app-upload-image-modal',
|
|
templateUrl: './upload-image-modal.component.html',
|
|
standalone: true,
|
|
imports: [CommonModule]
|
|
})
|
|
export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
|
|
@Input() deckName: string = '';
|
|
@Output() imageUploaded = new EventEmitter<{ imageSrc: string | ArrayBuffer | null | undefined, deckImage:DeckImage }>();
|
|
|
|
@ViewChild('uploadImageModal') modalElement!: ElementRef;
|
|
@ViewChild('imageFile') imageFileElement!: ElementRef;
|
|
|
|
imageFile: File | null = null;
|
|
processingStatus: string = '';
|
|
loading: boolean = false;
|
|
modal: any;
|
|
|
|
constructor(private deckService: DeckService, private http: HttpClient) { }
|
|
|
|
ngAfterViewInit(): void {
|
|
this.modal = new Modal(this.modalElement.nativeElement);
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
// Modal wird automatisch von Flowbite verwaltet
|
|
}
|
|
|
|
open(): void {
|
|
this.resetState();
|
|
this.modal.show();
|
|
}
|
|
|
|
closeModal(): void {
|
|
this.modal.hide();
|
|
}
|
|
|
|
resetState(): void {
|
|
this.imageFile = null;
|
|
this.processingStatus = '';
|
|
this.loading = false;
|
|
}
|
|
|
|
onFileChange(event: any): void {
|
|
const file: File = event.target.files[0];
|
|
if (!file) return;
|
|
this.imageFile = file;
|
|
this.processingStatus = 'Verarbeitung läuft...';
|
|
this.loading = true;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = async (e) => {
|
|
const imageSrc = e.target?.result;
|
|
|
|
// Bild als Base64-String ohne Präfix (data:image/...)
|
|
const imageBase64 = (imageSrc as string).split(',')[1];
|
|
|
|
try {
|
|
const response = await this.http.post<any>('/api/ocr', { image: imageBase64 }).toPromise();
|
|
|
|
if (!response || !response.results) {
|
|
this.processingStatus = 'Ungültige Antwort vom OCR-Service';
|
|
this.loading = false;
|
|
return;
|
|
}
|
|
|
|
this.processingStatus = 'Verarbeitung abgeschlossen';
|
|
this.loading = false;
|
|
|
|
// Emit Event mit Bilddaten und OCR-Ergebnissen
|
|
const bildname=this.imageFile?.name??'';
|
|
const bildid=response.results.length>0?response.results[0].name:null
|
|
const boxes:Box[] = [];
|
|
response.results.forEach((result: OcrResult) => {
|
|
const box = result.box;
|
|
|
|
const xs = box.map((point: number[]) => point[0]);
|
|
const ys = box.map((point: number[]) => point[1]);
|
|
const xMin = Math.min(...xs);
|
|
const xMax = Math.max(...xs);
|
|
const yMin = Math.min(...ys);
|
|
const yMax = Math.max(...ys);
|
|
boxes.push({x1:xMin,x2:xMax,y1:yMin,y2:yMax})
|
|
});
|
|
const deckImage:DeckImage={name:bildname,id:bildid,boxes}
|
|
this.imageUploaded.emit({ imageSrc, deckImage });
|
|
this.resetFileInput();
|
|
// Schließe das Upload-Modal
|
|
this.closeModal();
|
|
} catch (error) {
|
|
console.error('Fehler beim OCR-Service:', error);
|
|
this.processingStatus = 'Fehler beim OCR-Service';
|
|
this.loading = false;
|
|
}
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
/**
|
|
* Setzt das Datei-Input-Feld zurück, sodass dieselbe Datei erneut ausgewählt werden kann.
|
|
*/
|
|
resetFileInput(): void {
|
|
if (this.imageFileElement && this.imageFileElement.nativeElement) {
|
|
this.imageFileElement.nativeElement.value = '';
|
|
}
|
|
}
|
|
}
|