first commit

This commit is contained in:
Warunee Tamkoo 2023-09-06 14:51:44 +07:00
commit eb2f504652
32490 changed files with 5731109 additions and 0 deletions

21
node_modules/@tato30/vue-pdf/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 20222023 Aldo Hernandez
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

125
node_modules/@tato30/vue-pdf/README.md generated vendored Normal file
View file

@ -0,0 +1,125 @@
<div align="center">
<img width=250 src="./docs/.vuepress/public/logo.png" />
<h1>VuePDF</h1>
</div>
<p>
<a href="https://www.npmjs.com/package/@tato30/vue-pdf" target="_blank">
<img src="https://img.shields.io/npm/v/@tato30/vue-pdf?style=flat-square" />
</a>
<a href="https://www.npmjs.com/package/@tato30/vue-pdf" target="_blank" >
<img src="https://img.shields.io/npm/dw/@tato30/vue-pdf?style=flat-square" />
</a>
<a href="./LICENSE">
<img src="https://img.shields.io/npm/l/@tato30/vue-pdf?style=flat-square" />
</a>
</p>
<div align="center">
<h2><a href="https://tato30.github.io/VuePDF/">📖Documentation</a></h2>
</div>
## Introduction
VuePDF is a **Vue 3** component for pdf.js that allows you to flexibly display PDF pages within your project.
## Installation
```console
npm i @tato30/vue-pdf
```
```console
yarn add @tato30/vue-pdf
```
## Basic Usage
```vue
<script setup>
import { VuePDF, usePDF } from '@tato30/vue-pdf'
const { pdf, pages, info } = usePDF('document.pdf')
console.log(`Document has ${pages} pages`)
console.log(`Document info: ${info}`)
</script>
<template>
<VuePDF :pdf="pdf" />
</template>
```
## Reference
* [Props](./docs/guide/props.md)
* [Events](./docs/guide/events.md)
* [Methods](./docs/guide/methods.md)
* [Slots](./docs/guide/slots.md)
## Working With Layers
### Text and Annotations
This component supports text-selection and annotation-interaction by enabling them with `text-layer` and `annotation-layer` props respectively, but for this layers renders correctly is necessary setting `css` styles, it can be done by importing default styles from `@tato30/vue-pdf/style.css`.
```vue
<script setup>
import { VuePDF, usePDF } from '@tato30/vue-pdf'
import '@tato30/vue-pdf/style.css'
const { pdf } = usePDF('sample.pdf')
</script>
<template>
<VuePDF :pdf="pdf" text-layer annotation-layer />
</template>
```
You can also create your own custom styles and set them in your project, use this examples as guide:
- [text-layer styles](https://github.com/mozilla/pdf.js/blob/master/web/text_layer_builder.css)
- [annotation-layer styles](https://github.com/mozilla/pdf.js/blob/master/web/annotation_layer_builder.css)
### XFA Forms <badge type="tip" text="v1.7" vertical="middle" />
XFA forms also can be supported by enabling them from `usePDF`.
```vue
<script setup>
import { VuePDF, usePDF } from '@tato30/vue-pdf'
import '@tato30/vue-pdf/style.css'
const { pdf } = usePDF({
url: '/example_xfa.pdf',
enableXfa: true,
})
</script>
<template>
<VuePDF :pdf="pdf" />
</template>
```
## Server-Side Rendering
`VuePDF` is a client-side library, so if you are working with SSR frameworks like `nuxt`, surely will throw error during building stage, if that the case, you could wrap library in some "client only" directive or component, also `usePDF` should be wrapped.
## Contributing
Any idea, suggestion or contribution to the code or documentation are very welcome.
```sh
# Clone the repository
git clone https://github.com/TaTo30/VuePDF.git
# Change to code folder
cd VuePDF
# Install node_modules
npm install
# Run code with hot reload
npm run dev
```

611
node_modules/@tato30/vue-pdf/dist/index.mjs generated vendored Normal file

File diff suppressed because one or more lines are too long

1
node_modules/@tato30/vue-pdf/dist/index.umd.js generated vendored Normal file

File diff suppressed because one or more lines are too long

1
node_modules/@tato30/vue-pdf/dist/style.css generated vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,76 @@
import 'pdfjs-dist/web/pdf_viewer.css';
import type { AnnotationEventPayload } from './types';
declare function reload(): void;
declare function cancel(): void;
declare function getAnnotationStorage(): import("pdfjs-dist/types/src/display/annotation_storage").AnnotationStorage | undefined;
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
pdf?: import("pdfjs-dist/types/src/display/api").PDFDocumentLoadingTask | undefined;
page?: number | undefined;
scale?: number | undefined;
rotation?: number | undefined;
fitParent?: boolean | undefined;
textLayer?: boolean | undefined;
imageResourcesPath?: string | undefined;
hideForms?: boolean | undefined;
annotationLayer?: boolean | undefined;
annotationsFilter?: string[] | undefined;
annotationsMap?: object | undefined;
watermarkText?: string | undefined;
}>, {
page: number;
scale: number;
}>, {
reload: typeof reload;
cancel: typeof cancel;
getAnnotationStorage: typeof getAnnotationStorage;
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
annotation: (payload: AnnotationEventPayload) => void;
loaded: (payload: import("pdfjs-dist/types/src/display/display_utils").PageViewport) => void;
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
pdf?: import("pdfjs-dist/types/src/display/api").PDFDocumentLoadingTask | undefined;
page?: number | undefined;
scale?: number | undefined;
rotation?: number | undefined;
fitParent?: boolean | undefined;
textLayer?: boolean | undefined;
imageResourcesPath?: string | undefined;
hideForms?: boolean | undefined;
annotationLayer?: boolean | undefined;
annotationsFilter?: string[] | undefined;
annotationsMap?: object | undefined;
watermarkText?: string | undefined;
}>, {
page: number;
scale: number;
}>>> & {
onAnnotation?: ((payload: AnnotationEventPayload) => any) | undefined;
onLoaded?: ((payload: import("pdfjs-dist/types/src/display/display_utils").PageViewport) => any) | undefined;
}, {
scale: number;
page: number;
}, {}>, {
default?(_: {}): any;
}>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToRuntimeProps<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};
type __VLS_WithDefaults<P, D> = {
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
default: D[K];
}> : P[K];
};
type __VLS_WithTemplateSlots<T, S> = T & {
new (): {
$slots: S;
};
};
type __VLS_Prettify<T> = {
[K in keyof T]: T[K];
} & {};

