vue-pdfjs-headless 4.3.3 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -4
- package/package.json +7 -6
- package/dist/index.d.ts +0 -139
- package/dist/index.js +0 -654
package/README.md
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
[![NPM downloads][badge-npm-downloads]][url-npm]
|
|
6
6
|
[![NPM Unpacked Size (with version)][badge-npm-unpacked-size]][url-npm]
|
|
7
7
|
|
|
8
|
-
Headless Vue composables over pdfjs-dist
|
|
8
|
+
Headless Vue composables over pdfjs-dist that load a document, draw its pages and track the viewer's state, with no styling and no renderer of its own.
|
|
9
|
+
|
|
10
|
+
Design notes live in [the specs](https://github.com/Esposter/Esposter/tree/main/openspec/specs/vue-pdfjs-headless).
|
|
9
11
|
|
|
10
12
|
## Table of Contents
|
|
11
13
|
|
|
12
14
|
- 🚀 [Getting Started](#getting-started)
|
|
13
|
-
-
|
|
15
|
+
- 🧩 [Key Exports](#key-exports)
|
|
14
16
|
- ⚖️ [License](#license)
|
|
15
17
|
|
|
16
18
|
---
|
|
@@ -21,9 +23,42 @@ Headless Vue composables over pdfjs-dist: a document's loading, a page's drawing
|
|
|
21
23
|
pnpm i vue-pdfjs-headless
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
```ts
|
|
27
|
+
import * as pdfjs from "pdfjs-dist";
|
|
28
|
+
import { shallowRef } from "vue";
|
|
29
|
+
import { usePdfDocument, usePdfPage } from "vue-pdfjs-headless";
|
|
30
|
+
|
|
31
|
+
const canvas = shallowRef<HTMLCanvasElement>();
|
|
32
|
+
const { pdfDocument } = usePdfDocument({
|
|
33
|
+
renderer: {
|
|
34
|
+
api: pdfjs,
|
|
35
|
+
cMapUrl: "/cmaps/",
|
|
36
|
+
standardFontDataUrl: "/fonts/",
|
|
37
|
+
wasmUrl: "/wasm/",
|
|
38
|
+
workerSrc: "/pdf.worker.mjs",
|
|
39
|
+
},
|
|
40
|
+
source: "/document.pdf",
|
|
41
|
+
});
|
|
42
|
+
usePdfPage({ canvas, pageNumber: 1, pdfDocument });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Bind `canvas` to a `<canvas ref="canvas" />` in the component's template, and the page is drawn into it.
|
|
46
|
+
|
|
47
|
+
## <a name="key-exports">🧩 Key Exports</a>
|
|
25
48
|
|
|
26
|
-
|
|
49
|
+
| Export | Kind | Purpose |
|
|
50
|
+
| ------------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `PdfRenderer` | interface | The renderer's API module, its data folder URLs and its worker, which the consumer supplies |
|
|
52
|
+
| `PdfSource` | type | A document by its URL, its bytes, or a file the reader picked |
|
|
53
|
+
| `PdfViewerState` | interface | The viewer's pages, zoom, rotation, search, download and print, as state and actions |
|
|
54
|
+
| `readXfdf` | function | Reads the free-text annotations of an XFDF file, or an error naming what is wrong with it |
|
|
55
|
+
| `usePdfAnnotations` | composable | The reader's comments and free-text annotations, exported to and imported from XFDF |
|
|
56
|
+
| `usePdfDocument` | composable | Loads a document from a source through the consumer's renderer, with its password prompt and failure as state |
|
|
57
|
+
| `usePdfPage` | composable | Draws one page of a loaded document into a canvas, at the canvas's width and the device's pixel ratio |
|
|
58
|
+
| `usePdfThumbnails` | composable | One thumbnail per page, drawn only while its row is in view of the sidebar |
|
|
59
|
+
| `usePdfViewer` | composable | Builds the renderer's viewer for a loaded document, with its pages, zoom and search as state |
|
|
60
|
+
| `usePdfZoomGesture` | composable | Pinch and Ctrl-wheel zoom the viewer about the pointer, keeping the content under it in place |
|
|
61
|
+
| `writeXfdf` | function | Writes free-text annotations as XFDF |
|
|
27
62
|
|
|
28
63
|
## <a name="license">⚖️ License</a>
|
|
29
64
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-pdfjs-headless",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Headless Vue composables over pdfjs-dist: a document's loading, a page's drawing and the viewer's state, with no styling and no renderer of its own.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"headless",
|
|
@@ -43,20 +43,21 @@
|
|
|
43
43
|
"lint": "eslint .",
|
|
44
44
|
"lint:fix": "eslint --fix .",
|
|
45
45
|
"test": "vitest",
|
|
46
|
-
"typecheck": "
|
|
46
|
+
"typecheck": "tsrs --fast"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@esposter/shared": "4.
|
|
49
|
+
"@esposter/shared": "4.4.0",
|
|
50
|
+
"neverthrow": "^8.2.0"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"@esposter/configuration": "4.
|
|
53
|
+
"@esposter/configuration": "4.4.0",
|
|
53
54
|
"@vue/test-utils": "^2.5.1",
|
|
54
55
|
"happy-dom": "^21.0.4",
|
|
55
|
-
"tsdown": "
|
|
56
|
+
"tsdown": "0.23.2"
|
|
56
57
|
},
|
|
57
58
|
"peerDependencies": {
|
|
58
59
|
"pdfjs-dist": "^6.4.299",
|
|
59
60
|
"vue": "^3.5.44"
|
|
60
61
|
},
|
|
61
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "e1a416c4b91da69cc2aa259b50a4d656f204d272"
|
|
62
63
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { ComputedRef, MaybeRefOrGetter, Ref, ShallowRef } from "vue";
|
|
2
|
-
import * as PdfJs from "pdfjs-dist";
|
|
3
|
-
import { PDFDocumentLoadingTask, PDFDocumentProxy, PageViewport } from "pdfjs-dist";
|
|
4
|
-
import * as PdfJsViewer from "pdfjs-dist/web/pdf_viewer.mjs";
|
|
5
|
-
import { PDFViewer } from "pdfjs-dist/web/pdf_viewer.mjs";
|
|
6
|
-
export type PdfApi = Pick<typeof PdfJs, "getDocument" | "GlobalWorkerOptions" | "PasswordResponses">;
|
|
7
|
-
export type PdfDocumentParameters = Partial<Parameters<PdfApi["getDocument"]>[0]>;
|
|
8
|
-
export interface PdfLoadingProgress {
|
|
9
|
-
loaded: number;
|
|
10
|
-
total: number;
|
|
11
|
-
}
|
|
12
|
-
export interface PdfDocumentState {
|
|
13
|
-
isFailed: Ref<boolean>;
|
|
14
|
-
isPasswordRequested: Ref<boolean>;
|
|
15
|
-
isPasswordWrong: Ref<boolean>;
|
|
16
|
-
pdfDocument: ShallowRef<PDFDocumentProxy | undefined>;
|
|
17
|
-
progress: Ref<PdfLoadingProgress>;
|
|
18
|
-
submitPassword: (password: string) => void;
|
|
19
|
-
}
|
|
20
|
-
export interface PdfRenderer {
|
|
21
|
-
api: PdfApi;
|
|
22
|
-
cMapUrl: string;
|
|
23
|
-
standardFontDataUrl: string;
|
|
24
|
-
wasmUrl: string;
|
|
25
|
-
workerSrc: string;
|
|
26
|
-
}
|
|
27
|
-
export type PdfSource = File | string | Uint8Array;
|
|
28
|
-
interface UsePdfDocumentOptions {
|
|
29
|
-
parameters?: PdfDocumentParameters;
|
|
30
|
-
renderer: MaybeRefOrGetter<PdfRenderer | undefined>;
|
|
31
|
-
source: MaybeRefOrGetter<PdfSource | undefined>;
|
|
32
|
-
}
|
|
33
|
-
export declare const usePdfDocument: ({ parameters, renderer, source }: UsePdfDocumentOptions) => PdfDocumentState;
|
|
34
|
-
interface UsePdfPageOptions {
|
|
35
|
-
canvas: MaybeRefOrGetter<HTMLCanvasElement | undefined>;
|
|
36
|
-
isVisible?: MaybeRefOrGetter<boolean>;
|
|
37
|
-
pageNumber: MaybeRefOrGetter<number>;
|
|
38
|
-
pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
|
|
39
|
-
}
|
|
40
|
-
export declare const usePdfPage: ({ canvas, isVisible, pageNumber, pdfDocument }: UsePdfPageOptions) => void;
|
|
41
|
-
export interface PdfThumbnail {
|
|
42
|
-
canvas: ShallowRef<HTMLCanvasElement | undefined>;
|
|
43
|
-
isCurrent: ComputedRef<boolean>;
|
|
44
|
-
isVisible: Ref<boolean>;
|
|
45
|
-
pageNumber: number;
|
|
46
|
-
}
|
|
47
|
-
interface UsePdfThumbnailsOptions {
|
|
48
|
-
currentPageNumber: MaybeRefOrGetter<number>;
|
|
49
|
-
pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
|
|
50
|
-
root: MaybeRefOrGetter<HTMLElement | undefined>;
|
|
51
|
-
}
|
|
52
|
-
export declare const usePdfThumbnails: ({ currentPageNumber, pdfDocument, root }: UsePdfThumbnailsOptions) => ShallowRef<PdfThumbnail[]>;
|
|
53
|
-
export type PdfViewerApi = Pick<typeof PdfJsViewer, "EventBus" | "FindState" | "LinkTarget" | "PDFFindController" | "PDFLinkService" | "PDFViewer">;
|
|
54
|
-
export interface PdfMatchesCount {
|
|
55
|
-
current: number;
|
|
56
|
-
total: number;
|
|
57
|
-
}
|
|
58
|
-
export type PdfOutline = NonNullable<Awaited<ReturnType<PDFDocumentProxy["getOutline"]>>>;
|
|
59
|
-
export interface PdfPageOverlay {
|
|
60
|
-
element: HTMLElement;
|
|
61
|
-
pageNumber: number;
|
|
62
|
-
viewport: PageViewport;
|
|
63
|
-
}
|
|
64
|
-
export interface PdfViewerState {
|
|
65
|
-
actualSize: () => void;
|
|
66
|
-
currentPageNumber: Ref<number>;
|
|
67
|
-
download: (filename: string) => void;
|
|
68
|
-
findNext: () => void;
|
|
69
|
-
findPrevious: () => void;
|
|
70
|
-
fitPage: () => void;
|
|
71
|
-
fitWidth: () => void;
|
|
72
|
-
followBookmark: (item: PdfOutline[number]) => void;
|
|
73
|
-
goToPage: (pageNumber: number) => void;
|
|
74
|
-
isFullscreen: Ref<boolean>;
|
|
75
|
-
isMatchCase: Ref<boolean>;
|
|
76
|
-
isNotFound: Ref<boolean>;
|
|
77
|
-
isWholeWord: Ref<boolean>;
|
|
78
|
-
isZoomInDisabled: ComputedRef<boolean>;
|
|
79
|
-
matchesCount: Ref<PdfMatchesCount>;
|
|
80
|
-
nextPage: () => void;
|
|
81
|
-
outline: ShallowRef<PdfOutline>;
|
|
82
|
-
overlays: ShallowRef<PdfPageOverlay[]>;
|
|
83
|
-
pagesCount: Ref<number>;
|
|
84
|
-
pagesRotation: Ref<number>;
|
|
85
|
-
previousPage: () => void;
|
|
86
|
-
print: () => void;
|
|
87
|
-
rotate: () => void;
|
|
88
|
-
scale: Ref<number>;
|
|
89
|
-
searchQuery: Ref<string>;
|
|
90
|
-
toggleFullscreen: () => void;
|
|
91
|
-
zoomIn: () => void;
|
|
92
|
-
zoomOut: () => void;
|
|
93
|
-
}
|
|
94
|
-
interface UsePdfViewerOptions {
|
|
95
|
-
container: MaybeRefOrGetter<HTMLDivElement | undefined>;
|
|
96
|
-
highlightTerms?: MaybeRefOrGetter<string[]>;
|
|
97
|
-
pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
|
|
98
|
-
viewer: MaybeRefOrGetter<HTMLDivElement | undefined>;
|
|
99
|
-
viewerApi: MaybeRefOrGetter<PdfViewerApi | undefined>;
|
|
100
|
-
}
|
|
101
|
-
export declare const usePdfViewer: ({ container, highlightTerms, pdfDocument, viewer, viewerApi }: UsePdfViewerOptions) => PdfViewerState;
|
|
102
|
-
interface UsePdfZoomGestureOptions {
|
|
103
|
-
container: MaybeRefOrGetter<HTMLDivElement | undefined>;
|
|
104
|
-
getViewer: () => PDFViewer | undefined;
|
|
105
|
-
}
|
|
106
|
-
export declare const usePdfZoomGesture: ({ container, getViewer }: UsePdfZoomGestureOptions) => void;
|
|
107
|
-
export declare const PDF_MAX_CANVAS_AREA = 16777216;
|
|
108
|
-
export declare const PDF_MIN_SCALE = .1;
|
|
109
|
-
export declare const PDF_MAX_SCALE = 10;
|
|
110
|
-
export declare const PDF_ROTATION_STEP = 90;
|
|
111
|
-
export declare const PDF_FULL_TURN = 360;
|
|
112
|
-
export declare const PDF_PRINT_SCALE = 2;
|
|
113
|
-
export declare const PDF_PRINT_BATCH_SIZE = 10;
|
|
114
|
-
export declare const PDF_PRINT_CLASS = "pdf-print";
|
|
115
|
-
export declare const PDF_MIME_TYPE = "application/pdf";
|
|
116
|
-
export declare const PDF_PRINT_STYLE: string;
|
|
117
|
-
export declare const PDF_WHEEL_ZOOM_DIVISOR = 500;
|
|
118
|
-
export declare const destroyLoadingTask: (task: PDFDocumentLoadingTask) => void;
|
|
119
|
-
interface Props {
|
|
120
|
-
cssWidth: number;
|
|
121
|
-
pageHeight: number;
|
|
122
|
-
pageWidth: number;
|
|
123
|
-
pixelRatio: number;
|
|
124
|
-
}
|
|
125
|
-
export declare const getCanvasScale: ({ cssWidth, pageHeight, pageWidth, pixelRatio }: Props) => number;
|
|
126
|
-
export declare const getSourceParameters: (source: PdfSource) => Promise<{
|
|
127
|
-
data: Uint8Array;
|
|
128
|
-
} | {
|
|
129
|
-
url: string;
|
|
130
|
-
}>;
|
|
131
|
-
export declare const getZoomedScroll: ({ point, ratio, scroll }: {
|
|
132
|
-
point: number;
|
|
133
|
-
ratio: number;
|
|
134
|
-
scroll: number;
|
|
135
|
-
}) => number;
|
|
136
|
-
export declare const loadPdfDocument: (renderer: PdfRenderer, source: PdfSource, parameters: PdfDocumentParameters) => Promise<PDFDocumentLoadingTask>;
|
|
137
|
-
export declare const renderPrintImage: (pdfDocument: PDFDocumentProxy, pageNumber: number) => Promise<HTMLImageElement>;
|
|
138
|
-
export declare const renderPrintSheets: (pdfDocument: PDFDocumentProxy, checkIsCancelled: () => boolean) => Promise<HTMLDivElement | undefined>;
|
|
139
|
-
export {};
|
package/dist/index.js
DELETED
|
@@ -1,654 +0,0 @@
|
|
|
1
|
-
import { downloadFile, getResultAsync, getSynchronizedFunction, noop } from "@esposter/shared";
|
|
2
|
-
import { computed, effectScope, onScopeDispose, ref, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
// src/services/destroyLoadingTask.ts
|
|
4
|
-
const destroyLoadingTask = getSynchronizedFunction(async (task) => {
|
|
5
|
-
await task.destroy();
|
|
6
|
-
});
|
|
7
|
-
// src/services/getSourceParameters.ts
|
|
8
|
-
const getSourceParameters = async (source) => {
|
|
9
|
-
if (typeof source === "string") return { url: source };
|
|
10
|
-
if (source instanceof File) return { data: new Uint8Array(await source.arrayBuffer()) };
|
|
11
|
-
return { data: new Uint8Array(source) };
|
|
12
|
-
};
|
|
13
|
-
// src/services/loadPdfDocument.ts
|
|
14
|
-
const loadPdfDocument = async (renderer, source, parameters) => {
|
|
15
|
-
renderer.api.GlobalWorkerOptions.workerSrc = renderer.workerSrc;
|
|
16
|
-
const sourceParameters = await getSourceParameters(source);
|
|
17
|
-
return renderer.api.getDocument({
|
|
18
|
-
cMapPacked: true,
|
|
19
|
-
cMapUrl: renderer.cMapUrl,
|
|
20
|
-
standardFontDataUrl: renderer.standardFontDataUrl,
|
|
21
|
-
wasmUrl: renderer.wasmUrl,
|
|
22
|
-
...parameters,
|
|
23
|
-
...sourceParameters
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
// src/composables/usePdfDocument.ts
|
|
27
|
-
const EMPTY_PROGRESS = {
|
|
28
|
-
loaded: 0,
|
|
29
|
-
total: 0
|
|
30
|
-
};
|
|
31
|
-
const usePdfDocument = ({ parameters = {}, renderer, source }) => {
|
|
32
|
-
const pdfDocument = shallowRef();
|
|
33
|
-
const progress = ref(EMPTY_PROGRESS);
|
|
34
|
-
const isFailed = ref(false);
|
|
35
|
-
const isPasswordRequested = ref(false);
|
|
36
|
-
const isPasswordWrong = ref(false);
|
|
37
|
-
let loadingTask;
|
|
38
|
-
let updatePassword;
|
|
39
|
-
let loadGeneration = 0;
|
|
40
|
-
const destroyCurrentTask = () => {
|
|
41
|
-
if (loadingTask) destroyLoadingTask(loadingTask);
|
|
42
|
-
loadingTask = void 0;
|
|
43
|
-
};
|
|
44
|
-
const release = () => {
|
|
45
|
-
loadGeneration++;
|
|
46
|
-
destroyCurrentTask();
|
|
47
|
-
pdfDocument.value = void 0;
|
|
48
|
-
progress.value = EMPTY_PROGRESS;
|
|
49
|
-
isFailed.value = false;
|
|
50
|
-
isPasswordRequested.value = false;
|
|
51
|
-
isPasswordWrong.value = false;
|
|
52
|
-
};
|
|
53
|
-
const load = async (currentRenderer, currentSource) => {
|
|
54
|
-
const generation = loadGeneration;
|
|
55
|
-
await getResultAsync(async () => {
|
|
56
|
-
const task = await loadPdfDocument(currentRenderer, currentSource, parameters);
|
|
57
|
-
if (generation !== loadGeneration) {
|
|
58
|
-
destroyLoadingTask(task);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
loadingTask = task;
|
|
62
|
-
task.onProgress = ({ loaded, total }) => {
|
|
63
|
-
if (generation === loadGeneration) progress.value = {
|
|
64
|
-
loaded,
|
|
65
|
-
total
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
task.onPassword = (passwordCallback, reason) => {
|
|
69
|
-
if (generation !== loadGeneration) return;
|
|
70
|
-
updatePassword = passwordCallback;
|
|
71
|
-
isPasswordWrong.value = reason === currentRenderer.api.PasswordResponses.INCORRECT_PASSWORD;
|
|
72
|
-
isPasswordRequested.value = true;
|
|
73
|
-
};
|
|
74
|
-
const loadedDocument = await task.promise;
|
|
75
|
-
if (generation === loadGeneration) pdfDocument.value = loadedDocument;
|
|
76
|
-
}).match(noop, (error) => {
|
|
77
|
-
if (generation !== loadGeneration) return;
|
|
78
|
-
isFailed.value = true;
|
|
79
|
-
destroyCurrentTask();
|
|
80
|
-
console.error(error);
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
const submitPassword = (password) => {
|
|
84
|
-
isPasswordRequested.value = false;
|
|
85
|
-
updatePassword?.(password);
|
|
86
|
-
};
|
|
87
|
-
watch([() => toValue(renderer), () => toValue(source)], getSynchronizedFunction(async ([currentRenderer, currentSource]) => {
|
|
88
|
-
release();
|
|
89
|
-
if (currentRenderer && currentSource) await load(currentRenderer, currentSource);
|
|
90
|
-
}), { immediate: true });
|
|
91
|
-
onScopeDispose(release);
|
|
92
|
-
return {
|
|
93
|
-
isFailed,
|
|
94
|
-
isPasswordRequested,
|
|
95
|
-
isPasswordWrong,
|
|
96
|
-
pdfDocument,
|
|
97
|
-
progress,
|
|
98
|
-
submitPassword
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
// src/services/constants.ts
|
|
102
|
-
const PDF_MAX_CANVAS_AREA = 16777216;
|
|
103
|
-
const PDF_MIN_SCALE = .1;
|
|
104
|
-
const PDF_MAX_SCALE = 10;
|
|
105
|
-
const PDF_ROTATION_STEP = 90;
|
|
106
|
-
const PDF_FULL_TURN = 360;
|
|
107
|
-
const PDF_PRINT_SCALE = 2;
|
|
108
|
-
const PDF_PRINT_BATCH_SIZE = 10;
|
|
109
|
-
const PDF_PRINT_CLASS = "pdf-print";
|
|
110
|
-
const PDF_MIME_TYPE = "application/pdf";
|
|
111
|
-
const PDF_PRINT_STYLE = `@page { margin: 3mm } .${PDF_PRINT_CLASS} { display: none } .${PDF_PRINT_CLASS} img { display: block; page-break-after: always; width: 100% } @media print { .${PDF_PRINT_CLASS} { display: block } body > :not(.${PDF_PRINT_CLASS}) { display: none !important } }`;
|
|
112
|
-
const PDF_WHEEL_ZOOM_DIVISOR = 500;
|
|
113
|
-
// src/services/getCanvasScale.ts
|
|
114
|
-
const getCanvasScale = ({ cssWidth, pageHeight, pageWidth, pixelRatio }) => {
|
|
115
|
-
const scale = cssWidth / pageWidth * pixelRatio;
|
|
116
|
-
if (pageWidth * pageHeight * scale ** 2 <= 16777216) return scale;
|
|
117
|
-
return Math.sqrt(PDF_MAX_CANVAS_AREA / (pageWidth * pageHeight));
|
|
118
|
-
};
|
|
119
|
-
// src/composables/usePdfPage.ts
|
|
120
|
-
const usePdfPage = ({ canvas, isVisible = true, pageNumber, pdfDocument }) => {
|
|
121
|
-
let cssWidth = 0;
|
|
122
|
-
let loadGeneration = 0;
|
|
123
|
-
let page;
|
|
124
|
-
let renderTask;
|
|
125
|
-
const awaitRender = getSynchronizedFunction(async (task) => {
|
|
126
|
-
await getResultAsync(() => task.promise).match(noop, (error) => {
|
|
127
|
-
if (task === renderTask) console.error(error);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
const cancelRender = () => {
|
|
131
|
-
renderTask?.cancel();
|
|
132
|
-
renderTask = void 0;
|
|
133
|
-
};
|
|
134
|
-
const drawPage = () => {
|
|
135
|
-
const currentCanvas = toValue(canvas);
|
|
136
|
-
if (!page || !currentCanvas || cssWidth === 0 || !toValue(isVisible)) return;
|
|
137
|
-
cancelRender();
|
|
138
|
-
const { height, width } = page.getViewport({ scale: 1 });
|
|
139
|
-
const viewport = page.getViewport({ scale: getCanvasScale({
|
|
140
|
-
cssWidth,
|
|
141
|
-
pageHeight: height,
|
|
142
|
-
pageWidth: width,
|
|
143
|
-
pixelRatio: window.devicePixelRatio
|
|
144
|
-
}) });
|
|
145
|
-
currentCanvas.width = viewport.width;
|
|
146
|
-
currentCanvas.height = viewport.height;
|
|
147
|
-
const task = page.render({
|
|
148
|
-
canvas: currentCanvas,
|
|
149
|
-
viewport
|
|
150
|
-
});
|
|
151
|
-
renderTask = task;
|
|
152
|
-
awaitRender(task);
|
|
153
|
-
};
|
|
154
|
-
watch([() => toValue(pdfDocument), () => toValue(pageNumber)], getSynchronizedFunction(async ([currentDocument, currentPageNumber]) => {
|
|
155
|
-
const generation = ++loadGeneration;
|
|
156
|
-
cancelRender();
|
|
157
|
-
page = void 0;
|
|
158
|
-
if (!currentDocument) return;
|
|
159
|
-
await getResultAsync(async () => {
|
|
160
|
-
const loadedPage = await currentDocument.getPage(currentPageNumber);
|
|
161
|
-
if (generation !== loadGeneration) return;
|
|
162
|
-
page = loadedPage;
|
|
163
|
-
drawPage();
|
|
164
|
-
}).match(noop, (error) => {
|
|
165
|
-
if (generation === loadGeneration) console.error(error);
|
|
166
|
-
});
|
|
167
|
-
}), { immediate: true });
|
|
168
|
-
watch(() => toValue(canvas), (currentCanvas, _previousCanvas, onCleanup) => {
|
|
169
|
-
if (!currentCanvas) {
|
|
170
|
-
cancelRender();
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
cssWidth = 0;
|
|
174
|
-
const observer = new ResizeObserver((entries) => {
|
|
175
|
-
const width = entries[0]?.contentRect.width ?? 0;
|
|
176
|
-
if (width === cssWidth) return;
|
|
177
|
-
cssWidth = width;
|
|
178
|
-
drawPage();
|
|
179
|
-
});
|
|
180
|
-
observer.observe(currentCanvas);
|
|
181
|
-
onCleanup(() => {
|
|
182
|
-
observer.disconnect();
|
|
183
|
-
});
|
|
184
|
-
}, { immediate: true });
|
|
185
|
-
watch(() => toValue(isVisible), (visible) => {
|
|
186
|
-
if (visible) drawPage();
|
|
187
|
-
});
|
|
188
|
-
onScopeDispose(() => {
|
|
189
|
-
loadGeneration++;
|
|
190
|
-
cancelRender();
|
|
191
|
-
});
|
|
192
|
-
};
|
|
193
|
-
// src/composables/usePdfThumbnails.ts
|
|
194
|
-
const usePdfThumbnails = ({ currentPageNumber, pdfDocument, root }) => {
|
|
195
|
-
const thumbnails = shallowRef([]);
|
|
196
|
-
const rows = /* @__PURE__ */ new Map();
|
|
197
|
-
let observer;
|
|
198
|
-
let scope;
|
|
199
|
-
const createThumbnail = (pageNumber, currentDocument, currentObserver) => {
|
|
200
|
-
const canvas = shallowRef();
|
|
201
|
-
const isVisible = ref(false);
|
|
202
|
-
const thumbnail = {
|
|
203
|
-
canvas,
|
|
204
|
-
isCurrent: computed(() => toValue(currentPageNumber) === pageNumber),
|
|
205
|
-
isVisible,
|
|
206
|
-
pageNumber
|
|
207
|
-
};
|
|
208
|
-
usePdfPage({
|
|
209
|
-
canvas: () => canvas.value,
|
|
210
|
-
isVisible: () => isVisible.value,
|
|
211
|
-
pageNumber,
|
|
212
|
-
pdfDocument: currentDocument
|
|
213
|
-
});
|
|
214
|
-
watch(canvas, (element, _previousElement, onCleanup) => {
|
|
215
|
-
if (!element) return;
|
|
216
|
-
rows.set(element, thumbnail);
|
|
217
|
-
currentObserver.observe(element);
|
|
218
|
-
onCleanup(() => {
|
|
219
|
-
currentObserver.unobserve(element);
|
|
220
|
-
rows.delete(element);
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
return thumbnail;
|
|
224
|
-
};
|
|
225
|
-
const disposeThumbnails = () => {
|
|
226
|
-
scope?.stop();
|
|
227
|
-
observer?.disconnect();
|
|
228
|
-
};
|
|
229
|
-
watch(() => toValue(pdfDocument), (loaded) => {
|
|
230
|
-
disposeThumbnails();
|
|
231
|
-
rows.clear();
|
|
232
|
-
thumbnails.value = [];
|
|
233
|
-
if (!loaded) return;
|
|
234
|
-
const currentObserver = new IntersectionObserver((entries) => {
|
|
235
|
-
for (const entry of entries) {
|
|
236
|
-
const row = rows.get(entry.target);
|
|
237
|
-
if (row) row.isVisible.value = entry.isIntersecting;
|
|
238
|
-
}
|
|
239
|
-
}, { root: toValue(root) ?? null });
|
|
240
|
-
observer = currentObserver;
|
|
241
|
-
scope = effectScope();
|
|
242
|
-
thumbnails.value = scope.run(() => Array.from({ length: loaded.numPages }, (_value, index) => createThumbnail(index + 1, loaded, currentObserver))) ?? [];
|
|
243
|
-
}, { immediate: true });
|
|
244
|
-
onScopeDispose(disposeThumbnails);
|
|
245
|
-
return thumbnails;
|
|
246
|
-
};
|
|
247
|
-
// src/services/getZoomedScroll.ts
|
|
248
|
-
const getZoomedScroll = ({ point, ratio, scroll }) => (scroll + point) * ratio - point;
|
|
249
|
-
// src/composables/usePdfZoomGesture.ts
|
|
250
|
-
const usePdfZoomGesture = ({ container, getViewer }) => {
|
|
251
|
-
const abortController = new AbortController();
|
|
252
|
-
const pointers = /* @__PURE__ */ new Map();
|
|
253
|
-
let pinchDistance = 0;
|
|
254
|
-
const measurePinch = () => {
|
|
255
|
-
const [first, second] = [...pointers.values()];
|
|
256
|
-
if (pointers.size !== 2 || !first || !second) return void 0;
|
|
257
|
-
return {
|
|
258
|
-
distance: Math.hypot(second.x - first.x, second.y - first.y),
|
|
259
|
-
point: {
|
|
260
|
-
x: (first.x + second.x) / 2,
|
|
261
|
-
y: (first.y + second.y) / 2
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
};
|
|
265
|
-
const measurePinchDistance = () => measurePinch()?.distance ?? 0;
|
|
266
|
-
const zoomAbout = (ratio, point) => {
|
|
267
|
-
const viewer = getViewer();
|
|
268
|
-
const element = toValue(container);
|
|
269
|
-
if (!viewer || !element) return;
|
|
270
|
-
const { currentScale } = viewer;
|
|
271
|
-
const nextScale = Math.min(Math.max(currentScale * ratio, PDF_MIN_SCALE), 10);
|
|
272
|
-
const scaleRatio = nextScale / currentScale;
|
|
273
|
-
const { left, top } = element.getBoundingClientRect();
|
|
274
|
-
const { scrollLeft, scrollTop } = element;
|
|
275
|
-
viewer.currentScale = nextScale;
|
|
276
|
-
element.scrollLeft = getZoomedScroll({
|
|
277
|
-
point: point.x - left,
|
|
278
|
-
ratio: scaleRatio,
|
|
279
|
-
scroll: scrollLeft
|
|
280
|
-
});
|
|
281
|
-
element.scrollTop = getZoomedScroll({
|
|
282
|
-
point: point.y - top,
|
|
283
|
-
ratio: scaleRatio,
|
|
284
|
-
scroll: scrollTop
|
|
285
|
-
});
|
|
286
|
-
};
|
|
287
|
-
const onPointerDown = (event) => {
|
|
288
|
-
pointers.set(event.pointerId, {
|
|
289
|
-
x: event.clientX,
|
|
290
|
-
y: event.clientY
|
|
291
|
-
});
|
|
292
|
-
pinchDistance = measurePinchDistance();
|
|
293
|
-
};
|
|
294
|
-
const onPointerMove = (event) => {
|
|
295
|
-
if (!pointers.has(event.pointerId)) return;
|
|
296
|
-
pointers.set(event.pointerId, {
|
|
297
|
-
x: event.clientX,
|
|
298
|
-
y: event.clientY
|
|
299
|
-
});
|
|
300
|
-
const pinch = measurePinch();
|
|
301
|
-
if (pinch && pinchDistance > 0) zoomAbout(pinch.distance / pinchDistance, pinch.point);
|
|
302
|
-
pinchDistance = pinch?.distance ?? 0;
|
|
303
|
-
};
|
|
304
|
-
const onPointerEnd = (event) => {
|
|
305
|
-
pointers.delete(event.pointerId);
|
|
306
|
-
pinchDistance = measurePinchDistance();
|
|
307
|
-
};
|
|
308
|
-
const onWheel = (event) => {
|
|
309
|
-
if (!event.ctrlKey) return;
|
|
310
|
-
event.preventDefault();
|
|
311
|
-
zoomAbout(Math.exp(-event.deltaY / 500), {
|
|
312
|
-
x: event.clientX,
|
|
313
|
-
y: event.clientY
|
|
314
|
-
});
|
|
315
|
-
};
|
|
316
|
-
watch(() => toValue(container), (element) => {
|
|
317
|
-
if (!element) return;
|
|
318
|
-
const { signal } = abortController;
|
|
319
|
-
element.addEventListener("pointerdown", (event) => {
|
|
320
|
-
onPointerDown(event);
|
|
321
|
-
}, { signal });
|
|
322
|
-
element.addEventListener("pointermove", (event) => {
|
|
323
|
-
onPointerMove(event);
|
|
324
|
-
}, { signal });
|
|
325
|
-
element.addEventListener("pointerup", (event) => {
|
|
326
|
-
onPointerEnd(event);
|
|
327
|
-
}, { signal });
|
|
328
|
-
element.addEventListener("pointercancel", (event) => {
|
|
329
|
-
onPointerEnd(event);
|
|
330
|
-
}, { signal });
|
|
331
|
-
element.addEventListener("pointerleave", (event) => {
|
|
332
|
-
onPointerEnd(event);
|
|
333
|
-
}, { signal });
|
|
334
|
-
element.addEventListener("wheel", (event) => {
|
|
335
|
-
onWheel(event);
|
|
336
|
-
}, {
|
|
337
|
-
passive: false,
|
|
338
|
-
signal
|
|
339
|
-
});
|
|
340
|
-
}, { immediate: true });
|
|
341
|
-
onScopeDispose(() => {
|
|
342
|
-
abortController.abort();
|
|
343
|
-
});
|
|
344
|
-
};
|
|
345
|
-
// src/services/renderPrintImage.ts
|
|
346
|
-
const renderPrintImage = async (pdfDocument, pageNumber) => {
|
|
347
|
-
const page = await pdfDocument.getPage(pageNumber);
|
|
348
|
-
const { height, width } = page.getViewport({ scale: 1 });
|
|
349
|
-
const printScale = getCanvasScale({
|
|
350
|
-
cssWidth: width,
|
|
351
|
-
pageHeight: height,
|
|
352
|
-
pageWidth: width,
|
|
353
|
-
pixelRatio: 2
|
|
354
|
-
});
|
|
355
|
-
const viewport = page.getViewport({ scale: printScale });
|
|
356
|
-
const canvas = window.document.createElement("canvas");
|
|
357
|
-
canvas.width = viewport.width;
|
|
358
|
-
canvas.height = viewport.height;
|
|
359
|
-
await page.render({
|
|
360
|
-
canvas,
|
|
361
|
-
viewport
|
|
362
|
-
}).promise;
|
|
363
|
-
const image = window.document.createElement("img");
|
|
364
|
-
image.src = canvas.toDataURL("image/png");
|
|
365
|
-
return image;
|
|
366
|
-
};
|
|
367
|
-
// src/services/renderPrintSheets.ts
|
|
368
|
-
const renderPrintSheets = async (pdfDocument, checkIsCancelled) => {
|
|
369
|
-
const style = window.document.createElement("style");
|
|
370
|
-
style.textContent = PDF_PRINT_STYLE;
|
|
371
|
-
const printRoot = window.document.createElement("div");
|
|
372
|
-
printRoot.className = PDF_PRINT_CLASS;
|
|
373
|
-
printRoot.append(style);
|
|
374
|
-
const renderBatch = async (firstPageNumber) => {
|
|
375
|
-
if (checkIsCancelled() || firstPageNumber > pdfDocument.numPages) return;
|
|
376
|
-
const lastPageNumber = Math.min(firstPageNumber + 10 - 1, pdfDocument.numPages);
|
|
377
|
-
const pageNumbers = Array.from({ length: lastPageNumber - firstPageNumber + 1 }, (_value, index) => firstPageNumber + index);
|
|
378
|
-
printRoot.append(...await Promise.all(pageNumbers.map((pageNumber) => renderPrintImage(pdfDocument, pageNumber))));
|
|
379
|
-
await renderBatch(lastPageNumber + 1);
|
|
380
|
-
};
|
|
381
|
-
await renderBatch(1);
|
|
382
|
-
return checkIsCancelled() ? void 0 : printRoot;
|
|
383
|
-
};
|
|
384
|
-
// src/composables/usePdfViewer.ts
|
|
385
|
-
const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, viewerApi }) => {
|
|
386
|
-
const currentPageNumber = ref(0);
|
|
387
|
-
const isFullscreen = ref(false);
|
|
388
|
-
const isMatchCase = ref(false);
|
|
389
|
-
const isNotFound = ref(false);
|
|
390
|
-
const isWholeWord = ref(false);
|
|
391
|
-
const matchesCount = ref({
|
|
392
|
-
current: 0,
|
|
393
|
-
total: 0
|
|
394
|
-
});
|
|
395
|
-
const outline = shallowRef([]);
|
|
396
|
-
const overlays = shallowRef([]);
|
|
397
|
-
const pagesCount = ref(0);
|
|
398
|
-
const pagesRotation = ref(0);
|
|
399
|
-
const scale = ref(0);
|
|
400
|
-
const searchQuery = ref("");
|
|
401
|
-
const isZoomInDisabled = computed(() => scale.value >= 10);
|
|
402
|
-
let abortController;
|
|
403
|
-
let containerElement;
|
|
404
|
-
let eventBus;
|
|
405
|
-
let linkService;
|
|
406
|
-
let pdfViewer;
|
|
407
|
-
let resizeObserver;
|
|
408
|
-
let printRoot;
|
|
409
|
-
let printGeneration = 0;
|
|
410
|
-
const onFullscreenChange = () => {
|
|
411
|
-
isFullscreen.value = window.document.fullscreenElement === containerElement;
|
|
412
|
-
};
|
|
413
|
-
const createViewer = (currentViewerApi, containerValue, viewerElement) => {
|
|
414
|
-
const { EventBus, FindState, LinkTarget, PDFFindController, PDFLinkService, PDFViewer } = currentViewerApi;
|
|
415
|
-
const bus = new EventBus();
|
|
416
|
-
const links = new PDFLinkService({
|
|
417
|
-
eventBus: bus,
|
|
418
|
-
externalLinkTarget: LinkTarget.BLANK
|
|
419
|
-
});
|
|
420
|
-
const controller = new PDFFindController({
|
|
421
|
-
eventBus: bus,
|
|
422
|
-
linkService: links
|
|
423
|
-
});
|
|
424
|
-
const viewerAbortController = new AbortController();
|
|
425
|
-
const { signal } = viewerAbortController;
|
|
426
|
-
const instance = new PDFViewer({
|
|
427
|
-
abortSignal: signal,
|
|
428
|
-
container: containerValue,
|
|
429
|
-
eventBus: bus,
|
|
430
|
-
findController: controller,
|
|
431
|
-
linkService: links,
|
|
432
|
-
maxCanvasPixels: PDF_MAX_CANVAS_AREA,
|
|
433
|
-
viewer: viewerElement
|
|
434
|
-
});
|
|
435
|
-
links.setViewer(instance);
|
|
436
|
-
abortController = viewerAbortController;
|
|
437
|
-
containerElement = containerValue;
|
|
438
|
-
eventBus = bus;
|
|
439
|
-
linkService = links;
|
|
440
|
-
pdfViewer = instance;
|
|
441
|
-
bus.on("pagesinit", () => {
|
|
442
|
-
instance.currentScaleValue = "auto";
|
|
443
|
-
});
|
|
444
|
-
bus.on("pagechanging", (event) => {
|
|
445
|
-
currentPageNumber.value = event.pageNumber;
|
|
446
|
-
});
|
|
447
|
-
bus.on("pagerendered", (event) => {
|
|
448
|
-
const overlay = {
|
|
449
|
-
element: event.source.div,
|
|
450
|
-
pageNumber: event.pageNumber,
|
|
451
|
-
viewport: event.source.viewport
|
|
452
|
-
};
|
|
453
|
-
overlays.value = [...overlays.value.filter(({ pageNumber }) => pageNumber !== event.pageNumber), overlay];
|
|
454
|
-
});
|
|
455
|
-
bus.on("scalechanging", (event) => {
|
|
456
|
-
scale.value = event.scale;
|
|
457
|
-
});
|
|
458
|
-
bus.on("rotationchanging", (event) => {
|
|
459
|
-
pagesRotation.value = event.pagesRotation;
|
|
460
|
-
});
|
|
461
|
-
bus.on("updatefindcontrolstate", (event) => {
|
|
462
|
-
isNotFound.value = event.state === FindState.NOT_FOUND;
|
|
463
|
-
matchesCount.value = event.matchesCount;
|
|
464
|
-
});
|
|
465
|
-
bus.on("updatefindmatchescount", (event) => {
|
|
466
|
-
matchesCount.value = event.matchesCount;
|
|
467
|
-
});
|
|
468
|
-
resizeObserver = new ResizeObserver(() => {
|
|
469
|
-
if (!pdfViewer) return;
|
|
470
|
-
const { currentScaleValue } = pdfViewer;
|
|
471
|
-
if (currentScaleValue) pdfViewer.currentScaleValue = currentScaleValue;
|
|
472
|
-
});
|
|
473
|
-
resizeObserver.observe(containerValue);
|
|
474
|
-
window.document.addEventListener("fullscreenchange", () => {
|
|
475
|
-
onFullscreenChange();
|
|
476
|
-
}, { signal });
|
|
477
|
-
window.addEventListener("afterprint", () => {
|
|
478
|
-
removePrint();
|
|
479
|
-
}, { signal });
|
|
480
|
-
applyDocument(toValue(pdfDocument));
|
|
481
|
-
};
|
|
482
|
-
const loadOutline = getSynchronizedFunction(async (loaded) => {
|
|
483
|
-
await getResultAsync(async () => {
|
|
484
|
-
const items = await loaded.getOutline();
|
|
485
|
-
if (loaded === toValue(pdfDocument)) outline.value = items ?? [];
|
|
486
|
-
}).match(noop, console.error);
|
|
487
|
-
});
|
|
488
|
-
const applyDocument = (loaded) => {
|
|
489
|
-
if (!pdfViewer || !linkService) return;
|
|
490
|
-
pagesCount.value = loaded?.numPages ?? 0;
|
|
491
|
-
overlays.value = [];
|
|
492
|
-
outline.value = [];
|
|
493
|
-
pdfViewer.setDocument(loaded ?? null);
|
|
494
|
-
linkService.setDocument(loaded ?? null);
|
|
495
|
-
currentPageNumber.value = 1;
|
|
496
|
-
pagesRotation.value = 0;
|
|
497
|
-
matchesCount.value = {
|
|
498
|
-
current: 0,
|
|
499
|
-
total: 0
|
|
500
|
-
};
|
|
501
|
-
isNotFound.value = false;
|
|
502
|
-
if (!loaded) return;
|
|
503
|
-
loadOutline(loaded);
|
|
504
|
-
const terms = toValue(highlightTerms);
|
|
505
|
-
if (terms.length > 0) findText({ query: terms });
|
|
506
|
-
};
|
|
507
|
-
const findText = ({ isPrevious = false, query, type = "" }) => {
|
|
508
|
-
eventBus?.dispatch("find", {
|
|
509
|
-
caseSensitive: isMatchCase.value,
|
|
510
|
-
entireWord: isWholeWord.value,
|
|
511
|
-
findPrevious: isPrevious,
|
|
512
|
-
highlightAll: true,
|
|
513
|
-
matchDiacritics: false,
|
|
514
|
-
query,
|
|
515
|
-
type
|
|
516
|
-
});
|
|
517
|
-
};
|
|
518
|
-
const removePrint = () => {
|
|
519
|
-
printGeneration++;
|
|
520
|
-
printRoot?.remove();
|
|
521
|
-
printRoot = void 0;
|
|
522
|
-
};
|
|
523
|
-
const followBookmark = (item) => {
|
|
524
|
-
if (item.dest) linkService?.goToDestination(item.dest);
|
|
525
|
-
};
|
|
526
|
-
const goToPage = (pageNumber) => {
|
|
527
|
-
if (pdfViewer && Number.isInteger(pageNumber) && pageNumber >= 1 && pageNumber <= pagesCount.value) pdfViewer.currentPageNumber = pageNumber;
|
|
528
|
-
};
|
|
529
|
-
const previousPage = () => {
|
|
530
|
-
pdfViewer?.previousPage();
|
|
531
|
-
};
|
|
532
|
-
const nextPage = () => {
|
|
533
|
-
pdfViewer?.nextPage();
|
|
534
|
-
};
|
|
535
|
-
const zoomIn = () => {
|
|
536
|
-
pdfViewer?.increaseScale();
|
|
537
|
-
};
|
|
538
|
-
const zoomOut = () => {
|
|
539
|
-
pdfViewer?.decreaseScale();
|
|
540
|
-
};
|
|
541
|
-
const fitWidth = () => {
|
|
542
|
-
if (pdfViewer) pdfViewer.currentScaleValue = "page-width";
|
|
543
|
-
};
|
|
544
|
-
const fitPage = () => {
|
|
545
|
-
if (pdfViewer) pdfViewer.currentScaleValue = "page-fit";
|
|
546
|
-
};
|
|
547
|
-
const actualSize = () => {
|
|
548
|
-
if (pdfViewer) pdfViewer.currentScaleValue = "page-actual";
|
|
549
|
-
};
|
|
550
|
-
const rotate = () => {
|
|
551
|
-
if (pdfViewer) pdfViewer.pagesRotation = (pdfViewer.pagesRotation + 90) % 360;
|
|
552
|
-
};
|
|
553
|
-
const findNext = () => {
|
|
554
|
-
findText({
|
|
555
|
-
query: searchQuery.value,
|
|
556
|
-
type: "again"
|
|
557
|
-
});
|
|
558
|
-
};
|
|
559
|
-
const findPrevious = () => {
|
|
560
|
-
findText({
|
|
561
|
-
isPrevious: true,
|
|
562
|
-
query: searchQuery.value,
|
|
563
|
-
type: "again"
|
|
564
|
-
});
|
|
565
|
-
};
|
|
566
|
-
const toggleFullscreen = getSynchronizedFunction(async () => {
|
|
567
|
-
const element = containerElement;
|
|
568
|
-
if (!element) return;
|
|
569
|
-
await getResultAsync(async () => {
|
|
570
|
-
if (window.document.fullscreenElement) await window.document.exitFullscreen();
|
|
571
|
-
else await element.requestFullscreen();
|
|
572
|
-
}).match(noop, console.error);
|
|
573
|
-
});
|
|
574
|
-
const download = getSynchronizedFunction(async (filename) => {
|
|
575
|
-
const downloaded = toValue(pdfDocument);
|
|
576
|
-
if (!downloaded) return;
|
|
577
|
-
await getResultAsync(async () => {
|
|
578
|
-
downloadFile(filename, new Uint8Array(await downloaded.getData()), PDF_MIME_TYPE);
|
|
579
|
-
}).match(noop, console.error);
|
|
580
|
-
});
|
|
581
|
-
const print = getSynchronizedFunction(async () => {
|
|
582
|
-
const printed = toValue(pdfDocument);
|
|
583
|
-
if (!printed) return;
|
|
584
|
-
removePrint();
|
|
585
|
-
const generation = printGeneration;
|
|
586
|
-
await getResultAsync(async () => {
|
|
587
|
-
const sheets = await renderPrintSheets(printed, () => generation !== printGeneration);
|
|
588
|
-
if (!sheets) return;
|
|
589
|
-
window.document.body.append(sheets);
|
|
590
|
-
printRoot = sheets;
|
|
591
|
-
window.print();
|
|
592
|
-
}).match(noop, console.error);
|
|
593
|
-
});
|
|
594
|
-
usePdfZoomGesture({
|
|
595
|
-
container,
|
|
596
|
-
getViewer: () => pdfViewer
|
|
597
|
-
});
|
|
598
|
-
watch([
|
|
599
|
-
() => toValue(viewerApi),
|
|
600
|
-
() => toValue(container),
|
|
601
|
-
() => toValue(viewer)
|
|
602
|
-
], ([currentViewerApi, containerElementValue, viewerElement]) => {
|
|
603
|
-
if (pdfViewer || !currentViewerApi || !containerElementValue || !viewerElement) return;
|
|
604
|
-
createViewer(currentViewerApi, containerElementValue, viewerElement);
|
|
605
|
-
}, { immediate: true });
|
|
606
|
-
watch(() => toValue(pdfDocument), (loaded) => {
|
|
607
|
-
applyDocument(loaded);
|
|
608
|
-
});
|
|
609
|
-
watch([
|
|
610
|
-
searchQuery,
|
|
611
|
-
isMatchCase,
|
|
612
|
-
isWholeWord
|
|
613
|
-
], () => {
|
|
614
|
-
findText({ query: searchQuery.value });
|
|
615
|
-
});
|
|
616
|
-
onScopeDispose(() => {
|
|
617
|
-
removePrint();
|
|
618
|
-
if (!pdfViewer) return;
|
|
619
|
-
pdfViewer.setDocument(null);
|
|
620
|
-
abortController?.abort();
|
|
621
|
-
resizeObserver?.disconnect();
|
|
622
|
-
});
|
|
623
|
-
return {
|
|
624
|
-
actualSize,
|
|
625
|
-
currentPageNumber,
|
|
626
|
-
download,
|
|
627
|
-
findNext,
|
|
628
|
-
findPrevious,
|
|
629
|
-
fitPage,
|
|
630
|
-
fitWidth,
|
|
631
|
-
followBookmark,
|
|
632
|
-
goToPage,
|
|
633
|
-
isFullscreen,
|
|
634
|
-
isMatchCase,
|
|
635
|
-
isNotFound,
|
|
636
|
-
isWholeWord,
|
|
637
|
-
isZoomInDisabled,
|
|
638
|
-
matchesCount,
|
|
639
|
-
nextPage,
|
|
640
|
-
outline,
|
|
641
|
-
overlays,
|
|
642
|
-
pagesCount,
|
|
643
|
-
pagesRotation,
|
|
644
|
-
previousPage,
|
|
645
|
-
print,
|
|
646
|
-
rotate,
|
|
647
|
-
scale,
|
|
648
|
-
searchQuery,
|
|
649
|
-
toggleFullscreen,
|
|
650
|
-
zoomIn,
|
|
651
|
-
zoomOut
|
|
652
|
-
};
|
|
653
|
-
};
|
|
654
|
-
export { PDF_FULL_TURN, PDF_MAX_CANVAS_AREA, PDF_MAX_SCALE, PDF_MIME_TYPE, PDF_MIN_SCALE, PDF_PRINT_BATCH_SIZE, PDF_PRINT_CLASS, PDF_PRINT_SCALE, PDF_PRINT_STYLE, PDF_ROTATION_STEP, PDF_WHEEL_ZOOM_DIVISOR, destroyLoadingTask, getCanvasScale, getSourceParameters, getZoomedScroll, loadPdfDocument, renderPrintImage, renderPrintSheets, usePdfDocument, usePdfPage, usePdfThumbnails, usePdfViewer, usePdfZoomGesture };
|