直接从 JavaScript 打印 PDF

Posted

技术标签:

【中文标题】直接从 JavaScript 打印 PDF【英文标题】:Print PDF directly from JavaScript 【发布时间】:2013-04-20 19:25:24 【问题描述】:

我正在构建一个 html 格式的 PDF 列表。在列表中,我想包括一个下载链接和一个打印按钮/链接。有什么方法可以直接打开 PDF 的“打印”对话框,而无需用户查看 PDF 或打开 PDF 查看器?

将 PDF 下载到隐藏的 iframe 并触发它使用 javascript 打印的一些变体?

【问题讨论】:

【参考方案1】:

基于下面的 cmets,它不再适用于现代浏览器 这个问题展示了一种可能对您有帮助的方法:Silent print an embedded PDF

它使用<embed>标签将PDF嵌入到文档中:

<embed
    type="application/pdf"
    src="path_to_pdf_document.pdf"
    id="pdfDocument"
    
     />

然后在加载 PDF 时在 Javascript 中对元素调用 .print() 方法:

function printDocument(documentId) 
    var doc = document.getElementById(documentId);

    //Wait until PDF is ready to print    
    if (typeof doc.print === 'undefined')     
        setTimeout(function()printDocument(documentId);, 1000);
     else 
        doc.print();
    

您可以将嵌入嵌入到隐藏的 iframe 中并从那里打印出来,从而为您提供无缝体验。

【讨论】:

此解决方案不起作用...我的 Chrome FF 权限被拒绝 如果嵌入的文档位于不同的域中,这将不起作用。 更容易将 javascript 添加到 pdf 以在呈现时打印。这就是谷歌文档所做的。这种方式要么是浏览器加载并打印它,要么是 adobe 插件。 是的,我在所有未定义 print() 方法的浏览器上都遇到了这个问题。这种方法过时了吗?还有其他解决方案吗? 这不再有效。 Chrome 最新版本,同一域上的 PDF。 @nullability 如果您找不到解决方法,请进行编辑并明确说明所写的内容在过去是正确的,但不再有效,这样人们就不会浪费时间尝试了。【参考方案2】:

这是一个从 iframe 打印 PDF 的功能。

您只需将 PDF 的 URL 传递给函数。加载 PDF 后,它将创建一个 iframe 并触发打印。

请注意,该函数不会破坏 iframe。相反,它会在每次调用函数时重用它。很难销毁 iframe,因为在打印完成之前需要它,并且 print 方法没有回调支持(据我所知)。

printPdf = function (url) 
  var iframe = this._printIframe;
  if (!this._printIframe) 
    iframe = this._printIframe = document.createElement('iframe');
    document.body.appendChild(iframe);

    iframe.style.display = 'none';
    iframe.onload = function() 
      setTimeout(function() 
        iframe.focus();
        iframe.contentWindow.print();
      , 1);
    ;
  

  iframe.src = url;

【讨论】:

谢谢你,因为你帮我解决了一个大问题:没有setTimeout,打印功能有时会失败。不知道为什么,希望有人能找出来。 print 方法确实有回调支持,但是当你在 2014 年写这个答案时它还没有得到广泛的支持。不过现在是;所有主要桌面浏览器的最新版本都支持onafterprint。我有点担心重用 iframe 可能会引入竞争条件,即有人快速单击两个按钮并最终打印第二个 PDF 两次,因为在第一个打印对话框出现之前 iframe URL 已经被换掉。 如果 iframe 内容不是来自同一来源,Chrome 会阻止 .print() 方法。不幸的是,截至 2021 年无法使用【参考方案3】:

您可以使用 Print.js (npm install print-js)。解压后为 128kB,您可以在 http://printjs.crabbly.com/ 找到文档。

但它不能在 IE 上打印,在这种情况下,您必须下载 PDF。

$http(
    url: "",
    method: "GET",
    headers: 
        "Content-type": "application/pdf"
    ,
    responseType: "arraybuffer"
).success(function (data, status, headers, config) 
    var pdfFile = new Blob([data], 
        type: "application/pdf"
    );
    var pdfUrl = URL.createObjectURL(pdfFile);
    //window.open(pdfUrl);
    printJS(pdfUrl);
    //var printwWindow = $window.open(pdfUrl);
    //printwWindow.print();
).error(function (data, status, headers, config) 
    alert("Sorry, something went wrong")
);

