UNPKG

ngx-extended-pdf-viewer

Version:

Embedding PDF files in your Angular application. Highly configurable viewer including the toolbar, sidebar, and all the features you're used to.

340 lines (339 loc) 17.8 kB
import { RendererFactory2 } from '@angular/core'; import { AnnotationMode, EditorAnnotation } from './options/editor-annotations'; import { PdfLayer } from './options/optional_content_config'; import { PDFPrintRange } from './options/pdf-print-range'; import { PDFNotificationService } from './pdf-notification-service'; import * as i0 from "@angular/core"; export interface FindOptions { highlightAll?: boolean; matchCase?: boolean; wholeWords?: boolean; matchDiacritics?: boolean; dontScrollIntoView?: boolean; findMultiple?: boolean; regexp?: boolean; useSecondaryFindcontroller?: boolean; } export interface PDFExportScaleFactor { width?: number; height?: number; scale?: number; } /** * A rectangular region of a page, expressed in normalized coordinates on the * page's *un-rotated* frame. Every value is a fraction between 0 and 1, measured * from the top-left corner of the un-rotated page (x grows to the right, y grows * downwards). * * To screenshot a single annotation, use the editor's rotation-independent * rectangle `event.source.normalizedPageRect` (from the `annotationEditorEvent`), * which is already in this coordinate system. Note that the editor's raw * `x`/`y`/`width`/`height` are **not** suitable here: they are stored in whatever * rotation the page had when the annotation was added (axes swapped for 90°/270°), * so they only match this frame when the annotation was added un-rotated. * * Example: the upper-left quarter of a page is `{ x: 0, y: 0, width: 0.5, height: 0.5 }`. */ export interface PdfPageCropBox { /** Distance of the left edge from the left of the page, as a fraction (0..1). */ x: number; /** Distance of the top edge from the top of the page, as a fraction (0..1). */ y: number; /** Width of the region, as a fraction of the page width (0..1). */ width: number; /** Height of the region, as a fraction of the page height (0..1). */ height: number; } /** * Rotation (in degrees, clockwise) to render a page at, e.g. when exporting it * via {@link NgxExtendedPdfViewerService.getPageAsCanvas} / * {@link NgxExtendedPdfViewerService.getPageAsImage}. Overrides the rotation the * user applied in the viewer. `0` gives the page in its authored orientation * regardless of how the user rotated it; `90`/`180`/`270` force that rotation. * Omit it to follow the user's current on-screen rotation. */ export type PdfPageRotation = 0 | 90 | 180 | 270; type DirectionType = 'ltr' | 'rtl' | 'both' | undefined; export interface PdfImageParameters { urlOrDataUrl: string; page?: number; left?: number | string; bottom?: number | string; right?: number | string; top?: number | string; rotation?: 0 | 90 | 180 | 270; } export interface Line { x: number; y: number; width: number; height: number; direction: DirectionType; text: string; } export interface Section { x: number; y: number; width: number; height: number; direction: DirectionType; lines: Array<Line>; } export declare class NgxExtendedPdfViewerService { private readonly rendererFactory; /** * Tracks the most recently mounted `<ngx-extended-pdf-viewer>` instance's `openPDF()` * completion. Public for backward compatibility — historically used as the "is the viewer * ready?" gate when the library only supported a single instance at a time. * * Today this flag is **not** the source of truth for the service's own `find()` / * `findNext()` / `findPrevious()` methods; those gate on the live `findController` * directly. Component-internal effect guards have moved to a per-instance flag. * * In a future multi-viewer world this field will likely become "any viewer is mounted". * Prefer querying viewer state via a viewer reference (see future API) instead of via * this singleton flag. */ ngxExtendedPdfViewerInitialized: boolean; secondaryMenuIsEmpty: import("@angular/core").WritableSignal<boolean>; private readonly renderer; private PDFViewerApplication?; constructor(rendererFactory: RendererFactory2, notificationService: PDFNotificationService); find(text: string | string[] | RegExp, options?: FindOptions): Array<Promise<number>> | undefined; findNext(useSecondaryFindcontroller?: boolean): boolean; findPrevious(useSecondaryFindcontroller?: boolean): boolean; print(printRange?: PDFPrintRange): void; removePrintRange(): void; setPrintRange(printRange: PDFPrintRange): void; filteredPageCount(pageCount: number, range: PDFPrintRange): number; isInPDFPrintRange(pageIndex: number, printRange: PDFPrintRange): boolean; getPageAsLines(pageNumber: number): Promise<Array<Line>>; getPageAsText(pageNumber: number): Promise<string>; private convertTextInfoToText; /** * Renders a single page to an off-screen `<canvas>`. * * @param pageNumber 1-based page number to render. * @param scale How large the rendered page should be. Provide exactly one of * `width`, `height` (both in pixels) or `scale` (a zoom factor, e.g. `2`). * @param background Optional CSS color painted behind the page (e.g. `'rgba(255,0,0,0.3)'`). * @param backgroundColorToReplace The page background color that is replaced by `background`. Defaults to white. * @param annotationMode Which annotations to render. Defaults to * `AnnotationMode.ENABLE_STORAGE`, so the screenshot includes what you * see on screen: saved annotations, current form-field values, and * annotations you just added with the editor (e.g. an image stamp) that * haven't been saved into the PDF yet. Pass `AnnotationMode.ENABLE` to * get only the annotations already baked into the document, or * `AnnotationMode.DISABLE` for none. * @param cropBox Optional region to crop to, in normalized 0..1 coordinates on * the page's *un-rotated* frame (top-left origin). When set, only that * part of the page is returned; the crop is rotated to follow the * rendered rotation for you. To screenshot a single annotation, pass the * editor's rotation-independent rectangle: `event.source.normalizedPageRect` * (do **not** pass the raw `x`/`y`/`width`/`height`, which are stored in * the rotation the annotation was added at). See {@link PdfPageCropBox}. * @param rotation Optional rotation override (`0`, `90`, `180` or `270`). By * default the screenshot follows the rotation the user applied in the * viewer. Pass `0` to always get the page in its authored orientation * regardless of the user's rotation, or `90`/`180`/`270` to force a * specific rotation. See {@link PdfPageRotation}. * @returns The rendered (and optionally cropped) canvas, or `undefined` if no document is loaded. */ getPageAsCanvas(pageNumber: number, scale: PDFExportScaleFactor, background?: string, backgroundColorToReplace?: string, annotationMode?: AnnotationMode, cropBox?: PdfPageCropBox, rotation?: PdfPageRotation): Promise<HTMLCanvasElement | undefined>; /** * Renders a single page and returns it as a PNG data URL. * * Same parameters as {@link NgxExtendedPdfViewerService.getPageAsCanvas}; in * particular `cropBox` lets you export just a sub-region (e.g. a single * annotation) using normalized 0..1 page-relative coordinates. * * @returns A `data:image/png;base64,...` string, or `undefined` if no document is loaded. */ getPageAsImage(pageNumber: number, scale: PDFExportScaleFactor, background?: string, backgroundColorToReplace?: string, annotationMode?: AnnotationMode, cropBox?: PdfPageCropBox, rotation?: PdfPageRotation): Promise<string | undefined>; private draw; /** * Rotates a normalized (0..1, top-left origin) cropBox from the page's * un-rotated coordinate space into the space of a canvas rendered at * `rotation` degrees clockwise. For 90°/270° the width and height swap axes. */ private rotateCropBox; /** * Returns a new canvas containing only the region described by `cropBox` * (normalized 0..1 page-relative coordinates, top-left origin) of `source`. */ private cropCanvas; private getPageDrawContext; getCurrentDocumentAsBlob(): Promise<Blob | undefined>; getFormData(currentFormValues?: boolean): Promise<Array<Object>>; /** * Adds a page to the rendering queue * @param {number} pageIndex Index of the page to render * @returns {boolean} false, if the page has already been rendered, * if it's out of range or if the viewer hasn't been initialized yet */ addPageToRenderQueue(pageIndex: number): boolean; isRenderQueueEmpty(): boolean; hasPageBeenRendered(pageIndex: number): boolean; private sleep; renderPage(pageIndex: number): Promise<void>; currentlyRenderedPages(): Array<number>; numberOfPages(): number; getCurrentlyVisiblePageNumbers(): Array<number>; listLayers(): Promise<Array<PdfLayer> | undefined>; toggleLayer(layerId: string): Promise<void>; scrollPageIntoView(pageNumber: number, pageSpot?: { top?: number | string; left?: number | string; }): void; /** * Returns all editor annotations (drawings, text, images, highlights) in serialized format. * * **Two kinds of identifier:** * - `id` — a **temporary** identifier (`pdfjs_internal_editor_N`) regenerated * every session. Useful for live event tracking via `annotationEditorEvent`, * but it is **not** stable, so do not persist it. * - `customId` — a **stable**, developer-supplied identifier (e.g. a UUID). * It is only present if you set it (see below). Unlike `id`, it survives the * `getSerializedAnnotations()` → store → `addEditorAnnotation()` round-trip, * so it is the field to rely on when correlating saved annotations. * * **Example - Stable IDs across sessions (#3225):** * ```typescript * // First save: assign your own stable id to each annotation. * const annotations = pdfService.getSerializedAnnotations() ?? []; * const toStore = annotations.map((a) => ({ ...a, customId: a.customId ?? crypto.randomUUID() })); * localStorage.setItem('annotations', JSON.stringify(toStore)); * * // Restore: customId is preserved (the temporary `id` is regenerated). * const stored = JSON.parse(localStorage.getItem('annotations')!); * await pdfService.addEditorAnnotation(stored); * // getSerializedAnnotations() now returns the same customId values. * ``` * * @returns Array of serialized annotations (each with a temporary `id`, plus a * stable `customId` if you assigned one), or null if none exist */ getSerializedAnnotations(): EditorAnnotation[] | null | undefined; /** * Returns a single editor annotation by its identifier. * * Matches against **both** identifiers, so you can look an annotation up by * either the temporary `id` (e.g. the one carried by an `annotationEditorEvent`) * or the stable `customId` you assigned (see {@link getSerializedAnnotations}). * * @param id The annotation's temporary `id` or its stable `customId` * @returns The serialized annotation matching the identifier, or null if not found */ getSerializedAnnotation(id: string): EditorAnnotation | null | undefined; /** * Programmatically adds one or more editor annotations to the PDF. * * **ID Behavior:** * - The temporary `id` field is **ignored** - a fresh internal id is always * assigned, so no id conflicts can occur. * - The stable `customId` field, if present, is **preserved** (#3225). Set it * to your own value (e.g. a UUID) before storing, and the restored * annotation keeps it - `getSerializedAnnotations()` will return it again. * Uniqueness of `customId` values is your responsibility. * * **Supported Annotation Types:** * - Ink (drawings) * - FreeText (text boxes) * - Stamp (images) * - Highlight * - Popup (comments) * * **Timing:** an annotation is added to a page's annotation _editor_ layer, * which is created only after that page has been rendered (slightly after the * display annotation layer). Wait for the page's `(annotationEditorLayerRendered)` * event before calling this method - **not** `(annotationLayerRendered)`, which * fires too early. Calling it before the editor layer exists logs * `paste: "Cannot read properties of undefined (reading 'deserialize')"` and adds * nothing (see issue #2656). * * @param serializedAnnotation A single annotation object, array of annotations, or JSON string * @returns Promise that resolves when the annotation(s) have been added * * @example * // Add a single annotation (with or without ID - both work the same) * await pdfService.addEditorAnnotation({ * annotationType: 3, * color: [255, 0, 0], * value: 'Hello', * pageIndex: 0, * rect: [100, 100, 200, 150], * rotation: 0, * // `id` is ignored; set `customId` if you want a stable id that survives the round-trip * customId: 'a3f1c2e0-...' * }); */ addEditorAnnotation(serializedAnnotation: string | EditorAnnotation): Promise<void>; removeEditorAnnotations(filter?: (serialized: object) => boolean): void; private loadImageAsDataURL; /** * Adds an image to a page as a stamp (editor) annotation. Since this is a * viewer rather than an editor, the image is placed on the annotation editor * layer; in most cases the result is indistinguishable from a real stamp. * * The `left`, `bottom`, `right`, and `top` coordinates accept percentages * (e.g. `'50%'`), pixels (e.g. `'100px'`), or PDF coordinates (e.g. `100`). * Omitted coordinates default to the logical origin (`left`/`bottom` to `0`, * `right`/`top` to `'100%'`). If `page` is omitted, the current page is used. * * **Timing:** wait for the target page's `(annotationEditorLayerRendered)` * event before calling this - **not** `(annotationLayerRendered)`. The editor * layer is created only after the page is rendered, so calling it too early * logs `paste: "Cannot read properties of undefined (reading 'deserialize')"` * and adds nothing (see issue #2656). On large, lazily-rendered documents, * add each page's image from its own `(annotationEditorLayerRendered)` handler. * * @param parameters The image source, optional target page, position, and rotation * @returns Promise that resolves once the image has been added */ addImageToAnnotationLayer({ urlOrDataUrl, page, left, bottom, right, top, rotation }: PdfImageParameters): Promise<void>; /** * Adds a highlight (editor) annotation to a page. * * The `left`, `bottom`, `right`, and `top` coordinates accept percentages * (e.g. `'50%'`), pixels (e.g. `'100px'`), or PDF coordinates (e.g. `100`). * If `page` is omitted (`undefined`), the current page is used. * * **Timing:** like {@link addImageToAnnotationLayer}, wait for the target * page's `(annotationEditorLayerRendered)` event before calling this - **not** * `(annotationLayerRendered)`. Calling it before the editor layer exists logs * `paste: "Cannot read properties of undefined (reading 'deserialize')"` and * adds nothing (see issue #2656). * * @param color RGB color as a 0-255 triple, e.g. `[255, 255, 0]` for yellow * @param page Zero-based page index, or `undefined` for the current page * @param left Left edge (percentage, pixels, or PDF coordinate) * @param bottom Bottom edge (percentage, pixels, or PDF coordinate) * @param right Right edge (percentage, pixels, or PDF coordinate) * @param top Top edge (percentage, pixels, or PDF coordinate) * @param thickness Highlighter thickness; defaults to `12` * @param rotation Rotation in degrees (`0`, `90`, `180`, or `270`); defaults to `0` * @param opacity Opacity between `0` and `1`; defaults to `0.5` * @returns Promise that resolves once the highlight has been added */ addHighlightToAnnotationLayer(color: number[], page: number | undefined, left: number | string, bottom: number | string, right: number | string, top: number | string, thickness?: number, rotation?: 0 | 90 | 180 | 270, opacity?: number): Promise<void>; currentPageIndex(): number | undefined; private convertToPDFCoordinates; switchAnnotationEdtorMode(mode: number): void; set editorFontSize(size: number); set editorFontColor(color: string); set editorInkColor(color: string); set editorInkOpacity(opacity: number); set editorInkThickness(thickness: number); set editorHighlightColor(color: string); /** @deprecated This feature was never wired up in pdf.js. Use editorHighlightColor instead. */ set editorHighlightDefaultColor(color: string); set editorHighlightShowAll(showAll: boolean); set editorHighlightThickness(thickness: number); setEditorProperty(editorPropertyType: number, value: any): void; getCurrentPage(): number; getPageCount(): number; movePage(fromIndex: number, toIndex: number): void; static ɵfac: i0.ɵɵFactoryDeclaration<NgxExtendedPdfViewerService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<NgxExtendedPdfViewerService>; } export {};