UNPKG

pdfjs-vue-print

Version:

Example Vue 3 project using pdf.js to build a simple custom PDF.js viewer and print service.

284 lines (234 loc) 7.46 kB
/* Copyright 2012 Mozilla Foundation * Copyright 2022 Drew Letcher * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ "use strict"; import * as pdfjsLib from "pdfjs-dist/build/pdf.js" import { l10n } from "pdfjs-dist/web/pdf_viewer"; import { PDFPrintServiceFactory } from "./print_service_factory.js"; import * as PrintService from "./print_service.js" pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.js"; const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/"; const CMAP_PACKED = true; const MAX_IMAGE_SIZE = 1024 * 1024; const ENABLE_XFA = false; export default class PrintOnlyApp { constructor(options) { this.options = options; this.printContainer = options.printContainer || null; this.password = options.password || ""; this.onPrinted = options.onPrinted || null; this._boundEvents = {}; this.pdfDocument = null; this.pdfLoadingTask = null; this.url = ""; this.documentInfo = null; this.metadata = null; this.pagesOverview = null; this.enablePrintAutoRotate = true; this.printResolution = 150; this.printService = null; } // Called once when the document is loaded. async create() { console.log("create"); PrintService.install(); this.bindPrintEvents(); } destroy() { this.unbindPrintEvents(); PrintService.remove(); } bindPrintEvents() { const { _boundEvents } = this; _boundEvents.beforePrint = this.beforePrint.bind(this); _boundEvents.afterPrint = this.afterPrint.bind(this); window.addEventListener("beforeprint", _boundEvents.beforePrint); window.addEventListener("afterprint", _boundEvents.afterPrint); } unbindPrintEvents() { const { _boundEvents } = this; window.removeEventListener("beforeprint", _boundEvents.beforePrint); window.removeEventListener("afterprint", _boundEvents.afterPrint); _boundEvents.beforePrint = null; _boundEvents.afterPrint = null; } /** * Opens PDF document specified by URL. */ async open(params) { console.log("open"); if (this.pdfLoadingTask) { // We need to destroy already opened document await this.close() } const url = params.url; this.setTitleUsingUrl(url); // Loading document const loadingTask = pdfjsLib.getDocument({ url, cMapUrl: CMAP_URL, cMapPacked: CMAP_PACKED, maxImageSize: MAX_IMAGE_SIZE, enableXfa: ENABLE_XFA, }); this.pdfLoadingTask = loadingTask; let pdfPassword = this.password; loadingTask.onPassword = (callback, reason) => { console.log("onPassword: " + reason) callback(pdfPassword) } const pdfDocument = await loadingTask.promise // Document loaded, specifying document for the viewer. this.pdfDocument = pdfDocument; this.setTitleUsingMetadata(pdfDocument); await this.getPagesOverview() } /** * Closes opened PDF document * @returns {Promise} - Returns the promise, which is resolved when all * destruction is completed. */ async close() { console.log("close"); if (!this.pdfLoadingTask) { return; } await this.pdfLoadingTask.destroy(); this.pdfLoadingTask = null; if (this.pdfDocument) { this.pdfDocument = null; } } async getPagesOverview() { function isPortraitOrientation(size) { return size.width <= size.height; } this.pagesOverview = []; if (!this.pdfDocument) { return; } for (let i = 1; i <= this.pdfDocument.numPages; i++) { const pdfPage = await this.pdfDocument.getPage(i); const viewport = pdfPage.getViewport({ scale: 1.0 }); if (!this.enablePrintAutoRotate || isPortraitOrientation(viewport)) { this.pagesOverview.push({ width: viewport.width, height: viewport.height, rotation: viewport.rotation, }); } else { // Landscape orientation. this.pagesOverview.push({ width: viewport.height, height: viewport.width, rotation: (viewport.rotation - 90) % 360, }); } } } beforePrint() { console.log("beforePrint") if (this.printService) { // There is no way to suppress beforePrint/afterPrint events, // but PDFPrintService may generate double events -- this will ignore // the second event that will be coming from native window.print(). return; } const pagesOverview = this.pagesOverview; // this.pdfViewer.getPagesOverview(); const printContainer = this.printContainer; const printResolution = this.printResolution; const optionalContentConfigPromise = null; // this.pdfViewer.optionalContentConfigPromise; console.log("create printService") const printService = PDFPrintServiceFactory.instance.createPrintService( this.pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n ); this.printService = printService; printService.layout(); } print() { window.print(); } afterPrint() { console.log("afterPrint"); if (this.printService) { console.log("destroy printService") this.printService.destroy(); this.printService = null; } if (this.onPrinted) this.onPrinted(); } setTitle(title) { document.title = title; } setTitleUsingUrl(url) { this.url = url; let title = pdfjsLib.getFilenameFromUrl(url) || url; try { title = decodeURIComponent(title); } catch (e) { // decodeURIComponent may throw URIError, // fall back to using the unprocessed url in that case } this.setTitle(title); } setTitleUsingMetadata(pdfDocument) { const self = this; pdfDocument.getMetadata() .then((data) => { const info = data.info; const metadata = data.metadata; self.documentInfo = info; self.metadata = metadata; // Provides some basic debug information console.log( "PDF " + pdfDocument.fingerprints[ 0 ] + " [" + info.PDFFormatVersion + " " + (info.Producer || "-").trim() + " / " + (info.Creator || "-").trim() + "]" + " (PDF.js: " + (pdfjsLib.version || "-") + ")" ); let pdfTitle; if (metadata && metadata.has("dc:title")) { const title = metadata.get("dc:title"); // Ghostscript sometimes returns 'Untitled', so prevent setting the // title to 'Untitled. if (title !== "Untitled") { pdfTitle = title; } } if (!pdfTitle && info && info.Title) { pdfTitle = info.Title; } if (pdfTitle) { self.setTitle(pdfTitle + " - " + document.title); } }); } }; export { PrintOnlyApp };