edit functionality + separation betw upload & edit
This commit is contained in:
227
src/app/edit-image-modal/edit-image-modal.component.ts
Normal file
227
src/app/edit-image-modal/edit-image-modal.component.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
// src/app/edit-image-modal.component.ts
|
||||
import { Component, Input, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { fabric } from 'fabric';
|
||||
import { Modal } from 'flowbite';
|
||||
import { DeckImage, DeckService, OcrResult } from '../deck.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-image-modal',
|
||||
templateUrl: './edit-image-modal.component.html',
|
||||
standalone: true,
|
||||
imports: [CommonModule]
|
||||
})
|
||||
export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
@Input() deckName: string = '';
|
||||
@Input() imageData : {imageSrc:string|ArrayBuffer|null, deckImage:DeckImage|null} = {imageSrc:null,deckImage:null};
|
||||
@Output() imageSaved = new EventEmitter<void>();
|
||||
@Output() closed = new EventEmitter<void>();
|
||||
@ViewChild('editImageModal') modalElement!: ElementRef;
|
||||
@ViewChild('canvas') canvasElement!: ElementRef<HTMLCanvasElement>;
|
||||
|
||||
detectedText: string = '';
|
||||
boxes: { x1: number; x2: number; y1: number; y2: number }[] = [];
|
||||
canvas!: fabric.Canvas;
|
||||
|
||||
maxCanvasWidth: number = 0;
|
||||
maxCanvasHeight: number = 0;
|
||||
|
||||
private keyDownHandler!: (e: KeyboardEvent) => void;
|
||||
modal: any;
|
||||
|
||||
constructor(private deckService: DeckService) { }
|
||||
|
||||
async ngAfterViewInit() {
|
||||
this.modal = new Modal(this.modalElement.nativeElement,{
|
||||
onHide: () => {
|
||||
this.closed.emit();
|
||||
}},
|
||||
);
|
||||
|
||||
this.maxCanvasWidth = window.innerWidth * 0.6;
|
||||
this.maxCanvasHeight = window.innerHeight * 0.6;
|
||||
|
||||
this.keyDownHandler = this.onKeyDown.bind(this);
|
||||
document.addEventListener('keydown', this.keyDownHandler);
|
||||
|
||||
await this.initializeCanvas();
|
||||
|
||||
this.modal.show();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
document.removeEventListener('keydown', this.keyDownHandler);
|
||||
if (this.canvas) {
|
||||
this.canvas.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
open(): void {
|
||||
this.modal.show();
|
||||
}
|
||||
|
||||
closeModal(): void {
|
||||
this.modal.hide();
|
||||
}
|
||||
|
||||
async initializeCanvas() {
|
||||
await this.processImage();
|
||||
}
|
||||
|
||||
private loadFabricImage(url: string): Promise<fabric.Image> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fabric.Image.fromURL(
|
||||
url,
|
||||
(img) => {
|
||||
resolve(img);
|
||||
},
|
||||
{
|
||||
crossOrigin: 'anonymous',
|
||||
originX: 'left',
|
||||
originY: 'top',
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async processImage(): Promise<void> {
|
||||
try {
|
||||
if (!this.imageData){
|
||||
return
|
||||
}
|
||||
|
||||
this.canvas = new fabric.Canvas(this.canvasElement.nativeElement);
|
||||
|
||||
// Hintergrundbild setzen
|
||||
const backgroundImage = await this.loadFabricImage(this.imageData.imageSrc as string);
|
||||
|
||||
const originalWidth = backgroundImage.width!;
|
||||
const originalHeight = backgroundImage.height!;
|
||||
|
||||
const scaleX = this.maxCanvasWidth / originalWidth;
|
||||
const scaleY = this.maxCanvasHeight / originalHeight;
|
||||
const scaleFactor = Math.min(scaleX, scaleY, 1);
|
||||
|
||||
const canvasWidth = originalWidth * scaleFactor;
|
||||
const canvasHeight = originalHeight * scaleFactor;
|
||||
|
||||
this.canvas.setWidth(canvasWidth);
|
||||
this.canvas.setHeight(canvasHeight);
|
||||
|
||||
backgroundImage.set({
|
||||
scaleX: scaleFactor,
|
||||
scaleY: scaleFactor,
|
||||
});
|
||||
|
||||
this.canvas.setBackgroundImage(backgroundImage, this.canvas.renderAll.bind(this.canvas));
|
||||
|
||||
this.boxes = [];
|
||||
|
||||
// Boxen hinzufügen
|
||||
this.imageData.deckImage?.boxes.forEach(box => {
|
||||
|
||||
const rect = new fabric.Rect({
|
||||
left: box.x1 * scaleFactor,
|
||||
top: box.y1 * scaleFactor,
|
||||
width: (box.x2-box.x1) * scaleFactor,
|
||||
height: (box.y2-box.y1) * scaleFactor,
|
||||
fill: 'rgba(255, 0, 0, 0.3)',
|
||||
selectable: true,
|
||||
hasControls: true,
|
||||
hasBorders: true,
|
||||
objectCaching: false,
|
||||
});
|
||||
|
||||
rect.on('modified', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
rect.on('moved', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
rect.on('scaled', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
rect.on('rotated', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
rect.on('removed', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
|
||||
this.canvas.add(rect);
|
||||
});
|
||||
|
||||
this.updateBoxCoordinates();
|
||||
|
||||
// this.detectedText = ocrResults.map(result => result.text).join('\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler bei der Bildverarbeitung:', error);
|
||||
}
|
||||
}
|
||||
|
||||
onKeyDown(e: KeyboardEvent): void {
|
||||
if (e.key === 'Delete' || e.key === 'Del') {
|
||||
const activeObject = this.canvas.getActiveObject();
|
||||
if (activeObject) {
|
||||
this.canvas.remove(activeObject);
|
||||
this.canvas.requestRenderAll();
|
||||
this.updateBoxCoordinates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateBoxCoordinates(): void {
|
||||
this.boxes = [];
|
||||
|
||||
let scaleFactor = 1;
|
||||
const bgImage = this.canvas.backgroundImage;
|
||||
if (bgImage && bgImage instanceof fabric.Image) {
|
||||
scaleFactor = bgImage.get('scaleX') || 1;
|
||||
}
|
||||
|
||||
this.canvas.getObjects('rect').forEach((rect: fabric.Rect) => {
|
||||
const left = rect.left!;
|
||||
const top = rect.top!;
|
||||
const width = rect.width! * rect.scaleX!;
|
||||
const height = rect.height! * rect.scaleY!;
|
||||
|
||||
const x1 = left / scaleFactor;
|
||||
const y1 = top / scaleFactor;
|
||||
const x2 = (left + width) / scaleFactor;
|
||||
const y2 = (top + height) / scaleFactor;
|
||||
|
||||
this.boxes.push({
|
||||
x1: Math.round(x1),
|
||||
x2: Math.round(x2),
|
||||
y1: Math.round(y1),
|
||||
y2: Math.round(y2)
|
||||
});
|
||||
});
|
||||
|
||||
this.canvas.requestRenderAll();
|
||||
}
|
||||
|
||||
save(): void {
|
||||
// Hier implementierst du die Logik zum Speichern der Bilddaten
|
||||
// Zum Beispiel über einen Service oder direkt hier
|
||||
const data = {
|
||||
deckname: this.deckName,
|
||||
bildname: this.imageData.deckImage?.name,//this.imageFile?.name,
|
||||
bildid: this.imageData.deckImage?.id,
|
||||
boxes: this.boxes,
|
||||
};
|
||||
this.deckService.saveImageData(data).subscribe({
|
||||
next: () => {
|
||||
this.imageSaved.emit();
|
||||
this.closeModal();
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Fehler beim Speichern des Bildes:', err);
|
||||
alert('Fehler beim Speichern des Bildes.');
|
||||
this.closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user