From 6b38de9892ccd7f14c37d313bb3719361170c3d8 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Thu, 10 Mar 2022 16:15:41 +0200 Subject: [PATCH] use pdf viewer instead of instance & extract some methods --- .../annotation-actions.component.ts | 30 ++-- .../file-workload.component.html | 1 - .../file-workload/file-workload.component.ts | 4 +- .../pdf-viewer/pdf-viewer.component.ts | 18 +-- .../file-preview-screen.component.html | 4 +- .../file-preview-screen.component.ts | 132 +++++------------ .../services/annotation-actions.service.ts | 75 ++++------ .../services/annotation-draw.service.ts | 137 +++++++----------- .../services/pdf-viewer.service.ts | 64 +++++--- 9 files changed, 195 insertions(+), 270 deletions(-) diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-actions/annotation-actions.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-actions/annotation-actions.component.ts index 6d83d104c..d16df6947 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-actions/annotation-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/annotation-actions/annotation-actions.component.ts @@ -3,12 +3,12 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { PermissionsService } from '@services/permissions.service'; import { AnnotationPermissions } from '@models/file/annotation.permissions'; import { AnnotationActionsService } from '../../services/annotation-actions.service'; -import { WebViewerInstance } from '@pdftron/webviewer'; import { UserService } from '@services/user.service'; import { AnnotationReferencesService } from '../../services/annotation-references.service'; import { MultiSelectService } from '../../services/multi-select.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { HelpModeService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; +import { PdfViewer } from '../../services/pdf-viewer.service'; export const AnnotationButtonTypes = { dark: 'dark', @@ -26,7 +26,6 @@ export class AnnotationActionsComponent implements OnChanges { @Input() buttonType: AnnotationButtonType = AnnotationButtonTypes.dark; @Input() tooltipPosition: 'before' | 'above' = 'before'; @Input() canPerformAnnotationActions: boolean; - @Input() viewer: WebViewerInstance; @Input() alwaysVisible: boolean; @Output() readonly annotationsChanged = new EventEmitter(); annotationPermissions: AnnotationPermissions; @@ -37,6 +36,7 @@ export class AnnotationActionsComponent implements OnChanges { readonly annotationReferencesService: AnnotationReferencesService, readonly helpModeService: HelpModeService, private readonly _userService: UserService, + private readonly _pdf: PdfViewer, private readonly _state: FilePreviewStateService, private readonly _permissionsService: PermissionsService, ) {} @@ -53,8 +53,8 @@ export class AnnotationActionsComponent implements OnChanges { } get viewerAnnotations() { - if (this.viewer?.Core.annotationManager) { - return this._annotations.map(a => this.viewer?.Core.annotationManager?.getAnnotationById(a.id)); + if (this._pdf.annotationManager) { + return this._annotations.map(a => this._pdf.annotationManager.getAnnotationById(a.id)); } else { return []; } @@ -76,6 +76,10 @@ export class AnnotationActionsComponent implements OnChanges { return ScrollableParentViews.ANNOTATIONS_LIST; } + get helpModeKey() { + return this.annotations[0]?.typeLabel?.split('.')[1]; + } + async ngOnChanges(): Promise { await this._setPermissions(); } @@ -95,28 +99,28 @@ export class AnnotationActionsComponent implements OnChanges { hideAnnotation($event: MouseEvent) { $event.stopPropagation(); - this.viewer.Core.annotationManager.hideAnnotations(this.viewerAnnotations); - this.viewer.Core.annotationManager.deselectAllAnnotations(); + this._pdf.annotationManager.hideAnnotations(this.viewerAnnotations); + this._pdf.annotationManager.deselectAllAnnotations(); this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, true); } showAnnotation($event: MouseEvent) { $event.stopPropagation(); - this.viewer.Core.annotationManager.showAnnotations(this.viewerAnnotations); - this.viewer.Core.annotationManager.deselectAllAnnotations(); + this._pdf.annotationManager.showAnnotations(this.viewerAnnotations); + this._pdf.annotationManager.deselectAllAnnotations(); this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, false); } resize($event: MouseEvent) { - this.annotationActionsService.resize($event, this.viewer, this.annotations[0]); + this.annotationActionsService.resize($event, this.annotations[0]); } acceptResize($event: MouseEvent) { - return this.annotationActionsService.acceptResize($event, this.viewer, this.annotations[0], this.annotationsChanged); + return this.annotationActionsService.acceptResize($event, this.annotations[0], this.annotationsChanged); } cancelResize($event: MouseEvent) { - this.annotationActionsService.cancelResize($event, this.viewer, this.annotations[0], this.annotationsChanged); + this.annotationActionsService.cancelResize($event, this.annotations[0], this.annotationsChanged); } private async _setPermissions() { @@ -127,8 +131,4 @@ export class AnnotationActionsComponent implements OnChanges { this.annotations, ); } - - get helpModeKey() { - return this.annotations[0]?.typeLabel?.split('.')[1]; - } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html index cbfbcaa6b..3be6766ec 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.html @@ -60,7 +60,6 @@ [alwaysVisible]="true" [annotations]="selectedAnnotations" [canPerformAnnotationActions]="state.isWritable$ | async" - [viewer]="viewer" buttonType="primary" tooltipPosition="above" > diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts index 6bb4db0f4..1f34c3d9e 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/file-workload/file-workload.component.ts @@ -25,7 +25,6 @@ import { shareLast, } from '@iqser/common-ui'; import { PermissionsService } from '@services/permissions.service'; -import { WebViewerInstance } from '@pdftron/webviewer'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { map, tap } from 'rxjs/operators'; import { File } from '@red/domain'; @@ -36,6 +35,7 @@ import { SkippedService } from '../../services/skipped.service'; import { FilePreviewStateService } from '../../services/file-preview-state.service'; import { ViewModeService } from '../../services/view-mode.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { PdfViewer } from '../../services/pdf-viewer.service'; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; @@ -56,7 +56,6 @@ export class FileWorkloadComponent { @Input() dialogRef: MatDialogRef; @Input() file!: File; @Input() annotationActionsTemplate: TemplateRef; - @Input() viewer: WebViewerInstance; @Output() readonly selectAnnotations = new EventEmitter(); @Output() readonly deselectAnnotations = new EventEmitter(); @Output() readonly selectPage = new EventEmitter(); @@ -73,6 +72,7 @@ export class FileWorkloadComponent { @ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef; constructor( + private readonly _pdf: PdfViewer, readonly filterService: FilterService, readonly skippedService: SkippedService, readonly state: FilePreviewStateService, diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts index 08fa127ce..f7d1628c1 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/pdf-viewer/pdf-viewer.component.ts @@ -66,7 +66,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha @Output() readonly manualAnnotationRequested = new EventEmitter(); @Output() readonly pageChanged = new EventEmitter(); @Output() readonly keyUp = new EventEmitter(); - @Output() readonly viewerReady = new EventEmitter(); + @Output() readonly viewerReady = new EventEmitter(); @Output() readonly annotationsChanged = new EventEmitter(); @ViewChild('viewer', { static: true }) viewer: ElementRef; @ViewChild('compareFileInput', { static: true }) compareFileInput: ElementRef; @@ -118,6 +118,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha this.addActiveScreenSubscription = this.stateService.blob$ .pipe( withLatestFrom(this.stateService.file$), + tap(() => (this.pdf.ready = false)), tap(([blob, file]) => this._loadDocument(blob, file)), ) .subscribe(); @@ -473,8 +474,8 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha this.documentViewer.getTool('AnnotationCreateRectangle').setStyles({ StrokeThickness: 2, - StrokeColor: this._annotationDrawService.getAndConvertColor(this.instance, dossierTemplateId, 'manual'), - FillColor: this._annotationDrawService.getAndConvertColor(this.instance, dossierTemplateId, 'manual'), + StrokeColor: this._annotationDrawService.getAndConvertColor(dossierTemplateId, 'manual'), + FillColor: this._annotationDrawService.getAndConvertColor(dossierTemplateId, 'manual'), Opacity: 0.6, }); } @@ -519,12 +520,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha ]); } - const actions = this._annotationActionsService.getViewerAvailableActions( - this.instance, - this.dossier, - annotationWrappers, - this.annotationsChanged, - ); + const actions = this._annotationActionsService.getViewerAvailableActions(this.dossier, annotationWrappers, this.annotationsChanged); this.instance.UI.annotationPopup.add(actions); } @@ -545,7 +541,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha private _addRectangleManualRedaction() { const activeAnnotation = this.annotationManager.getSelectedAnnotations()[0]; const activePage = activeAnnotation.getPageNumber(); - const quads = [this._annotationDrawService.annotationToQuads(activeAnnotation, this.instance)]; + const quads = [this._annotationDrawService.annotationToQuads(activeAnnotation)]; const manualRedaction = this._getManualRedaction({ [activePage]: quads }); this._cleanUpSelectionAndButtonState(); @@ -696,7 +692,7 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha private _setReadyAndInitialState(): void { this._ngZone.run(() => { this.pdf.ready = true; - this.viewerReady.emit(this.instance); + this.viewerReady.emit(); const routePageNumber: number = this._activatedRoute.snapshot.queryParams.page; this.pageChanged.emit(routePageNumber || 1); this._setInitialDisplayMode(); diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index a2f32d01f..8f1822104 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -66,7 +66,7 @@ (keyUp)="handleKeyEvent($event); handleArrowEvent($event)" (manualAnnotationRequested)="openManualAnnotationDialog($event)" (pageChanged)="viewerPageChanged($event)" - (viewerReady)="viewerReady($event)" + (viewerReady)="viewerReady()" *ngIf="displayPdfViewer" [annotations]="visibleAnnotations" [canPerformActions]="canPerformAnnotationActions$ | async" @@ -98,7 +98,6 @@ [dialogRef]="dialogRef" [file]="file" [selectedAnnotations]="selectedAnnotations" - [viewer]="activeViewer" > @@ -110,7 +109,6 @@ (annotationsChanged)="annotationsChangedByReviewAction($event)" [annotations]="[annotation]" [canPerformAnnotationActions]="canPerformAnnotationActions$ | async" - [viewer]="activeViewer" > diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts index c7cbce87a..bf3177a8f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts @@ -1,7 +1,6 @@ import { ChangeDetectorRef, Component, HostListener, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router'; -import { Core, WebViewerInstance } from '@pdftron/webviewer'; -import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component'; +import { Core } from '@pdftron/webviewer'; import { AutoUnsubscribe, CircleButtonTypes, @@ -71,13 +70,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni selectedAnnotations: AnnotationWrapper[] = []; displayPdfViewer = false; activeViewerPage: number = null; - @ViewChild(PdfViewerComponent) readonly viewerComponent: PdfViewerComponent; readonly canPerformAnnotationActions$: Observable; readonly fileId = this.stateService.fileId; readonly dossierId = this.stateService.dossierId; readonly file$ = this.stateService.file$.pipe(tap(file => this._fileUpdated(file))); ready = false; - private _instance: WebViewerInstance; private _lastPage: string; @ViewChild('fileWorkloadComponent') private readonly _workloadComponent: FileWorkloadComponent; @@ -140,10 +137,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni return this._fileData ? this._fileData.allAnnotations : []; } - get activeViewer(): WebViewerInstance { - return this._instance; - } - private get _fileData(): FileDataModel { return this.stateService.fileData; } @@ -162,19 +155,19 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } async updateViewMode(): Promise { - if (!this._instance?.Core.documentViewer.getDocument()) { + if (!this._pdf.ready) { return; } const textHighlightAnnotationIds = this._fileData.textHighlightAnnotations.map(a => a.id); - const textHighlightAnnotations = this._getAnnotations((a: Core.Annotations.Annotation) => + const textHighlightAnnotations = this._pdf.getAnnotations((a: Core.Annotations.Annotation) => textHighlightAnnotationIds.includes(a.Id), ); this._pdf.deleteAnnotations(textHighlightAnnotations); const ocrAnnotationIds = this._fileData.allAnnotations.filter(a => a.isOCR).map(a => a.id); - const annotations = this._getAnnotations(a => a.getCustomData('redact-manager')); + const annotations = this._pdf.getAnnotations(a => a.getCustomData('redact-manager')); const redactions = annotations.filter(a => a.getCustomData('redaction')); switch (this._viewModeService.viewMode) { @@ -185,8 +178,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni .filter(a => !ocrAnnotationIds.includes(a.Id)); const nonStandardEntries = annotations.filter(a => a.getCustomData('changeLogRemoved') === 'true'); this._setAnnotationsOpacity(standardEntries, true); - this._show(standardEntries); - this._hide(nonStandardEntries); + this._pdf.showAnnotations(standardEntries); + this._pdf.hideAnnotations(nonStandardEntries); break; } case 'DELTA': { @@ -194,30 +187,24 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const nonChangeLogEntries = annotations.filter(a => a.getCustomData('changeLog') === 'false'); this._setAnnotationsColor(redactions, 'annotationColor'); this._setAnnotationsOpacity(changeLogEntries, true); - this._show(changeLogEntries); - this._hide(nonChangeLogEntries); + this._pdf.showAnnotations(changeLogEntries); + this._pdf.hideAnnotations(nonChangeLogEntries); break; } case 'REDACTED': { const nonRedactionEntries = annotations.filter(a => a.getCustomData('redaction') === 'false'); this._setAnnotationsOpacity(redactions); this._setAnnotationsColor(redactions, 'redactionColor'); - this._show(redactions); - this._hide(nonRedactionEntries); + this._pdf.showAnnotations(redactions); + this._pdf.hideAnnotations(nonRedactionEntries); break; } case 'TEXT_HIGHLIGHTS': { this._loadingService.start(); const textHighlights = await firstValueFrom(this._pdfViewerDataService.loadTextHighlightsFor(this.dossierId, this.fileId)); - this._hide(annotations); + this._pdf.hideAnnotations(annotations); this._fileData.textHighlights = textHighlights; - await this._annotationDrawService.drawAnnotations( - this.activeViewer, - this._fileData.textHighlightAnnotations, - this.dossierId, - this.fileId, - false, - ); + await this._annotationDrawService.drawAnnotations(this._fileData.textHighlightAnnotations); this._loadingService.stop(); } } @@ -264,8 +251,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni rebuildFilters(deletePreviousAnnotations = false): void { const startTime = new Date().getTime(); if (deletePreviousAnnotations) { - const annotationsToDelete = this._instance?.Core.annotationManager?.getAnnotationsList() || []; - this._pdf.deleteAnnotations(annotationsToDelete); + this._pdf.deleteAnnotations(); console.log(`[REDACTION] Delete previous annotations time: ${new Date().getTime() - startTime} ms`); } @@ -303,18 +289,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni selectAnnotations(annotations?: AnnotationWrapper[]) { if (annotations) { const annotationsToSelect = this.multiSelectService.isActive ? [...this.selectedAnnotations, ...annotations] : annotations; - this.viewerComponent?.pdf?.selectAnnotations(annotationsToSelect, this.multiSelectService.isActive); + this._pdf.selectAnnotations(annotationsToSelect, this.multiSelectService.isActive); } else { - this.viewerComponent?.pdf?.deselectAllAnnotations(); + this._pdf.deselectAllAnnotations(); } } deselectAnnotations(annotations: AnnotationWrapper[]) { - this.viewerComponent.pdf.deselectAnnotations(annotations); + this._pdf.deselectAnnotations(annotations); } selectPage(pageNumber: number) { - this.viewerComponent.pdf.navigateToPage(pageNumber); + this._pdf.navigateToPage(pageNumber); this._workloadComponent?.scrollAnnotationsToPage(pageNumber, 'always'); this._lastPage = pageNumber.toString(); } @@ -333,9 +319,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const response = new ManualAnnotationResponse(entryWrapper, addAnnotationResponse); if (response?.annotationId) { - const annotation = this._instance.Core.annotationManager.getAnnotationById( - response.manualRedactionEntryWrapper.rectId, - ); + const annotation = this._pdf.annotationManager.getAnnotationById(response.manualRedactionEntryWrapper.rectId); this._pdf.deleteAnnotations([annotation]); const distinctPages = manualRedactionEntryWrapper.manualRedactionEntry.positions .map(p => p.page) @@ -409,19 +393,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni }; await this._router.navigate([], extras); - this._setActiveViewerPage(); + this.activeViewerPage = this._pdf.currentPage; this._changeDetectorRef.markForCheck(); } - async viewerReady($event: WebViewerInstance) { - this._instance = $event; + async viewerReady() { this.ready = true; await this._stampPDF(); await this._reloadAnnotations(); this._setExcludedPageStyles(); - this._instance.Core.documentViewer.addEventListener('pageComplete', () => { + this._pdf.documentViewer.addEventListener('pageComplete', () => { this._setExcludedPageStyles(); }); @@ -430,7 +413,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (pageNumber) { setTimeout(() => { this.selectPage(parseInt(pageNumber, 10)); - this._setActiveViewerPage(); + this.activeViewerPage = this._pdf.currentPage; this._scrollViews(); this._changeDetectorRef.markForCheck(); this._loadingService.stop(); @@ -474,27 +457,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni #deactivateMultiSelect(): void { this.multiSelectService.deactivate(); - this.viewerComponent?.pdf?.deselectAllAnnotations(); + this._pdf.deselectAllAnnotations(); this.handleAnnotationSelected([]); } - private _setActiveViewerPage() { - const currentPage = this._instance?.Core.documentViewer?.getCurrentPage(); - if (!currentPage) { - this.activeViewerPage = 1; - } else { - this.activeViewerPage = this._viewModeService.isCompare - ? currentPage % 2 === 0 - ? currentPage / 2 - : (currentPage + 1) / 2 - : currentPage; - } - } - private _setExcludedPageStyles() { const file = this._filesMapService.get(this.dossierId, this.fileId); setTimeout(() => { - const iframeDoc = this._instance.UI.iframeWindow.document; + const iframeDoc = this._pdf.UI.iframeWindow.document; const pageContainer = iframeDoc.getElementById(`pageWidgetContainer${this.activeViewerPage}`); if (pageContainer) { if (file.excludedPages.includes(this.activeViewerPage)) { @@ -507,15 +477,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private async _stampPDF() { - if (!this._instance?.Core.documentViewer.getDocument()) { + if (!this._pdf.ready) { return; } - const pdfNet = this._instance.Core.PDFNet; - const pdfDoc = await this._instance.Core.documentViewer.getDocument().getPDFDoc(); + const pdfDoc = await this._pdf.documentViewer.getDocument().getPDFDoc(); const file = this._filesMapService.get(this.dossierId, this.fileId); const allPages = [...Array(file.numberOfPages).keys()].map(page => page + 1); - await clearStamps(pdfDoc, pdfNet, allPages); + await clearStamps(pdfDoc, this._pdf.PDFNet, allPages); if (this._viewModeService.isRedacted) { const dossier = this._dossiersService.find(this.dossierId); @@ -525,8 +494,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } else { await this._stampExcludedPages(pdfDoc, file.excludedPages); } - this._instance.Core.documentViewer.refreshAll(); - this._instance.Core.documentViewer.updateView([this.activeViewerPage], this.activeViewerPage); + this._pdf.documentViewer.refreshAll(); + this._pdf.documentViewer.updateView([this.activeViewerPage], this.activeViewerPage); this._changeDetectorRef.markForCheck(); } @@ -534,7 +503,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const watermark = await this._watermarkService.getWatermark(dossierTemplateId).toPromise(); await stampPDFPage( document, - this._instance.Core.PDFNet, + this._pdf.PDFNet, watermark.text, watermark.fontSize, watermark.fontType, @@ -549,7 +518,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (excludedPages && excludedPages.length > 0) { await stampPDFPage( document, - this._instance.Core.PDFNet, + this._pdf.PDFNet, this._translateService.instant('file-preview.excluded-from-redaction') as string, 17, 'courier', @@ -642,7 +611,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private _deleteAnnotations(annotationsToDelete?: AnnotationWrapper[]) { - if (!this._instance?.Core.documentViewer.getDocument()) { + if (!this._pdf.ready) { return; } @@ -655,7 +624,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private async _cleanupAndRedrawAnnotations(newAnnotationsFilter?: (annotation: AnnotationWrapper) => boolean) { - if (!this._instance?.Core.documentViewer.getDocument()) { + if (!this._pdf.ready) { return; } @@ -669,20 +638,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni if (currentFilters) { this._handleDeltaAnnotationFilters(currentFilters, this.visibleAnnotations); } - await this._redrawAnnotations(newAnnotations); + await this._annotationDrawService.drawAnnotations(newAnnotations); console.log(`[REDACTION] Annotations redraw time: ${new Date().getTime() - startTime} ms for ${newAnnotations.length} annotations`); } - private _redrawAnnotations(annotations = this.allAnnotations) { - return this._annotationDrawService.drawAnnotations( - this._instance, - annotations, - this.fileId, - this.dossierId, - !!this._viewModeService.isCompare, - ); - } - private _handleDeltaAnnotationFilters(currentFilters: NestedFilter[], newAnnotations: AnnotationWrapper[]) { const primaryFilterGroup = this._filterService.getGroup('primaryFilters'); const primaryFilters = primaryFilterGroup.filters; @@ -703,7 +662,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private _findAndDeleteAnnotation(id: string) { - const viewerAnnotation = this._instance?.Core.annotationManager.getAnnotationById(id); + const viewerAnnotation = this._pdf.annotationManager.getAnnotationById(id); if (viewerAnnotation) { this._pdf.deleteAnnotations([viewerAnnotation]); } @@ -717,27 +676,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private _handleIgnoreAnnotationsDrawing(hideSkipped: boolean): void { - const ignored = this._getAnnotations(a => a.getCustomData('skipped')); + const ignored = this._pdf.getAnnotations(a => a.getCustomData('skipped')); if (hideSkipped) { - this._hide(ignored); + this._pdf.hideAnnotations(ignored); } else { - this._show(ignored); + this._pdf.showAnnotations(ignored); } } - private _getAnnotations(predicate: (value) => boolean) { - const annotations = this._instance.Core.annotationManager.getAnnotationsList(); - return predicate ? annotations.filter(predicate) : annotations; - } - - private _hide(annotations: Annotation[]): void { - this._instance.Core.annotationManager.hideAnnotations(annotations); - } - - private _show(annotations: Annotation[]): void { - this._instance.Core.annotationManager.showAnnotations(annotations); - } - private _setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal: boolean = false) { annotations.forEach(annotation => { annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 1; @@ -746,7 +692,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private _setAnnotationsColor(annotations: Annotation[], customData: string) { annotations.forEach(annotation => { - const color = this._annotationDrawService.convertColor(this._instance, annotation.getCustomData(customData)); + const color = this._annotationDrawService.convertColor(annotation.getCustomData(customData)); annotation['StrokeColor'] = color; annotation['FillColor'] = color; }); diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-actions.service.ts index 9678c87ae..932ebf2c4 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-actions.service.ts @@ -9,7 +9,7 @@ import { AnnotationPermissions } from '@models/file/annotation.permissions'; import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; import { BASE_HREF } from '../../../../../tokens'; import { UserService } from '@services/user.service'; -import { Core, WebViewerInstance } from '@pdftron/webviewer'; +import { Core } from '@pdftron/webviewer'; import { Dossier, IAddRedactionRequest, ILegalBasisChangeRequest, IRectangle, IResizeRequest } from '@red/domain'; import { toPosition } from '../../../utils/pdf-calculation.utils'; import { AnnotationDrawService } from './annotation-draw.service'; @@ -24,6 +24,7 @@ import { defaultDialogConfig } from '@iqser/common-ui'; import { filter } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { FilePreviewStateService } from './file-preview-state.service'; +import { PdfViewer } from './pdf-viewer.service'; import Annotation = Core.Annotations.Annotation; @Injectable() @@ -37,6 +38,7 @@ export class AnnotationActionsService { private readonly _translateService: TranslateService, private readonly _dialogService: DossiersDialogService, private readonly _dialog: MatDialog, + private readonly _pdf: PdfViewer, private readonly _annotationDrawService: AnnotationDrawService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _screenStateService: FilePreviewStateService, @@ -211,7 +213,6 @@ export class AnnotationActionsService { } getViewerAvailableActions( - viewer: WebViewerInstance, dossier: Dossier, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter, @@ -238,7 +239,7 @@ export class AnnotationActionsService { title: this._translateService.instant('annotation-actions.resize-accept.label'), onClick: () => this._ngZone.run(() => { - this.acceptResize(null, viewer, firstAnnotation, annotationsChanged); + this.acceptResize(null, firstAnnotation, annotationsChanged); }), }); availableActions.push({ @@ -247,7 +248,7 @@ export class AnnotationActionsService { title: this._translateService.instant('annotation-actions.resize-cancel.label'), onClick: () => this._ngZone.run(() => { - this.cancelResize(null, viewer, firstAnnotation, annotationsChanged); + this.cancelResize(null, firstAnnotation, annotationsChanged); }), }); return availableActions; @@ -257,7 +258,7 @@ export class AnnotationActionsService { type: 'actionButton', img: this._convertPath('/assets/icons/general/resize.svg'), title: this._translateService.instant('annotation-actions.resize.label'), - onClick: () => this._ngZone.run(() => this.resize(null, viewer, annotations[0])), + onClick: () => this._ngZone.run(() => this.resize(null, annotations[0])), }); } @@ -419,32 +420,26 @@ export class AnnotationActionsService { annotationToBeUpdated.hidden = hidden; } - resize($event: MouseEvent, viewer: WebViewerInstance, annotationWrapper: AnnotationWrapper) { + resize($event: MouseEvent, annotationWrapper: AnnotationWrapper) { $event?.stopPropagation(); annotationWrapper.resizing = true; - const annotationManager = viewer.Core.annotationManager; - const viewerAnnotation = annotationManager.getAnnotationById(annotationWrapper.id); + const viewerAnnotation = this._pdf.annotationManager.getAnnotationById(annotationWrapper.id); viewerAnnotation.ReadOnly = false; viewerAnnotation.Hidden = false; viewerAnnotation.disableRotationControl(); - annotationManager.redrawAnnotation(viewerAnnotation); - annotationManager.selectAnnotation(viewerAnnotation); + this._pdf.annotationManager.redrawAnnotation(viewerAnnotation); + this._pdf.annotationManager.selectAnnotation(viewerAnnotation); - this._annotationDrawService.annotationToQuads(viewerAnnotation, viewer); + this._annotationDrawService.annotationToQuads(viewerAnnotation); } - acceptResize( - $event: MouseEvent, - viewer: WebViewerInstance, - annotationWrapper: AnnotationWrapper, - annotationsChanged?: EventEmitter, - ) { + acceptResize($event: MouseEvent, annotationWrapper: AnnotationWrapper, annotationsChanged?: EventEmitter) { const data = { dossier: this._dossier }; const fileId = this._screenStateService.fileId; this._dialogService.openDialog('resizeAnnotation', $event, data, async (result: { comment: string }) => { - const textAndPositions = await this._extractTextAndPositions(viewer, annotationWrapper.id); + const textAndPositions = await this._extractTextAndPositions(annotationWrapper.id); const text = annotationWrapper.value === 'Rectangle' ? 'Rectangle' : annotationWrapper.isImage ? 'Image' : textAndPositions.text; @@ -463,21 +458,15 @@ export class AnnotationActionsService { }); } - cancelResize( - $event: MouseEvent, - viewer: WebViewerInstance, - annotationWrapper: AnnotationWrapper, - annotationsChanged: EventEmitter, - ) { + cancelResize($event: MouseEvent, annotationWrapper: AnnotationWrapper, annotationsChanged: EventEmitter) { $event?.stopPropagation(); annotationWrapper.resizing = false; - const annotationManager = viewer.Core.annotationManager; - const viewerAnnotation = annotationManager.getAnnotationById(annotationWrapper.id); + const viewerAnnotation = this._pdf.annotationManager.getAnnotationById(annotationWrapper.id); viewerAnnotation.ReadOnly = false; - annotationManager.redrawAnnotation(viewerAnnotation); - annotationManager.deselectAllAnnotations(); + this._pdf.annotationManager.redrawAnnotation(viewerAnnotation); + this._pdf.annotationManager.deselectAllAnnotations(); annotationsChanged.emit(annotationWrapper); } @@ -540,19 +529,19 @@ export class AnnotationActionsService { return this._baseHref + path; } - private async _extractTextAndPositions(viewer: WebViewerInstance, annotationId: string) { - const viewerAnnotation = viewer.Core.annotationManager.getAnnotationById(annotationId); + private async _extractTextAndPositions(annotationId: string) { + const viewerAnnotation = this._pdf.annotationManager.getAnnotationById(annotationId); - const document = await viewer.Core.documentViewer.getDocument().getPDFDoc(); + const document = await this._pdf.documentViewer.getDocument().getPDFDoc(); const page = await document.getPage(viewerAnnotation.getPageNumber()); - if (viewerAnnotation instanceof viewer.Core.Annotations.TextHighlightAnnotation) { + if (viewerAnnotation instanceof this._pdf.Annotations.TextHighlightAnnotation) { const words = []; const rectangles: IRectangle[] = []; for (const quad of viewerAnnotation.Quads) { const rect = toPosition( viewerAnnotation.getPageNumber(), - viewer.Core.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()), - this._translateQuads(viewer, viewerAnnotation.getPageNumber(), quad), + this._pdf.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()), + this._translateQuads(viewerAnnotation.getPageNumber(), quad), ); rectangles.push(rect); @@ -560,13 +549,13 @@ export class AnnotationActionsService { // TODO: so that we do not extract text from line above/line below const percentHeightOffset = rect.height / 10; - const pdfNetRect = new viewer.Core.PDFNet.Rect( + const pdfNetRect = new this._pdf.instance.Core.PDFNet.Rect( rect.topLeft.x, rect.topLeft.y + percentHeightOffset, rect.topLeft.x + rect.width, rect.topLeft.y + rect.height - percentHeightOffset, ); - const quadWords = await this._extractTextFromRect(viewer, page, pdfNetRect); + const quadWords = await this._extractTextFromRect(page, pdfNetRect); words.push(...quadWords); } @@ -579,8 +568,8 @@ export class AnnotationActionsService { } else { const rect = toPosition( viewerAnnotation.getPageNumber(), - viewer.Core.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()), - this._annotationDrawService.annotationToQuads(viewerAnnotation, viewer), + this._pdf.documentViewer.getPageHeight(viewerAnnotation.getPageNumber()), + this._annotationDrawService.annotationToQuads(viewerAnnotation), ); return { positions: [rect], @@ -589,16 +578,16 @@ export class AnnotationActionsService { } } - private _translateQuads(viewer: WebViewerInstance, page: number, quads: any) { - const rotation = viewer.Core.documentViewer.getCompleteRotation(page); + private _translateQuads(page: number, quads: any) { + const rotation = this._pdf.documentViewer.getCompleteRotation(page); return translateQuads(page, rotation, quads); } - private async _extractTextFromRect(viewer: WebViewerInstance, page: Core.PDFNet.Page, rect: Core.PDFNet.Rect) { - const txt = await viewer.Core.PDFNet.TextExtractor.create(); + private async _extractTextFromRect(page: Core.PDFNet.Page, rect: Core.PDFNet.Rect) { + const txt = await this._pdf.PDFNet.TextExtractor.create(); txt.begin(page, rect); // Read the page. - const words = []; + const words: string[] = []; // Extract words one by one. let line = await txt.getFirstLine(); for (; await line.isValid(); line = await line.getNextLine()) { diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-draw.service.ts index 989351705..8d9bd8cf8 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/annotation-draw.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { Core, WebViewerInstance } from '@pdftron/webviewer'; +import { Core } from '@pdftron/webviewer'; import { hexToRgb } from '@utils/functions'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { UserPreferenceService } from '@services/user-preference.service'; @@ -11,6 +11,9 @@ import { SkippedService } from './skipped.service'; import { firstValueFrom } from 'rxjs'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { DossiersService } from '../../../../../services/dossiers/dossiers.service'; +import { PdfViewer } from './pdf-viewer.service'; +import { FilePreviewStateService } from './file-preview-state.service'; +import { ViewModeService } from './view-mode.service'; import Annotation = Core.Annotations.Annotation; @Injectable() @@ -25,57 +28,54 @@ export class AnnotationDrawService { private readonly _redactionLogService: RedactionLogService, private readonly _userPreferenceService: UserPreferenceService, private readonly _skippedService: SkippedService, + private readonly _pdf: PdfViewer, + private readonly _state: FilePreviewStateService, + private readonly _viewModeService: ViewModeService, ) {} - async drawAnnotations( - activeViewer: WebViewerInstance, - annotationWrappers: AnnotationWrapper[], - fileId: string, - dossierId: string, - compareMode = false, - ) { - if (!activeViewer) { + async drawAnnotations(annotationWrappers: AnnotationWrapper[]) { + if (!this._pdf.instance || !this._pdf.ready) { return; } - const pdfNet = activeViewer.Core.PDFNet; + const pdfNet = this._pdf.instance.Core.PDFNet; await pdfNet.runWithCleanup( async () => { - await this._drawAnnotations(activeViewer, annotationWrappers, fileId, dossierId, compareMode); + await this._drawAnnotations(annotationWrappers); }, environment.licenseKey ? atob(environment.licenseKey) : null, ); } - getColor(activeViewer: WebViewerInstance, dossierTemplateId: string, superType: string, dictionary?: string) { + getColor(superType: string, dictionary?: string) { let color: string; switch (superType) { case 'hint': case 'redaction': case 'recommendation': - color = this._dictionariesMapService.getDictionaryColor(dictionary, dossierTemplateId); + color = this._dictionariesMapService.getDictionaryColor(dictionary, this._state.dossierTemplateId); break; case 'skipped': - color = this._dictionariesMapService.getDictionaryColor(superType, dossierTemplateId); + color = this._dictionariesMapService.getDictionaryColor(superType, this._state.dossierTemplateId); break; default: - color = this._dictionariesMapService.getDictionaryColor(superType, dossierTemplateId); + color = this._dictionariesMapService.getDictionaryColor(superType, this._state.dossierTemplateId); break; } return color; } - getAndConvertColor(activeViewer: WebViewerInstance, dossierTemplateId: string, superType: string, dictionary?: string) { - return this.convertColor(activeViewer, this.getColor(activeViewer, dossierTemplateId, superType, dictionary)); + getAndConvertColor(superType: string, dictionary?: string) { + return this.convertColor(this.getColor(superType, dictionary)); } - convertColor(activeViewer: WebViewerInstance, hexColor: string) { + convertColor(hexColor: string) { const rgbColor = hexToRgb(hexColor); - return new activeViewer.Core.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b); + return new this._pdf.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b); } - annotationToQuads(annotation: Annotation, activeViewer: WebViewerInstance) { + annotationToQuads(annotation: Annotation) { const x1 = annotation.getRect().x1; const y1 = annotation.getRect().y1 + annotation.getRect().getHeight(); @@ -88,51 +88,42 @@ export class AnnotationDrawService { const x4 = annotation.getRect().x1; const y4 = annotation.getRect().y1; - return new activeViewer.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4); + return new this._pdf.instance.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4); } - private async _drawAnnotations( - activeViewer: WebViewerInstance, - annotationWrappers: AnnotationWrapper[], - fileId: string, - dossierId: string, - compareMode: boolean, - ) { - const annotations = annotationWrappers - .map(annotation => this._computeAnnotation(activeViewer, annotation, dossierId, compareMode)) - .filter(a => !!a); - const annotationManager = activeViewer.Core.annotationManager; + private async _drawAnnotations(annotationWrappers: AnnotationWrapper[]) { + const annotations = annotationWrappers.map(annotation => this._computeAnnotation(annotation)).filter(a => !!a); + const annotationManager = this._pdf.annotationManager; annotationManager.addAnnotations(annotations, { imported: true }); await annotationManager.drawAnnotationsFromList(annotations); if (this._userPreferenceService.areDevFeaturesEnabled) { - const sectionsGrid = await firstValueFrom(this._redactionLogService.getSectionGrid(dossierId, fileId)).catch(() => ({ - rectanglesPerPage: {}, - })); - await this._drawSections(activeViewer, sectionsGrid, dossierId); + const { dossierId, fileId } = this._state; + const sectionsGrid$ = this._redactionLogService.getSectionGrid(dossierId, fileId); + const sectionsGrid = await firstValueFrom(sectionsGrid$).catch(() => ({ rectanglesPerPage: {} })); + await this._drawSections(sectionsGrid); } } - private async _drawSections(activeViewer: WebViewerInstance, sectionGrid: ISectionGrid, dossierId: string) { + private async _drawSections(sectionGrid: ISectionGrid) { 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(activeViewer, parseInt(page, 10), sectionRectangle, dossierId)); + sections.push(this._computeSection(parseInt(page, 10), sectionRectangle)); // sectionRectangle.tableCells?.forEach(cell =>{ // sections.push(this.computeSection(activeViewer, parseInt(page, 10), cell)); // }) }); } - const annotationManager = activeViewer.Core.annotationManager; + const annotationManager = this._pdf.annotationManager; annotationManager.addAnnotations(sections, { imported: true }); await annotationManager.drawAnnotationsFromList(sections); } - private _computeSection(activeViewer: WebViewerInstance, pageNumber: number, sectionRectangle: ISectionRectangle, dossierId: string) { - const dossierTemplateId = this._dossiersService.find(dossierId).dossierTemplateId; - const rectangleAnnot = new activeViewer.Core.Annotations.RectangleAnnotation(); - const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber); + private _computeSection(pageNumber: number, sectionRectangle: ISectionRectangle) { + const rectangleAnnot = new this._pdf.Annotations.RectangleAnnotation(); + const pageHeight = this._pdf.documentViewer.getPageHeight(pageNumber); const rectangle: IRectangle = { topLeft: sectionRectangle.topLeft, page: pageNumber, @@ -145,27 +136,22 @@ export class AnnotationDrawService { rectangleAnnot.Width = rectangle.width + 2; rectangleAnnot.Height = rectangle.height + 2; rectangleAnnot.ReadOnly = true; - rectangleAnnot.StrokeColor = this.getAndConvertColor(activeViewer, dossierTemplateId, 'analysis', 'analysis'); + rectangleAnnot.StrokeColor = this.getAndConvertColor('analysis', 'analysis'); rectangleAnnot.StrokeThickness = 1; return rectangleAnnot; } - private _computeAnnotation( - activeViewer: WebViewerInstance, - annotationWrapper: AnnotationWrapper, - dossierId: string, - compareMode: boolean, - ) { - const pageNumber = compareMode ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber; - if (pageNumber > activeViewer.Core.documentViewer.getPageCount()) { + private _computeAnnotation(annotationWrapper: AnnotationWrapper) { + const pageNumber = this._viewModeService.isCompare ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber; + if (pageNumber > this._pdf.documentViewer.getPageCount()) { // skip imported annotations from files that have more pages than the current one return; } if (annotationWrapper.superType === 'text-highlight') { - const rectangleAnnot = new activeViewer.Core.Annotations.RectangleAnnotation(); - const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber); + const rectangleAnnot = new this._pdf.Annotations.RectangleAnnotation(); + const pageHeight = this._pdf.documentViewer.getPageHeight(pageNumber); const rectangle: IRectangle = annotationWrapper.positions[0]; rectangleAnnot.PageNumber = pageNumber; rectangleAnnot.X = rectangle.topLeft.x; @@ -173,37 +159,30 @@ export class AnnotationDrawService { rectangleAnnot.Width = rectangle.width; rectangleAnnot.Height = rectangle.height; rectangleAnnot.ReadOnly = true; - rectangleAnnot.StrokeColor = this.convertColor(activeViewer, annotationWrapper.color); + rectangleAnnot.StrokeColor = this.convertColor(annotationWrapper.color); rectangleAnnot.StrokeThickness = 1; rectangleAnnot.Id = annotationWrapper.id; return rectangleAnnot; } - const dossierTemplateId = this._dossiersService.find(dossierId).dossierTemplateId; - let annotation: Core.Annotations.RectangleAnnotation | Core.Annotations.TextHighlightAnnotation; if (annotationWrapper.rectangle || annotationWrapper.isImage) { - annotation = new activeViewer.Core.Annotations.RectangleAnnotation(); - const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber); + annotation = new this._pdf.Annotations.RectangleAnnotation(); + const pageHeight = this._pdf.documentViewer.getPageHeight(pageNumber); const firstPosition = annotationWrapper.positions[0]; annotation.X = firstPosition.topLeft.x; annotation.Y = pageHeight - (firstPosition.topLeft.y + firstPosition.height); annotation.Width = firstPosition.width; - annotation.FillColor = this.getAndConvertColor( - activeViewer, - dossierTemplateId, - annotationWrapper.superType, - annotationWrapper.type, - ); + annotation.FillColor = this.getAndConvertColor(annotationWrapper.superType, annotationWrapper.type); annotation.Opacity = annotationWrapper.isChangeLogRemoved ? AnnotationDrawService.DEFAULT_REMOVED_ANNOTATION_OPACITY : AnnotationDrawService.DEFAULT_RECTANGLE_ANNOTATION_OPACITY; annotation.Height = firstPosition.height; annotation.Intensity = 100; } else { - annotation = new activeViewer.Core.Annotations.TextHighlightAnnotation(); - annotation.Quads = this._rectanglesToQuads(annotationWrapper.positions, activeViewer, pageNumber); + annotation = new this._pdf.Annotations.TextHighlightAnnotation(); + annotation.Quads = this._rectanglesToQuads(annotationWrapper.positions, pageNumber); annotation.Opacity = annotationWrapper.isChangeLogRemoved ? AnnotationDrawService.DEFAULT_REMOVED_ANNOTATION_OPACITY : AnnotationDrawService.DEFAULT_TEXT_ANNOTATION_OPACITY; @@ -212,12 +191,7 @@ export class AnnotationDrawService { annotation.setContents(annotationWrapper.content); annotation.PageNumber = pageNumber; - annotation.StrokeColor = this.getAndConvertColor( - activeViewer, - dossierTemplateId, - annotationWrapper.superType, - annotationWrapper.type, - ); + annotation.StrokeColor = this.getAndConvertColor(annotationWrapper.superType, annotationWrapper.type); annotation.Id = annotationWrapper.id; annotation.ReadOnly = true; // change log entries are drawn lighter @@ -233,21 +207,18 @@ export class AnnotationDrawService { annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry)); annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved)); annotation.setCustomData('opacity', String(annotation.Opacity)); - annotation.setCustomData('redactionColor', String(this.getColor(activeViewer, dossierTemplateId, 'redaction', 'preview'))); - annotation.setCustomData( - 'annotationColor', - String(this.getColor(activeViewer, dossierTemplateId, annotationWrapper.superType, annotationWrapper.type)), - ); + annotation.setCustomData('redactionColor', String(this.getColor('redaction', 'redaction'))); + annotation.setCustomData('annotationColor', String(this.getColor(annotationWrapper.superType, annotationWrapper.type))); return annotation; } - private _rectanglesToQuads(positions: IRectangle[], activeViewer: WebViewerInstance, pageNumber: number): any[] { - const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber); - return positions.map(p => this._rectangleToQuad(p, activeViewer, pageHeight)); + private _rectanglesToQuads(positions: IRectangle[], pageNumber: number): any[] { + const pageHeight = this._pdf.documentViewer.getPageHeight(pageNumber); + return positions.map(p => this._rectangleToQuad(p, pageHeight)); } - private _rectangleToQuad(rectangle: IRectangle, activeViewer: WebViewerInstance, pageHeight: number): any { + private _rectangleToQuad(rectangle: IRectangle, pageHeight: number): any { const x1 = rectangle.topLeft.x; const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height); @@ -260,6 +231,6 @@ export class AnnotationDrawService { const x4 = rectangle.topLeft.x; const y4 = pageHeight - rectangle.topLeft.y; - return new activeViewer.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4); + return new this._pdf.instance.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4); } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/pdf-viewer.service.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/pdf-viewer.service.ts index 8b1767893..27617911f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/pdf-viewer.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/pdf-viewer.service.ts @@ -56,16 +56,20 @@ export class PdfViewer { return this.instance.UI; } + get Annotations() { + return this.instance.Core.Annotations; + } + + get PDFNet() { + return this.instance.Core.PDFNet; + } + get paginationOffset() { return this.viewModeService.isCompare ? 2 : 1; } get currentPage() { - try { - return this.viewModeService.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage; - } catch (e) { - return null; - } + return this.viewModeService.isCompare ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage; } get totalPages() { @@ -73,19 +77,36 @@ export class PdfViewer { return null; } - try { - return this.viewModeService.isCompare ? Math.ceil(this._totalInternalPages / 2) : this._totalInternalPages; - } catch (e) { - return null; - } + return this.viewModeService.isCompare ? Math.ceil(this._totalInternalPages / 2) : this._totalInternalPages; } private get _currentInternalPage() { - return this.instance?.Core.documentViewer?.getCurrentPage(); + return this.documentViewer?.getCurrentPage() ?? 1; } private get _totalInternalPages() { - return this.instance?.Core.documentViewer?.getPageCount(); + return this.documentViewer?.getPageCount() ?? 1; + } + + hideAnnotations(annotations: Annotation[]): void { + this.annotationManager.hideAnnotations(annotations); + } + + showAnnotations(annotations: Annotation[]): void { + this.annotationManager.showAnnotations(annotations); + } + + getAnnotations(predicate?: (value) => boolean) { + const annotations = this.annotationManager?.getAnnotationsList() ?? []; + return predicate ? annotations.filter(predicate) : annotations; + } + + getAnnotationsById(ids: readonly string[]) { + if (this.annotationManager) { + return ids.map(id => this.annotationManager.getAnnotationById(id)); + } + + return []; } async loadViewer(htmlElement: HTMLElement) { @@ -140,6 +161,10 @@ export class PdfViewer { } deselectAllAnnotations() { + if (!this.ready) { + return; + } + this.annotationManager.deselectAllAnnotations(); } @@ -147,16 +172,21 @@ export class PdfViewer { if (!annotations) { return; } + if (!multiSelectActive) { this.deselectAllAnnotations(); } - const annotationsFromViewer = annotations.map(ann => this._getAnnotationById(ann.id)); + const annotationsFromViewer = this.getAnnotationsById(annotations.map(a => a.id)); this.annotationManager.jumpToAnnotation(annotationsFromViewer[0]); this.annotationManager.selectAnnotations(annotationsFromViewer); } - deleteAnnotations(annotations: Annotation[] = this.annotationManager?.getAnnotationsList() ?? []) { + deleteAnnotations(annotations: Annotation[] = this.getAnnotations()) { + if (!this.ready) { + return; + } + try { this.annotationManager.deleteAnnotations(annotations, { imported: true, @@ -168,7 +198,7 @@ export class PdfViewer { } deselectAnnotations(annotations: AnnotationWrapper[]) { - const ann = annotations.map(a => this._getAnnotationById(a.id)); + const ann = this.getAnnotationsById(annotations.map(a => a.id)); this.annotationManager.deselectAnnotations(ann); } @@ -178,10 +208,6 @@ export class PdfViewer { } } - private _getAnnotationById(id: string): Annotation { - return this.annotationManager.getAnnotationById(id); - } - #convertPath(path: string) { return `${this._baseHref}${path}`; }