View file

@ -0,0 +1,3 @@
export * from './types';
export * from './usePDF';
export { default as VuePDF } from './VuePDF.vue';

View file

@ -0,0 +1,34 @@
import type { AnnotationEventPayload } from '../types';
declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api").PDFPageProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils").PageViewport | undefined;
document?: import("pdfjs-dist/types/src/display/api").PDFDocumentProxy | undefined;
filter?: string[] | undefined;
map?: object | undefined;
imageResourcesPath?: string | undefined;
hideForms?: boolean | undefined;
enableScripting?: boolean | undefined;
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
annotation: (payload: AnnotationEventPayload) => void;
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api").PDFPageProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils").PageViewport | undefined;
document?: import("pdfjs-dist/types/src/display/api").PDFDocumentProxy | undefined;
filter?: string[] | undefined;
map?: object | undefined;
imageResourcesPath?: string | undefined;
hideForms?: boolean | undefined;
enableScripting?: boolean | undefined;
}>>> & {
onAnnotation?: ((payload: AnnotationEventPayload) => any) | undefined;
}, {}, {}>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToRuntimeProps<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};

View file

@ -0,0 +1,17 @@
declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api.js").PDFPageProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils.js").PageViewport | undefined;
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api.js").PDFPageProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils.js").PageViewport | undefined;
}>>>, {}, {}>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToRuntimeProps<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};

View file

@ -0,0 +1,19 @@
declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api").PDFPageProxy | undefined;
document?: import("pdfjs-dist/types/src/display/api").PDFDocumentProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils").PageViewport | undefined;
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
page?: import("pdfjs-dist/types/src/display/api").PDFPageProxy | undefined;
document?: import("pdfjs-dist/types/src/display/api").PDFDocumentProxy | undefined;
viewport?: import("pdfjs-dist/types/src/display/display_utils").PageViewport | undefined;
}>>>, {}, {}>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToRuntimeProps<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};

View file

@ -0,0 +1,27 @@
import type { PageViewport } from 'pdfjs-dist';
import type { OnProgressParameters } from 'pdfjs-dist/types/src/display/api';
import type { Metadata } from 'pdfjs-dist/types/src/display/metadata';
export type LoadedEventPayload = PageViewport;
export interface AnnotationEventPayload {
type: string;
data: any;
}
export type OnProgressCallback = (progressData: OnProgressParameters) => void;
export type UpdatePasswordFn = (newPassword: string) => void;
export type OnPasswordCallback = (updatePassword: UpdatePasswordFn, reason: any) => void;
export type OnErrorCallback = (error: any) => void;
export interface UsePDFOptions {
onProgress?: OnProgressCallback;
onPassword?: OnPasswordCallback;
onError?: OnErrorCallback;
password?: string;
}
export interface UsePDFInfoMetadata {
info: Object;
metadata: Metadata;
}
export interface UsePDFInfo {
metadata: UsePDFInfoMetadata;
attachments: Record<string, unknown>;
javascript: string[] | null;
}

View file

@ -0,0 +1,25 @@
import type { DocumentInitParameters, PDFDataRangeTransport, TypedArray } from 'pdfjs-dist/types/src/display/api';
import type { UsePDFInfo, UsePDFOptions } from './types';
/**
* @typedef {Object} UsePDFParameters
* @property {string} password
* Document password to unlock content
* @property {function} onProgress
* Callback to request a password if a wrong or no password was provided. The callback receives two parameters: a function that should be called with the new password, and a reason (see PasswordResponses).
* @property {function} onPassword
* Callback to be able to monitor the loading progress of the PDF file (necessary to implement e.g. a loading bar). The callback receives an OnProgressParameters argument. if this function is used option.password is ignored
* @property {function} onError
* Callback to be able to handle errors during loading
* */
/**
*
* @param {string | URL | TypedArray | PDFDataRangeTransport | DocumentInitParameters} src
* Can be a URL where a PDF file is located, a typed array (Uint8Array) already populated with data, or a parameter object.
* @param {UsePDFParameters} options
* UsePDF object parameters
*/
export declare function usePDF(src: string | URL | TypedArray | PDFDataRangeTransport | DocumentInitParameters, options?: UsePDFOptions): {
pdf: import("vue").ShallowRef<import("pdfjs-dist/types/src/display/api").PDFDocumentLoadingTask | undefined>;
pages: import("vue").ShallowRef<number>;
info: import("vue").ShallowRef<{}> | import("vue").ShallowRef<UsePDFInfo>;
};

View file

