202 lines
9.9 KiB
TypeScript
202 lines
9.9 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
import { Core } from '@pdftron/webviewer';
|
|
import { hexToRgb } from '@utils/functions';
|
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
|
import { UserPreferenceService } from '@users/user-preference.service';
|
|
import { RedactionLogService } from '@services/files/redaction-log.service';
|
|
|
|
import { IRectangle, ISectionGrid, ISectionRectangle, SuperTypes } from '@red/domain';
|
|
import { firstValueFrom } from 'rxjs';
|
|
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
|
import { PdfViewer } from './pdf-viewer.service';
|
|
import { ActivatedRoute } from '@angular/router';
|
|
import { REDAnnotationManager } from './annotation-manager.service';
|
|
import { List } from '@iqser/common-ui';
|
|
import { REDDocumentViewer } from './document-viewer.service';
|
|
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
|
import Annotation = Core.Annotations.Annotation;
|
|
import Quad = Core.Math.Quad;
|
|
|
|
const DEFAULT_TEXT_ANNOTATION_OPACITY = 1;
|
|
const DEFAULT_REMOVED_ANNOTATION_OPACITY = 0.2;
|
|
|
|
@Injectable()
|
|
export class AnnotationDrawService {
|
|
constructor(
|
|
private readonly _dictionariesMapService: DictionariesMapService,
|
|
private readonly _redactionLogService: RedactionLogService,
|
|
private readonly _userPreferenceService: UserPreferenceService,
|
|
private readonly _activatedRoute: ActivatedRoute,
|
|
private readonly _annotationManager: REDAnnotationManager,
|
|
private readonly _pdf: PdfViewer,
|
|
private readonly _documentViewer: REDDocumentViewer,
|
|
private readonly _defaultColorsService: DefaultColorsService,
|
|
) {}
|
|
|
|
async draw(annotations: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
|
|
try {
|
|
await this._draw(annotations, hideSkipped, dossierTemplateId);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
convertColor(hexColor: string) {
|
|
return this._pdf.color(hexToRgb(hexColor));
|
|
}
|
|
|
|
annotationToQuads(annotation: Annotation) {
|
|
const x1 = annotation.getRect().x1;
|
|
const y1 = annotation.getRect().y1 + annotation.getRect().getHeight();
|
|
|
|
const x2 = annotation.getRect().x1 + annotation.getRect().getWidth();
|
|
const y2 = annotation.getRect().y1 + annotation.getRect().getHeight();
|
|
|
|
const x3 = annotation.getRect().x1 + annotation.getRect().getWidth();
|
|
const y3 = annotation.getRect().y1;
|
|
|
|
const x4 = annotation.getRect().x1;
|
|
const y4 = annotation.getRect().y1;
|
|
|
|
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
|
|
}
|
|
|
|
private async _draw(annotationWrappers: List<AnnotationWrapper>, hideSkipped: boolean, dossierTemplateId: string) {
|
|
const totalPages = await firstValueFrom(this._pdf.totalPages$);
|
|
const annotations = annotationWrappers
|
|
?.map(annotation => this._computeAnnotation(annotation, hideSkipped, totalPages, dossierTemplateId))
|
|
.filterTruthy();
|
|
const documentLoaded = await firstValueFrom(this._documentViewer.loaded$);
|
|
if (!documentLoaded) {
|
|
return;
|
|
}
|
|
await this._annotationManager.add(annotations);
|
|
|
|
if (this._userPreferenceService.areDevFeaturesEnabled) {
|
|
const { dossierId, fileId } = this._pdf;
|
|
const sectionsGrid$ = this._redactionLogService.getSectionGrid(dossierId, fileId);
|
|
const sectionsGrid = await firstValueFrom(sectionsGrid$).catch(() => ({ rectanglesPerPage: {} }));
|
|
await this._drawSections(sectionsGrid, dossierTemplateId);
|
|
}
|
|
}
|
|
|
|
private async _drawSections(sectionGrid: ISectionGrid, dossierTemplateId: string) {
|
|
const sections: Core.Annotations.RectangleAnnotation[] = [];
|
|
for (const page of Object.keys(sectionGrid.rectanglesPerPage)) {
|
|
const sectionRectangles = sectionGrid.rectanglesPerPage[page];
|
|
sectionRectangles.forEach(sectionRectangle => {
|
|
sections.push(this._computeSection(parseInt(page, 10), sectionRectangle, dossierTemplateId));
|
|
});
|
|
}
|
|
await this._annotationManager.add(sections);
|
|
}
|
|
|
|
private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle, dossierTemplateId: string) {
|
|
const rectangleAnnot = this._pdf.rectangle();
|
|
const pageHeight = this._documentViewer.getHeight(pageNumber);
|
|
const rectangle: IRectangle = {
|
|
topLeft: sectionRectangle.topLeft,
|
|
page: pageNumber,
|
|
height: sectionRectangle.height,
|
|
width: sectionRectangle.width,
|
|
};
|
|
rectangleAnnot.PageNumber = pageNumber;
|
|
rectangleAnnot.X = rectangle.topLeft.x - 1;
|
|
rectangleAnnot.Y = pageHeight - (rectangle.topLeft.y + rectangle.height) - 1;
|
|
rectangleAnnot.Width = rectangle.width + 2;
|
|
rectangleAnnot.Height = rectangle.height + 2;
|
|
rectangleAnnot.ReadOnly = true;
|
|
rectangleAnnot.StrokeColor = this.convertColor(this._defaultColorsService.getColor(dossierTemplateId, 'analysisColor'));
|
|
rectangleAnnot.StrokeThickness = 1;
|
|
|
|
return rectangleAnnot;
|
|
}
|
|
|
|
private _computeAnnotation(annotationWrapper: AnnotationWrapper, hideSkipped: boolean, totalPages: number, dossierTemplateId: string) {
|
|
const pageNumber = this._pdf.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
|
|
if (pageNumber > totalPages) {
|
|
// skip imported annotations from files that have more pages than the current one
|
|
return;
|
|
}
|
|
|
|
if (annotationWrapper.superType === SuperTypes.TextHighlight) {
|
|
const rectangleAnnot = this._pdf.rectangle();
|
|
const pageHeight = this._documentViewer.getHeight(pageNumber);
|
|
const rectangle: IRectangle = annotationWrapper.positions[0];
|
|
rectangleAnnot.PageNumber = pageNumber;
|
|
rectangleAnnot.X = rectangle.topLeft.x;
|
|
rectangleAnnot.Y = pageHeight - (rectangle.topLeft.y + rectangle.height);
|
|
rectangleAnnot.Width = rectangle.width;
|
|
rectangleAnnot.Height = rectangle.height;
|
|
rectangleAnnot.ReadOnly = true;
|
|
rectangleAnnot.StrokeColor = this.convertColor(annotationWrapper.color);
|
|
rectangleAnnot.StrokeThickness = 1;
|
|
rectangleAnnot.Id = annotationWrapper.id;
|
|
|
|
return rectangleAnnot;
|
|
}
|
|
|
|
const annotation = this._pdf.textHighlight();
|
|
annotation.Quads = this._rectanglesToQuads(annotationWrapper.positions, pageNumber);
|
|
annotation.Opacity = annotationWrapper.isChangeLogRemoved ? DEFAULT_REMOVED_ANNOTATION_OPACITY : DEFAULT_TEXT_ANNOTATION_OPACITY;
|
|
annotation.setContents(annotationWrapper.content);
|
|
annotation.PageNumber = pageNumber;
|
|
annotation.StrokeColor = this.convertColor(annotationWrapper.color);
|
|
annotation.Id = annotationWrapper.id;
|
|
annotation.ReadOnly = true;
|
|
|
|
const isOCR = annotationWrapper.isOCR && !annotationWrapper.isSuggestionResize;
|
|
if (isOCR && !this._annotationManager.isHidden(annotationWrapper.annotationId)) {
|
|
this._annotationManager.addToHidden(annotationWrapper.annotationId);
|
|
}
|
|
annotation.Hidden =
|
|
annotationWrapper.isChangeLogRemoved ||
|
|
(hideSkipped && annotationWrapper.isSkipped) ||
|
|
this._annotationManager.isHidden(annotationWrapper.annotationId);
|
|
annotation.setCustomData('redact-manager', 'true');
|
|
annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation));
|
|
annotation.setCustomData('suggestion', String(annotationWrapper.isSuggestion));
|
|
annotation.setCustomData('suggestionAdd', String(annotationWrapper.isSuggestionAdd));
|
|
annotation.setCustomData('suggestionAddToFalsePositive', String(annotationWrapper.isSuggestionAddToFalsePositive));
|
|
annotation.setCustomData('suggestionRemove', String(annotationWrapper.isSuggestionRemove));
|
|
annotation.setCustomData('suggestionRecategorizeImage', String(annotationWrapper.isSuggestionRecategorizeImage));
|
|
annotation.setCustomData('skipped', String(annotationWrapper.isSkipped));
|
|
annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
|
|
annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved));
|
|
annotation.setCustomData('opacity', String(annotation.Opacity));
|
|
|
|
const redactionColor =
|
|
annotationWrapper.isSuggestion && this._userPreferenceService.getDisplaySuggestionsInPreview()
|
|
? this._defaultColorsService.getColor(dossierTemplateId, 'requestAddColor')
|
|
: this._defaultColorsService.getColor(dossierTemplateId, 'previewColor');
|
|
annotation.setCustomData('redactionColor', String(redactionColor));
|
|
annotation.setCustomData('annotationColor', String(annotationWrapper.color));
|
|
|
|
const appliedRedactionColor = this._defaultColorsService.getColor(dossierTemplateId, 'appliedRedactionColor');
|
|
annotation.setCustomData('appliedRedactionColor', String(appliedRedactionColor));
|
|
|
|
return annotation;
|
|
}
|
|
|
|
private _rectanglesToQuads(positions: IRectangle[], pageNumber: number): Quad[] {
|
|
const pageHeight = this._documentViewer.getHeight(pageNumber);
|
|
return positions.map(p => this._rectangleToQuad(p, pageHeight));
|
|
}
|
|
|
|
private _rectangleToQuad(rectangle: IRectangle, pageHeight: number): Quad {
|
|
const x1 = rectangle.topLeft.x;
|
|
const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height);
|
|
|
|
const x2 = rectangle.topLeft.x + rectangle.width;
|
|
const y2 = pageHeight - (rectangle.topLeft.y + rectangle.height);
|
|
|
|
const x3 = rectangle.topLeft.x + rectangle.width;
|
|
const y3 = pageHeight - rectangle.topLeft.y;
|
|
|
|
const x4 = rectangle.topLeft.x;
|
|
const y4 = pageHeight - rectangle.topLeft.y;
|
|
|
|
return this._pdf.quad(x1, y1, x2, y2, x3, y3, x4, y4);
|
|
}
|
|
}
|