|
|
@ -35,13 +35,10 @@ |
|
|
|
|
|
|
|
|
|
|
|
var activeService = null; |
|
|
|
var activeService = null; |
|
|
|
|
|
|
|
|
|
|
|
// Using one canvas for all paint operations -- painting one canvas at a time.
|
|
|
|
// Renders the page to the canvas of the given print service, and returns
|
|
|
|
var scratchCanvas = null; |
|
|
|
// the suggested dimensions of the output page.
|
|
|
|
|
|
|
|
function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size) { |
|
|
|
function renderPage(pdfDocument, pageNumber, size, wrapper) { |
|
|
|
var scratchCanvas = activeService.scratchCanvas; |
|
|
|
if (!scratchCanvas) { |
|
|
|
|
|
|
|
scratchCanvas = document.createElement('canvas'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The size of the canvas in pixels for printing.
|
|
|
|
// The size of the canvas in pixels for printing.
|
|
|
|
var PRINT_RESOLUTION = 150; |
|
|
|
var PRINT_RESOLUTION = 150; |
|
|
@ -50,9 +47,8 @@ |
|
|
|
scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); |
|
|
|
scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); |
|
|
|
|
|
|
|
|
|
|
|
// The physical size of the img as specified by the PDF document.
|
|
|
|
// The physical size of the img as specified by the PDF document.
|
|
|
|
var img = document.createElement('img'); |
|
|
|
var width = Math.floor(size.width * CSS_UNITS) + 'px'; |
|
|
|
img.style.width = Math.floor(size.width * CSS_UNITS) + 'px'; |
|
|
|
var height = Math.floor(size.height * CSS_UNITS) + 'px'; |
|
|
|
img.style.height = Math.floor(size.height * CSS_UNITS) + 'px'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ctx = scratchCanvas.getContext('2d'); |
|
|
|
var ctx = scratchCanvas.getContext('2d'); |
|
|
|
ctx.save(); |
|
|
|
ctx.save(); |
|
|
@ -68,23 +64,11 @@ |
|
|
|
intent: 'print' |
|
|
|
intent: 'print' |
|
|
|
}; |
|
|
|
}; |
|
|
|
return pdfPage.render(renderContext).promise; |
|
|
|
return pdfPage.render(renderContext).promise; |
|
|
|
}).then(function() { |
|
|
|
}).then(function () { |
|
|
|
if (!activeService) { |
|
|
|
return { |
|
|
|
return Promise.reject(new Error('cancelled')); |
|
|
|
width: width, |
|
|
|
} |
|
|
|
height: height, |
|
|
|
if (('toBlob' in scratchCanvas) && |
|
|
|
}; |
|
|
|
!pdfjsLib.PDFJS.disableCreateObjectURL) { |
|
|
|
|
|
|
|
scratchCanvas.toBlob(function (blob) { |
|
|
|
|
|
|
|
img.src = URL.createObjectURL(blob); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
img.src = scratchCanvas.toDataURL(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
wrapper.appendChild(img); |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
img.onload = resolve; |
|
|
|
|
|
|
|
img.onerror = reject; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -92,14 +76,16 @@ |
|
|
|
this.pdfDocument = pdfDocument; |
|
|
|
this.pdfDocument = pdfDocument; |
|
|
|
this.pagesOverview = pagesOverview; |
|
|
|
this.pagesOverview = pagesOverview; |
|
|
|
this.printContainer = printContainer; |
|
|
|
this.printContainer = printContainer; |
|
|
|
this.wrappers = []; |
|
|
|
|
|
|
|
this.currentPage = -1; |
|
|
|
this.currentPage = -1; |
|
|
|
|
|
|
|
// The temporary canvas where renderPage paints one page at a time.
|
|
|
|
|
|
|
|
this.scratchCanvas = document.createElement('canvas'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PDFPrintService.prototype = { |
|
|
|
PDFPrintService.prototype = { |
|
|
|
layout: function () { |
|
|
|
layout: function () { |
|
|
|
|
|
|
|
this.throwIfInactive(); |
|
|
|
|
|
|
|
|
|
|
|
var pdfDocument = this.pdfDocument; |
|
|
|
var pdfDocument = this.pdfDocument; |
|
|
|
var printContainer = this.printContainer; |
|
|
|
|
|
|
|
var body = document.querySelector('body'); |
|
|
|
var body = document.querySelector('body'); |
|
|
|
body.setAttribute('data-pdfjsprinting', true); |
|
|
|
body.setAttribute('data-pdfjsprinting', true); |
|
|
|
|
|
|
|
|
|
|
@ -130,29 +116,23 @@ |
|
|
|
'@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' + |
|
|
|
'@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' + |
|
|
|
'}'; |
|
|
|
'}'; |
|
|
|
body.appendChild(this.pageStyleSheet); |
|
|
|
body.appendChild(this.pageStyleSheet); |
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0, ii = this.pagesOverview.length; i < ii; ++i) { |
|
|
|
|
|
|
|
var wrapper = document.createElement('div'); |
|
|
|
|
|
|
|
printContainer.appendChild(wrapper); |
|
|
|
|
|
|
|
this.wrappers[i] = wrapper; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
destroy: function () { |
|
|
|
destroy: function () { |
|
|
|
|
|
|
|
if (activeService !== this) { |
|
|
|
|
|
|
|
// |activeService| cannot be replaced without calling destroy() first,
|
|
|
|
|
|
|
|
// so if it differs then an external consumer has a stale reference to
|
|
|
|
|
|
|
|
// us.
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
this.printContainer.textContent = ''; |
|
|
|
this.printContainer.textContent = ''; |
|
|
|
this.wrappers = null; |
|
|
|
|
|
|
|
if (this.pageStyleSheet && this.pageStyleSheet.parentNode) { |
|
|
|
if (this.pageStyleSheet && this.pageStyleSheet.parentNode) { |
|
|
|
this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet); |
|
|
|
this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet); |
|
|
|
this.pageStyleSheet = null; |
|
|
|
this.pageStyleSheet = null; |
|
|
|
} |
|
|
|
} |
|
|
|
if (activeService !== this) { |
|
|
|
this.scratchCanvas.width = this.scratchCanvas.height = 0; |
|
|
|
return; // no need to clean up shared resources
|
|
|
|
this.scratchCanvas = null; |
|
|
|
} |
|
|
|
|
|
|
|
activeService = null; |
|
|
|
activeService = null; |
|
|
|
if (scratchCanvas) { |
|
|
|
|
|
|
|
scratchCanvas.width = scratchCanvas.height = 0; |
|
|
|
|
|
|
|
scratchCanvas = null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ensureOverlay().then(function () { |
|
|
|
ensureOverlay().then(function () { |
|
|
|
if (OverlayManager.active !== 'printServiceOverlay') { |
|
|
|
if (OverlayManager.active !== 'printServiceOverlay') { |
|
|
|
return; // overlay was already closed
|
|
|
|
return; // overlay was already closed
|
|
|
@ -164,10 +144,7 @@ |
|
|
|
renderPages: function () { |
|
|
|
renderPages: function () { |
|
|
|
var pageCount = this.pagesOverview.length; |
|
|
|
var pageCount = this.pagesOverview.length; |
|
|
|
var renderNextPage = function (resolve, reject) { |
|
|
|
var renderNextPage = function (resolve, reject) { |
|
|
|
if (activeService !== this) { |
|
|
|
this.throwIfInactive(); |
|
|
|
reject(new Error('cancelled')); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (++this.currentPage >= pageCount) { |
|
|
|
if (++this.currentPage >= pageCount) { |
|
|
|
renderProgress(pageCount, pageCount); |
|
|
|
renderProgress(pageCount, pageCount); |
|
|
|
resolve(); |
|
|
|
resolve(); |
|
|
@ -175,12 +152,68 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
var index = this.currentPage; |
|
|
|
var index = this.currentPage; |
|
|
|
renderProgress(index, pageCount); |
|
|
|
renderProgress(index, pageCount); |
|
|
|
renderPage(this.pdfDocument, index + 1, |
|
|
|
renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index]) |
|
|
|
this.pagesOverview[index], this.wrappers[index]).then( |
|
|
|
.then(this.useRenderedPage.bind(this)) |
|
|
|
function () { renderNextPage(resolve, reject); }, reject); |
|
|
|
.then(function () { |
|
|
|
|
|
|
|
renderNextPage(resolve, reject); |
|
|
|
|
|
|
|
}, reject); |
|
|
|
}.bind(this); |
|
|
|
}.bind(this); |
|
|
|
return new Promise(renderNextPage); |
|
|
|
return new Promise(renderNextPage); |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useRenderedPage: function (printItem) { |
|
|
|
|
|
|
|
this.throwIfInactive(); |
|
|
|
|
|
|
|
var img = document.createElement('img'); |
|
|
|
|
|
|
|
img.style.width = printItem.width; |
|
|
|
|
|
|
|
img.style.height = printItem.height; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var scratchCanvas = this.scratchCanvas; |
|
|
|
|
|
|
|
if (('toBlob' in scratchCanvas) && |
|
|
|
|
|
|
|
!pdfjsLib.PDFJS.disableCreateObjectURL) { |
|
|
|
|
|
|
|
scratchCanvas.toBlob(function (blob) { |
|
|
|
|
|
|
|
img.src = URL.createObjectURL(blob); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
img.src = scratchCanvas.toDataURL(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var wrapper = document.createElement('div'); |
|
|
|
|
|
|
|
wrapper.appendChild(img); |
|
|
|
|
|
|
|
this.printContainer.appendChild(wrapper); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new Promise(function (resolve, reject) { |
|
|
|
|
|
|
|
img.onload = resolve; |
|
|
|
|
|
|
|
img.onerror = reject; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
performPrint: function () { |
|
|
|
|
|
|
|
this.throwIfInactive(); |
|
|
|
|
|
|
|
return new Promise(function (resolve) { |
|
|
|
|
|
|
|
// Push window.print in the macrotask queue to avoid being affected by
|
|
|
|
|
|
|
|
// the deprecation of running print() code in a microtask, see
|
|
|
|
|
|
|
|
// https://github.com/mozilla/pdf.js/issues/7547.
|
|
|
|
|
|
|
|
setTimeout(function () { |
|
|
|
|
|
|
|
if (!this.active) { |
|
|
|
|
|
|
|
resolve(); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
print.call(window); |
|
|
|
|
|
|
|
// Delay promise resolution in case print() was not synchronous.
|
|
|
|
|
|
|
|
setTimeout(resolve, 20); // Tidy-up.
|
|
|
|
|
|
|
|
}.bind(this), 0); |
|
|
|
|
|
|
|
}.bind(this)); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get active() { |
|
|
|
|
|
|
|
return this === activeService; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throwIfInactive: function () { |
|
|
|
|
|
|
|
if (!this.active) { |
|
|
|
|
|
|
|
throw new Error('This print request was cancelled or completed.'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -191,7 +224,9 @@ |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
ensureOverlay().then(function () { |
|
|
|
ensureOverlay().then(function () { |
|
|
|
OverlayManager.open('printServiceOverlay'); |
|
|
|
if (activeService) { |
|
|
|
|
|
|
|
OverlayManager.open('printServiceOverlay'); |
|
|
|
|
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
@ -199,8 +234,26 @@ |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
if (!activeService) { |
|
|
|
if (!activeService) { |
|
|
|
console.error('Expected print service to be initialized.'); |
|
|
|
console.error('Expected print service to be initialized.'); |
|
|
|
|
|
|
|
if (OverlayManager.active === 'printServiceOverlay') { |
|
|
|
|
|
|
|
OverlayManager.close('printServiceOverlay'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
activeService.renderPages().then(startPrint, abort); |
|
|
|
var activeServiceOnEntry = activeService; |
|
|
|
|
|
|
|
activeService.renderPages().then(function () { |
|
|
|
|
|
|
|
return activeServiceOnEntry.performPrint(); |
|
|
|
|
|
|
|
}).catch(function () { |
|
|
|
|
|
|
|
// Ignore any error messages.
|
|
|
|
|
|
|
|
}).then(function () { |
|
|
|
|
|
|
|
// aborts acts on the "active" print request, so we need to check
|
|
|
|
|
|
|
|
// whether the print request (activeServiceOnEntry) is still active.
|
|
|
|
|
|
|
|
// Without the check, an unrelated print request (created after aborting
|
|
|
|
|
|
|
|
// this print request while the pages were being generated) would be
|
|
|
|
|
|
|
|
// aborted.
|
|
|
|
|
|
|
|
if (activeServiceOnEntry.active) { |
|
|
|
|
|
|
|
abort(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -210,19 +263,6 @@ |
|
|
|
window.dispatchEvent(event); |
|
|
|
window.dispatchEvent(event); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function startPrint() { |
|
|
|
|
|
|
|
// Push window.print in the macrotask queue to avoid being affected by
|
|
|
|
|
|
|
|
// the deprecation of running print() code in a microtask, see
|
|
|
|
|
|
|
|
// https://github.com/mozilla/pdf.js/issues/7547.
|
|
|
|
|
|
|
|
setTimeout(function() { |
|
|
|
|
|
|
|
if (!activeService) { |
|
|
|
|
|
|
|
return; // Print task cancelled by user.
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
print.call(window); |
|
|
|
|
|
|
|
setTimeout(abort, 20); // Tidy-up
|
|
|
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function abort() { |
|
|
|
function abort() { |
|
|
|
if (activeService) { |
|
|
|
if (activeService) { |
|
|
|
activeService.destroy(); |
|
|
|
activeService.destroy(); |
|
|
|