@ -0,0 +1,5 @@
import type { PDFDocumentProxy } from 'pdfjs-dist';
import type { AnnotationEventPayload } from '../types';
declare const EVENTS_TO_HANDLER: string[];
declare function annotationEventsHandler(evt: Event, PDFDoc: PDFDocumentProxy, Annotations: Object[]): AnnotationEventPayload | Promise<AnnotationEventPayload | undefined> | undefined;
export { EVENTS_TO_HANDLER, annotationEventsHandler, };

View file

@ -0,0 +1,71 @@
import type { IPDFLinkService } from 'pdfjs-dist/types/web/interfaces';
declare class SimpleLinkService implements IPDFLinkService {
externalLinkEnabled: boolean;
constructor();
/**
* @type {number}
*/
get pagesCount(): number;
/**
* @type {number}
*/
get page(): number;
/**
* @param {number} _value
*/
set page(_value: number);
/**
* @type {number}
*/
get rotation(): number;
/**
* @param {number} _value
*/
set rotation(_value: number);
/**
* @type {boolean}
*/
get isInPresentationMode(): boolean;
/**
* @param {string|Array} _dest - The named, or explicit, PDF destination.
*/
goToDestination(_dest: string | Array<any>): Promise<void>;
/**
* @param {number|string} _val - The page number, or page label.
*/
goToPage(_val: number | string): void;
/**
* @param {HTMLAnchorElement} link
* @param {string} url
* @param {boolean} [_newWindow]
*/
addLinkAttributes(link: HTMLAnchorElement, url: string, _newWindow?: boolean): void;
/**
* @param _dest - The PDF destination object.
* @returns {string} The hyperlink to the PDF object.
*/
getDestinationHash(_dest: any): string;
/**
* @param _hash - The PDF parameters/hash.
* @returns {string} The hyperlink to the PDF object.
*/
getAnchorUrl(_hash: any): string;
/**
* @param {string} _hash
*/
setHash(_hash: string): void;
/**
* @param {string} _action
*/
executeNamedAction(_action: string): void;
/**
* @param {Object} _action
*/
executeSetOCGState(_action: object): void;
/**
* @param {number} _pageNum - page number.
* @param {Object} _pageRef - reference to the page.
*/
cachePageRef(_pageNum: number, _pageRef: object): void;
}
export { SimpleLinkService };

4
node_modules/@tato30/vue-pdf/dist/types/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,4 @@
import type { Plugin } from 'vue';
export declare const VuePDFPlugin: Plugin;
export * from './components';
export default VuePDFPlugin;

69
node_modules/@tato30/vue-pdf/package.json generated vendored Normal file
View file

@ -0,0 +1,69 @@
{
"name": "@tato30/vue-pdf",
"version": "1.7.2",
"description": "PDF viewer for Vue 3",
"author": {
"name": "Aldo Hernandez",
"url": "https://github.com/TaTo30"
},
"license": "MIT",
"homepage": "https://github.com/TaTo30/VuePDF/",
"repository": {
"type": "git",
"url": "git+https://github.com/TaTo30/VuePDF.git"
},
"bugs": {
"url": "https://github.com/TaTo30/VuePDF/issues"
},
"keywords": [
"pdf",
"vue",
"viewer"
],
"exports": {
".": {
"require": "./dist/index.umd.js",
"import": "./dist/index.mjs",
"types": "./dist/types/index.d.ts"
},
"./**/*.css": "./dist/*.css",
"./src/*": "./src/*"
},
"main": "./dist/index.umd.js",
"module": "./dist/index.mjs",
"types": "./dist/types/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"dev": "vite --force --config vite.playground.ts",
"build": "npm run build:lib && npm run build:dts",
"build:lib": "vite build",
"build:dts": "vue-tsc --declaration --emitDeclarationOnly -p tsconfig.build.json",
"publish": "npm publish --access public",
"publish:beta": "npm publish --tag beta --access public",
"preview": "vite preview --port 5050",
"lint": "eslint .",
"lint:fix": "eslint --fix ."
},
"peerDependencies": {
"vue": "^3.2.33"
},
"dependencies": {
"pdfjs-dist": "3.7.107"
},
"devDependencies": {
"@antfu/eslint-config": "^0.38.5",
"@babel/core": "^7.21.8",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@types/node": "^18.16.3",
"@vitejs/plugin-vue": "^4.2.1",
"@vue/eslint-config-prettier": "^7.1.0",
"eslint": "^8.39.0",
"typescript": "^4.9.4",
"vite": "^4.3.4",
"vue": "^3.2.47",
"vue-tsc": "^1.6.3"
}
}

256
node_modules/@tato30/vue-pdf/src/components/VuePDF.vue generated vendored Normal file
View file

