1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.PDFPrintService = PDFPrintService;
|
28 |
|
29 | var _pdf = require("../pdf");
|
30 |
|
31 | var _app = require("./app.js");
|
32 |
|
33 | var _print_utils = require("./print_utils.js");
|
34 |
|
35 | let activeService = null;
|
36 | let dialog = null;
|
37 | let overlayManager = null;
|
38 |
|
39 | function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) {
|
40 | const scratchCanvas = activeService.scratchCanvas;
|
41 | const PRINT_UNITS = printResolution / _pdf.PixelsPerInch.PDF;
|
42 | scratchCanvas.width = Math.floor(size.width * PRINT_UNITS);
|
43 | scratchCanvas.height = Math.floor(size.height * PRINT_UNITS);
|
44 | const ctx = scratchCanvas.getContext("2d");
|
45 | ctx.save();
|
46 | ctx.fillStyle = "rgb(255, 255, 255)";
|
47 | ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height);
|
48 | ctx.restore();
|
49 | return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function ([pdfPage, printAnnotationStorage]) {
|
50 | const renderContext = {
|
51 | canvasContext: ctx,
|
52 | transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
|
53 | viewport: pdfPage.getViewport({
|
54 | scale: 1,
|
55 | rotation: size.rotation
|
56 | }),
|
57 | intent: "print",
|
58 | annotationMode: _pdf.AnnotationMode.ENABLE_STORAGE,
|
59 | optionalContentConfigPromise,
|
60 | printAnnotationStorage
|
61 | };
|
62 | return pdfPage.render(renderContext).promise;
|
63 | });
|
64 | }
|
65 |
|
66 | function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise = null, printAnnotationStoragePromise = null, l10n) {
|
67 | this.pdfDocument = pdfDocument;
|
68 | this.pagesOverview = pagesOverview;
|
69 | this.printContainer = printContainer;
|
70 | this._printResolution = printResolution || 150;
|
71 | this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig();
|
72 | this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve();
|
73 | this.l10n = l10n;
|
74 | this.currentPage = -1;
|
75 | this.scratchCanvas = document.createElement("canvas");
|
76 | }
|
77 |
|
78 | PDFPrintService.prototype = {
|
79 | layout() {
|
80 | this.throwIfInactive();
|
81 | const body = document.querySelector("body");
|
82 | body.setAttribute("data-pdfjsprinting", true);
|
83 | const hasEqualPageSizes = this.pagesOverview.every(function (size) {
|
84 | return size.width === this.pagesOverview[0].width && size.height === this.pagesOverview[0].height;
|
85 | }, this);
|
86 |
|
87 | if (!hasEqualPageSizes) {
|
88 | console.warn("Not all pages have the same size. The printed " + "result may be incorrect!");
|
89 | }
|
90 |
|
91 | this.pageStyleSheet = document.createElement("style");
|
92 | const pageSize = this.pagesOverview[0];
|
93 | this.pageStyleSheet.textContent = "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}";
|
94 | body.append(this.pageStyleSheet);
|
95 | },
|
96 |
|
97 | destroy() {
|
98 | if (activeService !== this) {
|
99 | return;
|
100 | }
|
101 |
|
102 | this.printContainer.textContent = "";
|
103 | const body = document.querySelector("body");
|
104 | body.removeAttribute("data-pdfjsprinting");
|
105 |
|
106 | if (this.pageStyleSheet) {
|
107 | this.pageStyleSheet.remove();
|
108 | this.pageStyleSheet = null;
|
109 | }
|
110 |
|
111 | this.scratchCanvas.width = this.scratchCanvas.height = 0;
|
112 | this.scratchCanvas = null;
|
113 | activeService = null;
|
114 | ensureOverlay().then(function () {
|
115 | if (overlayManager.active === dialog) {
|
116 | overlayManager.close(dialog);
|
117 | }
|
118 | });
|
119 | },
|
120 |
|
121 | renderPages() {
|
122 | if (this.pdfDocument.isPureXfa) {
|
123 | (0, _print_utils.getXfaHtmlForPrinting)(this.printContainer, this.pdfDocument);
|
124 | return Promise.resolve();
|
125 | }
|
126 |
|
127 | const pageCount = this.pagesOverview.length;
|
128 |
|
129 | const renderNextPage = (resolve, reject) => {
|
130 | this.throwIfInactive();
|
131 |
|
132 | if (++this.currentPage >= pageCount) {
|
133 | renderProgress(pageCount, pageCount, this.l10n);
|
134 | resolve();
|
135 | return;
|
136 | }
|
137 |
|
138 | const index = this.currentPage;
|
139 | renderProgress(index, pageCount, this.l10n);
|
140 | renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () {
|
141 | renderNextPage(resolve, reject);
|
142 | }, reject);
|
143 | };
|
144 |
|
145 | return new Promise(renderNextPage);
|
146 | },
|
147 |
|
148 | useRenderedPage() {
|
149 | this.throwIfInactive();
|
150 | const img = document.createElement("img");
|
151 | const scratchCanvas = this.scratchCanvas;
|
152 |
|
153 | if ("toBlob" in scratchCanvas) {
|
154 | scratchCanvas.toBlob(function (blob) {
|
155 | img.src = URL.createObjectURL(blob);
|
156 | });
|
157 | } else {
|
158 | img.src = scratchCanvas.toDataURL();
|
159 | }
|
160 |
|
161 | const wrapper = document.createElement("div");
|
162 | wrapper.className = "printedPage";
|
163 | wrapper.append(img);
|
164 | this.printContainer.append(wrapper);
|
165 | return new Promise(function (resolve, reject) {
|
166 | img.onload = resolve;
|
167 | img.onerror = reject;
|
168 | });
|
169 | },
|
170 |
|
171 | performPrint() {
|
172 | this.throwIfInactive();
|
173 | return new Promise(resolve => {
|
174 | setTimeout(() => {
|
175 | if (!this.active) {
|
176 | resolve();
|
177 | return;
|
178 | }
|
179 |
|
180 | print.call(window);
|
181 | setTimeout(resolve, 20);
|
182 | }, 0);
|
183 | });
|
184 | },
|
185 |
|
186 | get active() {
|
187 | return this === activeService;
|
188 | },
|
189 |
|
190 | throwIfInactive() {
|
191 | if (!this.active) {
|
192 | throw new Error("This print request was cancelled or completed.");
|
193 | }
|
194 | }
|
195 |
|
196 | };
|
197 | const print = window.print;
|
198 |
|
199 | window.print = function () {
|
200 | if (activeService) {
|
201 | console.warn("Ignored window.print() because of a pending print job.");
|
202 | return;
|
203 | }
|
204 |
|
205 | ensureOverlay().then(function () {
|
206 | if (activeService) {
|
207 | overlayManager.open(dialog);
|
208 | }
|
209 | });
|
210 |
|
211 | try {
|
212 | dispatchEvent("beforeprint");
|
213 | } finally {
|
214 | if (!activeService) {
|
215 | console.error("Expected print service to be initialized.");
|
216 | ensureOverlay().then(function () {
|
217 | if (overlayManager.active === dialog) {
|
218 | overlayManager.close(dialog);
|
219 | }
|
220 | });
|
221 | return;
|
222 | }
|
223 |
|
224 | const activeServiceOnEntry = activeService;
|
225 | activeService.renderPages().then(function () {
|
226 | return activeServiceOnEntry.performPrint();
|
227 | }).catch(function () {}).then(function () {
|
228 | if (activeServiceOnEntry.active) {
|
229 | abort();
|
230 | }
|
231 | });
|
232 | }
|
233 | };
|
234 |
|
235 | function dispatchEvent(eventType) {
|
236 | const event = document.createEvent("CustomEvent");
|
237 | event.initCustomEvent(eventType, false, false, "custom");
|
238 | window.dispatchEvent(event);
|
239 | }
|
240 |
|
241 | function abort() {
|
242 | if (activeService) {
|
243 | activeService.destroy();
|
244 | dispatchEvent("afterprint");
|
245 | }
|
246 | }
|
247 |
|
248 | function renderProgress(index, total, l10n) {
|
249 | dialog ||= document.getElementById("printServiceDialog");
|
250 | const progress = Math.round(100 * index / total);
|
251 | const progressBar = dialog.querySelector("progress");
|
252 | const progressPerc = dialog.querySelector(".relative-progress");
|
253 | progressBar.value = progress;
|
254 | l10n.get("print_progress_percent", {
|
255 | progress
|
256 | }).then(msg => {
|
257 | progressPerc.textContent = msg;
|
258 | });
|
259 | }
|
260 |
|
261 | window.addEventListener("keydown", function (event) {
|
262 | if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
|
263 | window.print();
|
264 | event.preventDefault();
|
265 |
|
266 | if (event.stopImmediatePropagation) {
|
267 | event.stopImmediatePropagation();
|
268 | } else {
|
269 | event.stopPropagation();
|
270 | }
|
271 | }
|
272 | }, true);
|
273 |
|
274 | if ("onbeforeprint" in window) {
|
275 | const stopPropagationIfNeeded = function (event) {
|
276 | if (event.detail !== "custom" && event.stopImmediatePropagation) {
|
277 | event.stopImmediatePropagation();
|
278 | }
|
279 | };
|
280 |
|
281 | window.addEventListener("beforeprint", stopPropagationIfNeeded);
|
282 | window.addEventListener("afterprint", stopPropagationIfNeeded);
|
283 | }
|
284 |
|
285 | let overlayPromise;
|
286 |
|
287 | function ensureOverlay() {
|
288 | if (!overlayPromise) {
|
289 | overlayManager = _app.PDFViewerApplication.overlayManager;
|
290 |
|
291 | if (!overlayManager) {
|
292 | throw new Error("The overlay manager has not yet been initialized.");
|
293 | }
|
294 |
|
295 | dialog ||= document.getElementById("printServiceDialog");
|
296 | overlayPromise = overlayManager.register(dialog, true);
|
297 | document.getElementById("printCancel").onclick = abort;
|
298 | dialog.addEventListener("close", abort);
|
299 | }
|
300 |
|
301 | return overlayPromise;
|
302 | }
|
303 |
|
304 | _app.PDFPrintServiceFactory.instance = {
|
305 | supportsPrinting: true,
|
306 |
|
307 | createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n) {
|
308 | if (activeService) {
|
309 | throw new Error("The print service is created and active.");
|
310 | }
|
311 |
|
312 | activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise, l10n);
|
313 | return activeService;
|
314 | }
|
315 |
|
316 | }; |
\ | No newline at end of file |