【讨论】:

不在 IE、Edge 或 Firefox 上打印 PDF。 今天尝试使用 jQuery get 从服务器获取 pdf 的字节,然后如上所述创建 blob 和“createOvjectURL”。在这种情况下,PrintJS 不会显示打印对话框。 :) 我可以单击打印多个pdf文件吗? 刚刚尝试了演示页面。它在 Firefox 中打印【参考方案4】:

https://github.com/mozilla/pdf.js/

现场演示http://mozilla.github.io/pdf.js/

这可能是你想要的,但我看不出这有什么意义,因为现代浏览器包含这样的功能,而且它在低功率设备上运行非常慢,比如移动设备,顺便说一下,有自己的优化插件和应用程序。

【讨论】:

Pdf.js 在打印大文档时也非常慢,比如 80MB+【参考方案5】:

我使用此功能从服务器下载pdf流。

function printPdf(url) 
        var iframe = document.createElement('iframe');
        // iframe.id = 'pdfIframe'
        iframe.className='pdfIframe'
        document.body.appendChild(iframe);
        iframe.style.display = 'none';
        iframe.onload = function () 
            setTimeout(function () 
                iframe.focus();
                iframe.contentWindow.print();
                URL.revokeObjectURL(url)
                // document.body.removeChild(iframe)
            , 1);
        ;
        iframe.src = url;
        // URL.revokeObjectURL(url)
    

【讨论】:

【参考方案6】:

从base64字符串打印pdf的跨浏览器解决方案:

Chrome:打印窗口已打开 FF:带有 pdf 的新标签页已打开 IE11:打开/保存提示已打开

.

const blobPdfFromBase64String = base64String => 
   const byteArray = Uint8Array.from(
     atob(base64String)
       .split('')
       .map(char => char.charCodeAt(0))
   );
  return new Blob([byteArray],  type: 'application/pdf' );
;

const isIE11 = !!(window.navigator && window.navigator.msSaveOrOpenBlob); // or however you want to check it

const printPDF = blob => 
   try 
     isIE11
       ? window.navigator.msSaveOrOpenBlob(blob, 'documents.pdf')
       : printJS(URL.createObjectURL(blob)); // http://printjs.crabbly.com/
    catch (e) 
     throw PDFError;
   
;

printPDF(blobPdfFromBase64String(base64String))

奖励 - 在 IE11 的新选项卡中打开 blob 文件

如果您能够在服务器上对 base64 字符串进行一些预处理,您可以在某个 url 下公开它并使用printJS 中的链接:)

【讨论】:

【参考方案7】:

@Nicolas BADIA 回答的简化:

function printPDF (url)

    let pdfFrame = document.body.appendChild(document.createElement('iframe'));
    pdfFrame.style.display = 'none';
    pdfFrame.onload = () => (void pdfFrame.contentWindow.print());
    pdfFrame.src = url;

【讨论】:

【参考方案8】:

您可以使用fetch下载pdf文件,并使用Print.js进行打印

fetch("url").then(function (response) 
    response.blob().then(function (blob) 
        var reader = new FileReader();
        reader.onload = function () 

            //Remove the data:application/pdf;base64,
            printJS(
                printable: reader.result.substring(28),
                type: 'pdf',
                base64: true
            );
        ;
        reader.readAsDataURL(blob);
    )
);

【讨论】:

以上是关于直接从 JavaScript 打印 PDF的主要内容,如果未能解决你的问题,请参考以下文章

使用javascript打印到打印机时打印标题

如何使用JavaScript从浏览器打印图像

从 MySQL 获取查询并将其打印到 javascript 日历中

如何使用 jquery\javascript 从 firefox 浏览器打印 PDF 文档?

编写代码以打印从 1 到 `num` 的所有数字 JavaScript

从 javascript 调用 Google 云打印/搜索 API