@ -0,0 +1,256 @@
<!-- eslint-disable no-case-declarations -->
<script setup lang="ts">
import * as PDFJS from 'pdfjs-dist'
import { onMounted, ref, toRaw, watch } from 'vue'
import 'pdfjs-dist/web/pdf_viewer.css'
import type { PDFDocumentLoadingTask, PDFDocumentProxy, PDFPageProxy, PageViewport, RenderTask } from 'pdfjs-dist'
import type { GetViewportParameters, RenderParameters } from 'pdfjs-dist/types/src/display/api'
import type { AnnotationEventPayload, LoadedEventPayload } from './types'
import AnnotationLayer from './layers/AnnotationLayer.vue'
import TextLayer from './layers/TextLayer.vue'
import XFALayer from './layers/XFALayer.vue'
const props = withDefaults(defineProps<{
pdf?: PDFDocumentLoadingTask
page?: number
scale?: number
rotation?: number
fitParent?: boolean
textLayer?: boolean
imageResourcesPath?: string
hideForms?: boolean
annotationLayer?: boolean
annotationsFilter?: string[]
annotationsMap?: object
watermarkText?: string
}>(), {
page: 1,
scale: 1,
})
const emit = defineEmits<{
(event: 'annotation', payload: AnnotationEventPayload): void
(event: 'loaded', payload: LoadedEventPayload): void
}>()
// Template Refs
const container = ref<HTMLSpanElement>()
const loadingLayer = ref<HTMLSpanElement>()
const loading = ref(false)
let renderTask: RenderTask
// PDF Refs
const DocumentProxy = ref<PDFDocumentProxy>()
const PageProxy = ref<PDFPageProxy>()
const InternalViewport = ref<PageViewport>()
function emitLoaded(data: LoadedEventPayload) {
emit('loaded', data)
}
function emitAnnotation(data: AnnotationEventPayload) {
emit('annotation', data)
}
function computeRotation(rotation: number): number {
if (!(typeof rotation === 'number' && rotation % 90 === 0))
return 0
const factor = rotation / 90
if (factor > 4)
return computeRotation(rotation - 360)
else if (factor < 0)
return computeRotation(rotation + 360)
return rotation
}
function computeScale(page: PDFPageProxy): number {
let fscale = props.scale
if (props.fitParent) {
const parentWidth: number = (container.value!.parentNode! as HTMLElement).clientWidth
const scale1Width = page.getViewport({ scale: 1 }).width
fscale = parentWidth / scale1Width
}
return fscale
}
function paintWatermark(canvas: HTMLCanvasElement, baseFontSize = 18, zoomRatio = 1.0) {
if (!props.watermarkText)
return
const ctx: CanvasRenderingContext2D | null = canvas.getContext('2d')
if (!ctx)
return
ctx.font = `${baseFontSize * zoomRatio}px Trebuchet MS`
ctx.fillStyle = 'rgba(211, 210, 211, 0.3)'
const numWatermarks = 50 // Adjust the number of watermarks as desired
for (let i = 0; i < numWatermarks; i++) {
const x = (i % 5) * (canvas.width / 5) + canvas.width / 10
const y = Math.floor(i / 5) * (canvas.height / 5) + canvas.height / 10
ctx.save()
ctx.translate(x, y)
ctx.rotate(-(Math.PI / 4))
ctx.fillText(props.watermarkText, 0, 0)
ctx.restore()
}
}
function getCurrentCanvas(): HTMLCanvasElement | null {
let oldCanvas = null
container.value?.childNodes.forEach((el) => {
if ((el as HTMLElement).tagName === 'CANVAS')
oldCanvas = el
})
return oldCanvas
}
function setupCanvas(viewport: PageViewport): HTMLCanvasElement {
let canvas
const currentCanvas = getCurrentCanvas()!
if (currentCanvas && currentCanvas?.getAttribute('role') === 'main') {
canvas = currentCanvas
}
else {
canvas = document.createElement('canvas')
canvas.style.display = 'block'
canvas.setAttribute('dir', 'ltr')
}
const outputScale = window.devicePixelRatio || 1
canvas.width = Math.floor(viewport.width * outputScale)
canvas.height = Math.floor(viewport.height * outputScale)
canvas.style.width = `${Math.floor(viewport.width)}px`
canvas.style.height = `${Math.floor(viewport.height)}px`
// --scale-factor property
container.value?.style.setProperty('--scale-factor', `${viewport.scale}`)
// Also setting dimension properties for load layer
loadingLayer.value!.style.width = `${Math.floor(viewport.width)}px`
loadingLayer.value!.style.height = `${Math.floor(viewport.height)}px`
loadingLayer.value!.style.top = '0'
loadingLayer.value!.style.left = '0'
loading.value = true
return canvas
}
function cancelRender() {
if (renderTask)
renderTask.cancel()
}
function renderPage(pageNum: number) {
toRaw(DocumentProxy.value)?.getPage(pageNum).then((page) => {
cancelRender()
const defaultViewport = page.getViewport()
const viewportParams: GetViewportParameters = {
scale: computeScale(page),
rotation: computeRotation((props.rotation || 0) + defaultViewport.rotation),
}
const viewport = page.getViewport(viewportParams)
const oldCanvas = getCurrentCanvas()
const canvas = setupCanvas(viewport)
const outputScale = window.devicePixelRatio || 1
const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : undefined
// Render PDF page into canvas context
const renderContext: RenderParameters = {
canvasContext: canvas.getContext('2d')!,
viewport,
annotationMode: props.hideForms ? PDFJS.AnnotationMode.ENABLE : PDFJS.AnnotationMode.ENABLE_FORMS,
transform,
}
if (canvas?.getAttribute('role') !== 'main') {
if (oldCanvas)
container.value?.replaceChild(canvas, oldCanvas)
}
else {
canvas.removeAttribute('role')
}
PageProxy.value = page
InternalViewport.value = viewport
renderTask = page.render(renderContext)
renderTask.promise.then(() => {
paintWatermark(canvas, 18, viewport.scale)
loading.value = false
emitLoaded(InternalViewport.value!)
}).catch(() => {
// render task cancelled
})
})
}
function initDoc(proxy: PDFDocumentLoadingTask) {
proxy.promise.then(async (doc) => {
DocumentProxy.value = doc
renderPage(props.page)
})
}
watch(() => props.pdf, (pdf) => {
// for any change in pdf proxy, rework all
if (pdf !== undefined)
initDoc(pdf)
})
watch(() => [props.scale, props.rotation, props.page, props.hideForms, props.watermarkText], () => {
renderPage(props.page)
})
onMounted(() => {
if (props.pdf !== undefined)
initDoc(props.pdf)
})
function reload() {
renderPage(props.page)
}
function cancel() {
cancelRender()
}
function getAnnotationStorage() {
const pdf = toRaw(DocumentProxy.value)
return pdf?.annotationStorage
}
defineExpose({
reload,
cancel,
getAnnotationStorage,
})
</script>
<template>
<div ref="container" style="position: relative; display: block; overflow: hidden;">
<canvas dir="ltr" style="display: block" role="main" />
<AnnotationLayer
v-show="annotationLayer"
:filter="annotationsFilter!"
:map="annotationsMap"
:viewport="InternalViewport!"
:image-resources-path="imageResourcesPath"
:hide-forms="hideForms"
:page="PageProxy!"
:document="DocumentProxy!"
@annotation="emitAnnotation($event)"
/>
<TextLayer v-show="textLayer" :page="PageProxy!" :viewport="InternalViewport!" />
<XFALayer :page="PageProxy!" :viewport="InternalViewport!" :document="DocumentProxy!" />
<div v-show="loading" ref="loadingLayer" style="position: absolute;">
<slot />
</div>
</div>
</template>

