Распечатайте pdf без визуального открытия
Вещь, которую я хочу создать, заключается в том, что нажав кнопку, я хочу запустить печать PDF файла, но не открывая его.
+-----------+
| Print PDF |
+-----------+
^ Click *---------> printPdf(pdfUrl)
Как я впервые попытался использовать iframe:
var $iframe = null;
// This is supposed to fix the onload bug on IE, but it not fired
window.printIframeOnLoad = function() {
if (!$iframe.attr("src")) { return; }
var PDF = $iframe.get(0);
PDF.focus();
try {
// This doesn't work on IE anyways
PDF.contentWindow.print();
// I think on IE we can do something like this:
// PDF.document.execCommand("print", false, null);
} catch (e) {
// If we can't print it, we just open it in the current window
window.location = url;
}
};
function printPdf(url) {
if ($iframe) {
$iframe.remove();
}
$iframe = $('<iframe>', {
class: "hide",
id: "idPdf",
// Supposed to be a fix for IE
onload: "window.printIframeOnLoad()",
src: url
});
$("body").prepend($iframe);
}
Это работает на Safari (настольном и iOS) и Chrome (можем ли мы обобщить его, возможно, на webkit?).
В Firefox PDF.contentWindow.print()
заканчивается ошибкой permission denied
(даже файл pdf загружается из того же домена).
В IE (11) обработчик onload
просто не работает.
Теперь, мой вопрос: есть ли еще один лучший способ распечатать PDF без визуального открытия его пользователю?
Здесь кросс-браузер очень важен. Мы должны поддерживать как можно больше браузеров.
Какой лучший способ достичь этого? Является ли мой старт хорошим? Как его завершить?
Теперь мы находимся в 2016 году, и мне кажется, что это все еще больно для реализации в браузерах.
Ответы
Ответ 1
UPDATE. Эта ссылка подробно описывает элегантное решение, которое включает в себя редактирование свойств страницы для первой страницы и добавление действие на странице Open. Работает во всех браузерах (так как браузеры будут выполнять JavaScript, размещенный в разделе действия). Требуется Adobe Acrobat Pro.
Кажется, что 2016 год не принесет новых успехов в проблеме печати. Если бы аналогичная проблема и сделать кросс-браузер печати я решил, используя PDF.JS, но пришлось сделать однострочное дополнение к источнику (они просят вас строить на нем в любом случае).
Идея:
- Загрузите предварительно построенный стабильный выпуск из https://mozilla.github.io/pdf.js/getting_started/#download и добавьте в проект папки "build" и "web".
- Файл
viewer.html
- это то, что выделяет PDF файлы с богатым интерфейсом и содержит функции печати. Я добавил ссылку в этот файл на свой собственный JavaScript, который просто запускает window.print() после задержки.
Ссылка, добавленная к просмотру:
<script src="viewer.js"></script>
<!-- this autoPrint.js was added below viewer.js -->
<script src="autoPrint.js"></script>
</head>
autoPrint.js
javascript:
(function () {
function printWhenReady() {
if (PDFViewerApplication.initialized) {
window.print();
}
else {
window.setTimeout(printWhenReady, 3000);
}
};
printWhenReady();
})();
-
Затем я мог бы вызвать вызовы viewer.html?file=
в src iframe и скрыть его. Приходилось использовать видимость, а не отображать стили из-за Firefox:
<iframe src="web/viewer.html?file=abcde.pdf" style="visibility: hidden">
Результат: диалоговое окно печати появилось после небольшой задержки, когда PDF был скрыт от пользователя.
Протестировано в Chrome, IE, Firefox.
Ответ 2
Проведя последние пару часов, пытаясь понять это, и много поисков здесь, я определил...
Спецификация веб-API HTML5 для печати указывает, что один из printing steps
должен запустить beforeprint, простое событие (событие, которое не отменяется), к объекту окна печатаемого документа (а также любые вложенные контексты просмотра, это относится к iframes), чтобы разрешить для внесения изменений в документ перед печатью. Этот шаг является внутренним для браузера, а не тем, что вы сможете настроить. Во время этого процесса диалог печати браузера иногда показывает предварительный просмотр файла (это делает Chrome)... поэтому, если ваша цель - никогда не отображать файл для зрителя, который вы могли бы застрять.
Ближе всего к этому я пришел, создав файл index.html
, в котором есть кнопка, содержащая атрибуты data- *, которые предоставляют контекст. Измените путь /filename.ext в атрибуте data-print-resource-uri
на собственный локальный файл.
<!DOCTYPE html>
<html>
<head>
<title>Express</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>Express</h1>
<p>Welcome to Express</p>
<button name="printFile" id="printFile" data-print-resource-uri="/binary/paycheckStub.pdf" data-print-resource-type="application/pdf">Print File</button>
<iframe name="printf" id="printf" frameborder="0"></iframe>
<script src="/javascripts/print.js"></script>
</body>
</html>
Затем в файле print.js
я попробовал несколько вещей, но никогда не получил его работу (оставив разные вещи, с которыми я играл в комментариях).
// Reference vars
var printButton = document.getElementById('printFile');
var printFrame = document.getElementById('printf');
// onClick handler
printButton.onclick = function(evt) {
console.log('evt: ', evt);
printBlob('printf', printButton.getAttribute('data-print-resource-uri'), printButton.getAttribute('data-print-resource-type'));
}
// Fetch the file from the server
function getFile( fileUri, fileType, callback ) {
var xhr = new XMLHttpRequest();
xhr.open('GET', fileUri);
xhr.responseType = 'blob';
xhr.onload = function(e) {
// Success
if( 200 === this.status ) {
// Store as a Blob
var blob = new Blob([this.response], {type: fileType});
// Hang a URL to it
blob = URL.createObjectURL(blob);
callback(blob);
} else {
console.log('Error Status: ', this.status);
}
};
xhr.send();
}
function printBlob(printFrame, fileUri, fileType) {
// Debugging
console.log('inside of printBlob');
console.log('file URI: ', fileUri);
console.log('file TYPE: ', fileType);
// Get the file
getFile( fileUri, fileType, function(data) {
loadAndPrint(printFrame, data, fileType);
});
}
function loadAndPrint(printFrame, file, type) {
// Debugging
console.log('printFrame: ', printFrame);
console.log('file: ', file);
window.frames[printFrame].src = file;
window.frames[printFrame].print();
/*
// Setup the print window content
var windowContent = '<!DOCTYPE html>';
windowContent += '<html>'
windowContent += '<head><title>Print canvas</title></head>';
windowContent += '<body>'
windowContent += '<embed src="' + file + '" type="' + type + '">';
windowContent += '</body>';
windowContent += '</html>';
// Setup the print window
var printWin = window.open('','','width=340,height=260');
printWin.document.open();
printWin.document.write(windowContent);
printWin.document.close();
printWin.focus();
printWin.print();
printWin.close();
*/
}
Я думаю, что если вы можете заставить его работать правильно, Blob
может работать лучше всего в кросс-браузере, который вам нужен.
Я нашел несколько ссылок на эту тему, которые могут быть полезны: