11<script setup>
22import * as pdfjsLib from ' pdfjs-dist/legacy/build/pdf.mjs' ;
33import * as pdfjsViewer from ' pdfjs-dist/web/pdf_viewer' ;
4- import pdfjsWorker from ' pdfjs-dist/build/pdf.worker?worker' ;
54import workerSrc from ' ./worker.js?raw' ;
5+ import { range } from ' ./helpers/range.js' ;
66
77import { storeToRefs } from ' pinia' ;
8- import { onMounted , ref , reactive , computed , getCurrentInstance } from ' vue' ;
8+ import { onMounted , onUnmounted , ref , getCurrentInstance } from ' vue' ;
99import { useSuperdocStore } from ' @superdoc/stores/superdoc-store' ;
1010import useSelection from ' @superdoc/helpers/use-selection' ;
1111
12- window .pdfjsWorker = pdfjsWorker;
13- pdfjsLib .GlobalWorkerOptions .workerSrc = URL .createObjectURL (
14- new Blob ([workerSrc], {
15- type: ' application/javascript' ,
16- }),
17- );
12+ const workerUrl = URL .createObjectURL (new Blob ([workerSrc], { type: ' text/javascript' }));
13+ pdfjsLib .GlobalWorkerOptions .workerSrc = workerUrl;
1814
1915const emit = defineEmits ([' page-loaded' , ' ready' , ' selection-change' , ' bypass-selection' ]);
2016const superdocStore = useSuperdocStore ();
2117const { proxy } = getCurrentInstance ();
2218const { activeZoom } = storeToRefs (superdocStore);
2319const totalPages = ref (null );
2420const viewer = ref (null );
21+
22+ const pdfViewerConfig = proxy .$superdoc .config .pdfViewer ;
23+ const textLayerMode = pdfViewerConfig .textLayerMode ?? 0 ;
24+
25+ let pdfjsLoadingTask = null ;
26+ let pdfjsDocument = null ;
27+ let pdfPageViews = [];
28+
2529const props = defineProps ({
2630 documentData: {
2731 type: Object ,
@@ -31,7 +35,6 @@ const props = defineProps({
3135
3236const id = props .documentData .id ;
3337const pdfData = props .documentData .data ;
34- const selectionBounds = reactive ({});
3538
3639const getOriginalPageSize = (page ) => {
3740 const viewport = page .getViewport ({ scale: 1 });
@@ -42,62 +45,70 @@ const getOriginalPageSize = (page) => {
4245
4346async function initPdfLayer (arrayBuffer ) {
4447 const loadingTask = pdfjsLib .getDocument (arrayBuffer);
45- return await loadingTask .promise ;
48+ const document = await loadingTask .promise ;
49+ return { loadingTask, document };
4650}
4751
4852async function loadPDF (fileObject ) {
4953 const fileReader = new FileReader ();
5054 fileReader .onload = async function (event ) {
51- const pdfDocument = await initPdfLayer (event .target .result );
52- await renderPages (pdfDocument);
55+ const { loadingTask , document } = await initPdfLayer (event .target .result );
56+ pdfjsLoadingTask = loadingTask;
57+ pdfjsDocument = document ;
58+ renderPages (document );
5359 };
5460 fileReader .readAsArrayBuffer (fileObject);
5561}
5662
57- const enableTextLayer = (container , state ) => {
58- const textLayer = container .querySelector (' .textLayer' );
59- if (textLayer) textLayer .style .pointerEvents = state ? ' auto' : ' none' ;
60- };
61-
6263const renderPages = (pdfDocument ) => {
6364 setTimeout (() => {
6465 _renderPages (pdfDocument);
6566 }, 150 );
6667};
6768
69+ async function getPdfjsPages (pdf , firstPage , lastPage ) {
70+ const allPagesPromises = range (firstPage, lastPage + 1 ).map ((num ) => pdf .getPage (num));
71+ return await Promise .all (allPagesPromises);
72+ }
73+
6874async function _renderPages (pdfDocument ) {
6975 try {
7076 const numPages = pdfDocument .numPages ;
7177 totalPages .value = numPages;
7278
73- for (let i = 1 ; i <= numPages; i++ ) {
74- const page = await pdfDocument .getPage (i);
79+ const firstPage = 1 ;
80+ const pdfjsPages = await getPdfjsPages (pdfDocument, firstPage, numPages);
81+
82+ for (const [index , page ] of pdfjsPages .entries ()) {
7583 const container = document .createElement (' div' );
7684 container .className = ' pdf-page' ;
77- container .dataset .pageNumber = i ;
78- container .id = ` ${ id} -page-${ i } ` ;
85+ container .dataset .pageNumber = index + 1 ;
86+ container .id = ` ${ id} -page-${ index + 1 } ` ;
7987 viewer .value .appendChild (container);
8088
8189 const { width , height } = getOriginalPageSize (page);
90+
8291 const scale = 1 ;
8392 const eventBus = new pdfjsViewer.EventBus ();
8493 const pdfPageView = new pdfjsViewer.PDFPageView ({
8594 container,
86- id: i ,
95+ id: index + 1 ,
8796 scale,
8897 defaultViewport: page .getViewport ({ scale }),
8998 eventBus,
99+ textLayerMode,
90100 });
101+ pdfPageViews .push (pdfPageView);
91102
92- const viewport = page .getViewport ({ scale });
93103 const containerBounds = container .getBoundingClientRect ();
94104 containerBounds .originalWidth = width;
95105 containerBounds .originalHeight = height;
106+
96107 pdfPageView .setPdfPage (page);
97108 await pdfPageView .draw ();
98109
99110 // Emit page information
100- emit (' page-loaded' , id, i , containerBounds);
111+ emit (' page-loaded' , id, index , containerBounds);
101112 }
102113
103114 emit (' ready' , id, viewer);
@@ -152,11 +163,6 @@ function getSelectedTextBoundingBox(container) {
152163 return boundingBox;
153164}
154165
155- onMounted (async () => {
156- await import (' pdfjs-dist/web/pdf_viewer.css' );
157- const doc = await loadPDF (pdfData);
158- });
159-
160166const handlePdfClick = (e ) => {
161167 const { target } = e;
162168 if (target .tagName !== ' SPAN' ) {
@@ -175,6 +181,28 @@ const handleMouseUp = (e) => {
175181 emit (' selection-change' , sel);
176182 }
177183};
184+
185+ const destroy = () => {
186+ pdfPageViews .forEach ((view ) => view .destroy ()); // will cleanup page resources
187+
188+ pdfjsDocument .cleanup ();
189+ pdfjsDocument .destroy ();
190+
191+ pdfPageViews = [];
192+ pdfjsDocument = null ;
193+ pdfjsLoadingTask = null ;
194+
195+ URL .revokeObjectURL (workerUrl);
196+ };
197+
198+ onMounted (async () => {
199+ await import (' pdfjs-dist/web/pdf_viewer.css' );
200+ await loadPDF (pdfData);
201+ });
202+
203+ onUnmounted (() => {
204+ destroy ();
205+ });
178206< / script>
179207
180208< template>
0 commit comments