3
node_modules/@tato30/vue-pdf/src/components/index.ts generated vendored Normal file
View file

@ -0,0 +1,3 @@
export * from './types'
export * from './usePDF'
export { default as VuePDF } from './VuePDF.vue'

View file

@ -0,0 +1,139 @@
<script setup lang="ts">
import * as PDFJS from 'pdfjs-dist'
import { onMounted, ref, toRaw, watch } from 'vue'
import type { PDFDocumentProxy, PDFPageProxy, PageViewport } from 'pdfjs-dist'
import type { AnnotationLayerParameters } from 'pdfjs-dist/types/src/display/annotation_layer'
import { EVENTS_TO_HANDLER, annotationEventsHandler } from '../utils/annotations'
import { SimpleLinkService } from '../utils/link_service'
import type { AnnotationEventPayload } from '../types'
const props = defineProps<{
page?: PDFPageProxy
viewport?: PageViewport
document?: PDFDocumentProxy
filter?: string[]
map?: object
imageResourcesPath?: string
hideForms?: boolean
enableScripting?: boolean
}>()
const emit = defineEmits<{
(event: 'annotation', payload: AnnotationEventPayload): void
}>()
const layer = ref<HTMLDivElement>()
const annotations = ref<any[]>()
function annotationsEvents(evt: Event) {
const value = annotationEventsHandler(evt, props.document!, annotations.value!)
Promise.resolve(value).then((data) => {
if (data)
emit('annotation', data)
})
}
async function getFieldObjects() {
const fieldObjects = await toRaw(props.document)?.getFieldObjects()
return fieldObjects
}
async function getHasJSActions() {
const hasJSActions = await toRaw(props.document)?.hasJSActions()
return hasJSActions
}
async function getAnnotations() {
const page = props.page
let annotations = await page?.getAnnotations()
if (props.filter) {
const filters = props.filter
annotations = annotations!.filter((value) => {
const subType = value.subtype
const fieldType = value.fieldType ? `${subType}.${value.fieldType}` : null
return filters?.includes(subType) || (fieldType !== null && filters?.includes(fieldType))
})
}
return annotations
}
async function render() {
layer.value!.replaceChildren?.()
for (const evtHandler of EVENTS_TO_HANDLER)
layer.value!.removeEventListener(evtHandler, annotationsEvents)
const pdf = toRaw(props.document)
const page = props.page
const viewport = props.viewport
annotations.value = await getAnnotations()
// Canvas map for push button widget
const canvasMap = new Map<string, HTMLCanvasElement>([])
for (const anno of annotations.value!) {
if (anno.subtype === 'Widget' && anno.fieldType === 'Btn' && anno.pushButton) {
const canvasWidth = anno.rect[2] - anno.rect[0]
const canvasHeight = anno.rect[3] - anno.rect[1]
const subCanvas = document.createElement('canvas')
subCanvas.setAttribute('width', (canvasWidth * viewport!.scale).toString())
subCanvas.setAttribute('height', (canvasHeight * viewport!.scale).toString())
canvasMap.set(anno.id, subCanvas)
}
}
const annotationStorage = pdf!.annotationStorage
if (props.map) {
for (const [key, value] of Object.entries(props.map))
annotationStorage.setValue(key, value)
}
const parameters: AnnotationLayerParameters = {
annotations: annotations.value!,
viewport: viewport!.clone({ dontFlip: true }),
linkService: new SimpleLinkService(),
annotationCanvasMap: canvasMap,
div: layer.value!,
annotationStorage,
renderForms: !props.hideForms,
page: page!,
enableScripting: false,
hasJSActions: await getHasJSActions(),
fieldObjects: await getFieldObjects(),
downloadManager: null,
imageResourcesPath: props.imageResourcesPath,
}
PDFJS.AnnotationLayer.render(parameters)
for (const evtHandler of EVENTS_TO_HANDLER)
layer.value!.addEventListener(evtHandler, annotationsEvents)
}
watch(() => props.viewport, () => {
if (props.page && props.viewport && layer.value)
render()
})
onMounted(() => {
if (props.page && props.viewport && layer.value)
render()
})
</script>
<template>
<div ref="layer" class="annotationLayer" style="display: block;" />
</template>
<style>
.annotationLayer {
right: 0;
bottom: 0;
}
/* Make annotation sections available over text layer */
.annotationLayer section {
z-index: 1 !important;
}
</style>

View file

