Подтвердить что ты не робот

Распечатайте 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 году, и мне кажется, что это все еще больно для реализации в браузерах.

4b9b3361

Ответ 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 может работать лучше всего в кросс-браузере, который вам нужен.

Я нашел несколько ссылок на эту тему, которые могут быть полезны: