打印pdf而不是在视觉上打开它

时间:2016-07-28 14:46:59

标签: javascript jquery pdf printing

我想要构建的是通过单击按钮我想触发PDF文件的打印,但不打开它。

+-----------+
| Print PDF |
+-----------+
     ^ Click *---------> printPdf(pdfUrl)

我第一次尝试它的方法是使用iframe:

var $iframe = null;

// This is supposed to fix the onload bug on IE, but it's 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年,我觉得在整个浏览器中实施这仍然很难。

3 个答案:

答案 0 :(得分:15)

更新:此link详细介绍了一个优雅的解决方案,其中包括编辑第一页的页面属性并在页面打开时添加操作。适用于所有浏览器(因为浏览器将执行放置在actions部分中的JavaScript)。需要Adobe Acrobat Pro。

2016年似乎没有给打印问题带来新的进步。有一个类似的问题,并使打印跨浏览器我使用PDF.JS解决它,但不得不对源进行单线程添加(他们要求你在任何方面建立它)。

这个想法:

  • https://mozilla.github.io/pdf.js/getting_started/#download下载预构建的稳定版本,并添加&#34; build&#34;和&#34; web&#34;文件夹到项目。
  • 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();
})();
  • 然后我可以在iframe的src中调用viewer.html?file=并隐藏它。由于Firefox,不得不使用可见性而不是显示样式:

    <iframe src="web/viewer.html?file=abcde.pdf" style="visibility: hidden">
    

结果:在短暂延迟后显示打印对话框,其中PDF对用户隐藏。

在Chrome,IE,Firefox中测试。

答案 1 :(得分:6)

花了几个小时试图弄清楚这个,我在这里搜索了很多......

HTML5 Web API spec for Printing表示其中一个printing steps必须向正在打印的文档的窗口对象触发beforeprint,一个简单事件(不可取消的事件)以及任何嵌套的浏览上下文,这与iframe相关,以允许在打印之前更改Document。此步骤是浏览器的内部步骤,而不是您可以调整的内容。在此过程中,浏览器的打印对话框有时会显示文件的预览(Chrome会执行此操作)...因此,如果您的目标是永远不会将文件显示给查看者,则可能会被卡住。

最接近实现这一目标的方法是创建一个index.html文件,其中包含一个按钮,其中包含提供上下文的data- *属性。将data-print-resource-uri属性中的path / filename.ext更改为您自己的本地文件。

<!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使其正常工作,则可能会在您想要的跨浏览器方法中发挥最佳效果。

我找到了一些关于这个主题的参考资料,可能会有所帮助:

答案 2 :(得分:0)

我将在这里发布 IE 11 上 OP 函数的修改功能

    printPdf: function (url) {
        $('#mainLoading').show();
        let iframe = $('#idPdf');
        if (iframe) {
            iframe.remove();
        }

        iframe = $('<iframe>', {
            style: "display:none",
            id: "idPdf"
        });

        $("body").prepend(iframe);
        $('#idPdf').on("load", function(){
            utilities.printIframeOnLoad()
       })

        utilities.getAsyncBuffer(url, function(response){
            let path = utilities.getPdfLocalPath(response);
            $('#idPdf').attr('src', path);
        })
    },

     printIframeOnLoad: function () {
        let iframe = $('#idPdf');
        if (!iframe.attr("src")) { return; }

        var pdf = iframe.get(0);
        pdf.focus();
        $('#mainLoading').hide();
        pdf.contentWindow.print();
    },


    getPdfLocalPath: function (data) {
        var filename = "Application_" + utilities.uuidv4() + ".pdf";
        var blob = new Blob([data], { type: 'application/pdf' });
        if (window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
            return filename;
        }
        else {
            let url = window.URL || window.webkitURL;
            let href = url.createObjectURL(blob);
            return href;
        }
    },

    getAsyncBuffer: function (uriPath, callback) {

        var req = new XMLHttpRequest();
        req.open("GET", uriPath, true);
        req.responseType = "blob";
        req.onreadystatechange = function () {
            if (req.readyState === 4 && req.status === 200) {
                callback(req.response);
            }
        };
        req.send();
    }