@ -0,0 +1,66 @@
<script setup lang="ts">
import * as PDFJS from 'pdfjs-dist'
import { onMounted, ref, watch } from 'vue'
import type { PDFPageProxy, PageViewport } from 'pdfjs-dist'
import type { TextLayerRenderParameters } from 'pdfjs-dist/types/src/display/text_layer'
const props = defineProps<{
page?: PDFPageProxy
viewport?: PageViewport
}>()
const layer = ref<HTMLDivElement>()
const endContent = ref<HTMLDivElement>()
function render() {
layer.value!.replaceChildren?.()
const page = props.page
const viewport = props.viewport
const textStream = page?.streamTextContent({ includeMarkedContent: true, disableNormalization: true })
const parameters: TextLayerRenderParameters = {
textContentSource: textStream!,
viewport: viewport!,
container: layer.value!,
isOffscreenCanvasSupported: true,
textDivs: [],
textDivProperties: new WeakMap(),
}
const task = PDFJS.renderTextLayer(parameters)
task.promise.then(() => {
const endOfContent = document.createElement('div')
endOfContent.className = 'endOfContent'
layer.value?.appendChild(endOfContent)
endContent.value = endOfContent
})
}
function onMouseDown() {
if (!endContent.value)
return
endContent.value.classList.add('active')
}
function onMouseUp() {
if (!endContent.value)
return
endContent.value.classList.remove('active')
}
watch(() => props.viewport, (_) => {
if (props.page && props.viewport && layer.value)
render()
})
onMounted(() => {
if (props.page && props.viewport && layer.value)
render()
})
</script>
<template>
<div ref="layer" class="textLayer" style="display: block;" @mousedown="onMouseDown" @mouseup="onMouseUp" />
</template>

View file

@ -0,0 +1,58 @@
<script setup lang="ts">
import * as PDFJS from 'pdfjs-dist'
import { onMounted, ref, toRaw, watch } from 'vue'
import type { PDFDocumentProxy, PDFPageProxy, PageViewport } from 'pdfjs-dist'
import type { XfaLayerParameters } from 'pdfjs-dist/types/src/display/xfa_layer'
import { SimpleLinkService } from '../utils/link_service'
const props = defineProps<{
page?: PDFPageProxy
document?: PDFDocumentProxy
viewport?: PageViewport
}>()
const layer = ref<HTMLDivElement>()
async function render() {
layer.value!.replaceChildren?.()
const pdf = toRaw(props.document)
const page = props.page
const viewport = props.viewport
if (pdf!.isPureXfa) {
const xfaHTML = await page!.getXfa()
const parameters: XfaLayerParameters = {
div: layer.value!,
viewport: viewport!.clone({ dontFlip: true }),
linkService: new SimpleLinkService(),
annotationStorage: pdf?.annotationStorage,
xfaHtml: xfaHTML!,
}
PDFJS.XfaLayer.render(parameters)
}
}
watch(() => props.viewport, (_) => {
if (props.page && props.viewport && layer.value)
render()
})
onMounted(() => {
if (props.page && props.viewport && layer.value)
render()
})
</script>
<template>
<div ref="layer" style="display: block;" />
</template>
<style>
/* Make this layer over other layers */
.xfaLayer {
z-index: 5;
}
</style>

33
node_modules/@tato30/vue-pdf/src/components/types.ts generated vendored Normal file
View file

@ -0,0 +1,33 @@
import type { PageViewport } from 'pdfjs-dist'
import type { OnProgressParameters } from 'pdfjs-dist/types/src/display/api'
import type { Metadata } from 'pdfjs-dist/types/src/display/metadata'
export type LoadedEventPayload = PageViewport
export interface AnnotationEventPayload {
type: string
data: any
}
export type OnProgressCallback = (progressData: OnProgressParameters) => void
export type UpdatePasswordFn = (newPassword: string) => void
export type OnPasswordCallback = (updatePassword: UpdatePasswordFn, reason: any) => void
export type OnErrorCallback = (error: any) => void
export interface UsePDFOptions {
onProgress?: OnProgressCallback
onPassword?: OnPasswordCallback
onError?: OnErrorCallback
password?: string
}
export interface UsePDFInfoMetadata {
info: Object
metadata: Metadata
}
export interface UsePDFInfo {
metadata: UsePDFInfoMetadata
attachments: Record<string, unknown>
javascript: string[] | null
}

86
node_modules/@tato30/vue-pdf/src/components/usePDF.ts generated vendored Normal file
View file

@ -0,0 +1,86 @@
import * as PDFJS from 'pdfjs-dist'
import PDFWorker from 'pdfjs-dist/build/pdf.worker.min?url'
import { shallowRef } from 'vue'
import type { PDFDocumentLoadingTask } from 'pdfjs-dist'
import type { DocumentInitParameters, PDFDataRangeTransport, TypedArray } from 'pdfjs-dist/types/src/display/api'
import type { OnPasswordCallback, UsePDFInfo, UsePDFOptions } from './types'
// Could not find a way to make this work with vite, importing the worker entry bundle the whole worker to the the final output
// https://erindoyle.dev/using-pdfjs-with-vite/
// PDFJS.GlobalWorkerOptions.workerSrc = PDFWorker
function configWorker(wokerSrc: string) {
PDFJS.GlobalWorkerOptions.workerSrc = wokerSrc
}
/**
* @typedef {Object} UsePDFParameters
* @property {string} password
* Document password to unlock content
* @property {function} onProgress
* Callback to request a password if a wrong or no password was provided. The callback receives two parameters: a function that should be called with the new password, and a reason (see PasswordResponses).
* @property {function} onPassword
* Callback to be able to monitor the loading progress of the PDF file (necessary to implement e.g. a loading bar). The callback receives an OnProgressParameters argument. if this function is used option.password is ignored
* @property {function} onError
* Callback to be able to handle errors during loading
* */
/**
*
* @param {string | URL | TypedArray | PDFDataRangeTransport | DocumentInitParameters} src
* Can be a URL where a PDF file is located, a typed array (Uint8Array) already populated with data, or a parameter object.
* @param {UsePDFParameters} options
* UsePDF object parameters
*/
export function usePDF(src: string | URL | TypedArray | PDFDataRangeTransport | DocumentInitParameters, options: UsePDFOptions = {
onProgress: undefined,
onPassword: undefined,
onError: undefined,
password: '',
}) {
if (!PDFJS.GlobalWorkerOptions?.workerSrc)
configWorker(PDFWorker)
const pdf = shallowRef<PDFDocumentLoadingTask>()
const pages = shallowRef(0)
const info = shallowRef<UsePDFInfo | {}>({})
const loadingTask = PDFJS.getDocument(src)
if (options.onProgress)
loadingTask.onProgress = options.onProgress
if (options.onPassword) {
loadingTask.onPassword = options.onPassword
}
else if (options.password) {
const onPassword: OnPasswordCallback = (updatePassword, _) => {
updatePassword(options.password ?? '')
}
loadingTask.onPassword = onPassword
}
loadingTask.promise.then(async (doc) => {
pdf.value = doc.loadingTask
pages.value = doc.numPages
const metadata = await doc.getMetadata()
const attachments = (await doc.getAttachments()) as Record<string, unknown>
const javascript = await doc.getJavaScript()
info.value = {
metadata,
attachments,
javascript,
}
}, (error) => {
// PDF loading error
if (typeof options.onError === 'function')
options.onError(error)
})
return {
pdf,
pages,
info,
}
}

View file

@ -0,0 +1,213 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable no-case-declarations */
import type { PDFDocumentProxy } from 'pdfjs-dist'
import type { RefProxy } from 'pdfjs-dist/types/src/display/api'
import type { AnnotationEventPayload } from '../types'
interface PopupArgs {
[key: string]: string
}
interface LinkAnnotation {
dest: Array<any> | string
url: string
unsafeurl: string
}
const INTERNAL_LINK = 'internal-link'
const LINK = 'link'
const FILE_ATTACHMENT = 'file-attachment'
const FORM_TEXT = 'form-text'
const FORM_SELECT = 'form-select'
const FORM_CHECKBOX = 'form-checkbox'
const FORM_RADIO = 'form-radio'
const FORM_BUTTON = 'form-button'
const EVENTS_TO_HANDLER = ['click', 'dblclick', 'mouseover', 'input', 'change']
function getAnnotationsByKey(key: string, value: any, annotations: Object[]): any[] {
const result = []
if (annotations) {
for (const annotation of annotations) {
type Key = keyof typeof annotation
if (annotation[key as Key] === value)
result.push(annotation)
}
}
return result
}
function buildAnnotationData(type: string, data: any): AnnotationEventPayload {
return { type, data }
}
function inputAnnotation(inputEl: any, args?: any) {
switch (inputEl.type) {
case 'textarea':
case 'text':
return buildAnnotationData(FORM_TEXT, {
fieldName: inputEl.name,
value: inputEl.value,
})
case 'select-one':
case 'select-multiple':
const options = []
for (const opt of inputEl.options) {
options.push({
value: opt.value,
label: opt.label,
})
}
const selected = []
for (const opt of inputEl.selectedOptions) {
selected.push({
value: opt.value,
label: opt.label,
})
}
return buildAnnotationData(FORM_SELECT, {
fieldName: inputEl.name,
value: selected,
options,
})
case 'checkbox':
return buildAnnotationData(FORM_CHECKBOX, {
fieldName: inputEl.name,
checked: inputEl.checked,
})
case 'radio':
return buildAnnotationData(FORM_RADIO, {
fieldName: inputEl.name,
...args,
})
case 'button':
return buildAnnotationData(FORM_BUTTON, {
fieldName: inputEl.name,
...args,
})
}
}
function fileAnnotation(annotation: any) {
return buildAnnotationData(FILE_ATTACHMENT, annotation.file)
}
async function linkAnnotation(annotation: {
dest?: any
url?: string
unsafeUrl?: string
}, PDFDoc: PDFDocumentProxy) {
if (annotation.dest) {
// Get referenced page number of internal link
if (typeof annotation.dest === 'string') {
return buildAnnotationData(INTERNAL_LINK, {
referencedPage: Number(annotation.dest.substring(1, annotation.dest.length)),
offset: null,
})
}
else {
const pageIndex = await PDFDoc.getPageIndex(annotation.dest[0] as RefProxy)
return buildAnnotationData(INTERNAL_LINK, {
referencedPage: pageIndex + 1,
offset: {
left: annotation.dest[2],
bottom: annotation.dest[3],
},
})
}
}
else if (annotation.url) {
return buildAnnotationData(LINK, {
url: annotation.url,
unsafeUrl: annotation.unsafeUrl,
})
}
}
function mergePopupArgs(annotation: HTMLElement) {
for (const spanElement of annotation.getElementsByTagName('span')) {
let content = spanElement.textContent
const args = JSON.parse(spanElement.dataset.l10nArgs ?? '{}') as PopupArgs
if (content) {
for (const key in args)
content = content.replace(`{{${key}}}`, args[key])
}
spanElement.textContent = content
}
}
// Use this function to handle annotation events
function annotationEventsHandler(evt: Event, PDFDoc: PDFDocumentProxy, Annotations: Object[]) {
let annotation = (evt.target as HTMLInputElement).parentNode! as HTMLElement
// annotations are <section> elements if div returned find in child nodes the section element
if (annotation.tagName === 'DIV')
annotation = annotation.firstChild! as HTMLElement
if (annotation.className === 'linkAnnotation' && evt.type === 'click') {
const id: string | undefined = annotation.dataset?.annotationId
if (id)
return linkAnnotation(getAnnotationsByKey('id', id, Annotations)[0] as LinkAnnotation, PDFDoc)
}
else if (annotation.className.includes('popupAnnotation') || annotation.className.includes('textAnnotation')) {
mergePopupArgs(annotation)
}
else if (annotation.className.includes('fileAttachmentAnnotation')) {
mergePopupArgs(annotation)
const id = annotation.dataset.annotationId
if (id && evt.type === 'dblclick')
return fileAnnotation(getAnnotationsByKey('id', id, Annotations)[0])
}
else if (annotation.className.includes('textWidgetAnnotation') && evt.type === 'input') {
let inputElement: HTMLInputElement | HTMLTextAreaElement = annotation.getElementsByTagName('input')[0]
if (!inputElement)
inputElement = annotation.getElementsByTagName('textarea')[0]
return inputAnnotation(inputElement)
}
else if (annotation.className.includes('choiceWidgetAnnotation') && evt.type === 'input') {
return inputAnnotation(annotation.getElementsByTagName('select')[0])
}
else if (annotation.className.includes('buttonWidgetAnnotation checkBox') && evt.type === 'change') {
return inputAnnotation(annotation.getElementsByTagName('input')[0])
}
else if (annotation.className.includes('buttonWidgetAnnotation radioButton') && evt.type === 'change') {
const id = annotation.dataset.annotationId
if (id) {
const anno = getAnnotationsByKey('id', id, Annotations)[0]
const radioOptions = []
for (const radioAnnotations of getAnnotationsByKey('fieldName', anno.fieldName, Annotations)) {
if (radioAnnotations.buttonValue)
radioOptions.push(radioAnnotations.buttonValue)
}
return inputAnnotation(annotation.getElementsByTagName('input')[0], {
value: anno.buttonValue,
defaultValue: anno.fieldValue,
options: radioOptions,
})
}
}
else if (annotation.className.includes('buttonWidgetAnnotation pushButton') && evt.type === 'click') {
const id = annotation.dataset.annotationId
if (id) {
const anno = getAnnotationsByKey('id', id, Annotations)[0]
if (!anno.resetForm) {
return inputAnnotation(
{ name: anno.fieldName, type: 'button' },
{ actions: anno.actions, reset: false },
)
}
else {
return inputAnnotation(
{ name: anno.fieldName, type: 'button' },
{ actions: anno.actions, reset: true },
)
}
}
}
}
export {
EVENTS_TO_HANDLER,
annotationEventsHandler,
}

View file

@ -0,0 +1,103 @@
import type { IPDFLinkService } from 'pdfjs-dist/types/web/interfaces'
class SimpleLinkService implements IPDFLinkService {
externalLinkEnabled: boolean
constructor() {
this.externalLinkEnabled = true
}
/**
* @type {number}
*/
get pagesCount() {
return 0
}
/**
* @type {number}
*/
get page() {
return 0
}
/**
* @param {number} _value
*/
set page(_value: number) {}
/**
* @type {number}
*/
get rotation() {
return 0
}
/**
* @param {number} _value
*/
set rotation(_value: number) {}
/**
* @type {boolean}
*/
get isInPresentationMode() {
return false
}
/**
* @param {string|Array} _dest - The named, or explicit, PDF destination.
*/
async goToDestination(_dest: string | Array<any>) {}
/**
* @param {number|string} _val - The page number, or page label.
*/
goToPage(_val: number | string) {}
/**
* @param {HTMLAnchorElement} link
* @param {string} url
* @param {boolean} [_newWindow]
*/
addLinkAttributes(link: HTMLAnchorElement, url: string, _newWindow = false) { }
/**
* @param _dest - The PDF destination object.
* @returns {string} The hyperlink to the PDF object.
*/
getDestinationHash(_dest: any): string {
return '#'
}
/**
* @param _hash - The PDF parameters/hash.
* @returns {string} The hyperlink to the PDF object.
*/
getAnchorUrl(_hash: any): string {
return '#'
}
/**
* @param {string} _hash
*/
setHash(_hash: string) {}
/**
* @param {string} _action
*/
executeNamedAction(_action: string) {}
/**
* @param {Object} _action
*/
executeSetOCGState(_action: object) {}
/**
* @param {number} _pageNum - page number.
* @param {Object} _pageRef - reference to the page.
*/
cachePageRef(_pageNum: number, _pageRef: object) {}
}
export { SimpleLinkService }

20
node_modules/@tato30/vue-pdf/src/env.d.ts generated vendored Normal file
View file

@ -0,0 +1,20 @@
declare module "*?worker" {
const workerConstructor: {
new(): Worker
};
export default workerConstructor;
}
declare module "*?url" {
const url: string;
export default url;
}
declare module "*?worker&url" {
const workerUrl: string;
export default workerUrl;
}
declare module "pdfjs-dist/build/pdf" {
export * from 'pdfjs-dist'
}

12
node_modules/@tato30/vue-pdf/src/index.ts generated vendored Normal file
View file

@ -0,0 +1,12 @@
import type { Plugin } from 'vue'
import VuePDF from './components/VuePDF.vue'
export const VuePDFPlugin: Plugin = {
install(Vue) {
Vue.component(VuePDF.name, VuePDF)
},
}
export * from './components'
export default VuePDFPlugin