使用 Javascript、HTML5、AngularJS 从浏览器打印嵌入的 PDF

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26877165/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:28:02  来源:igfitidea点击:

Print embedded PDF from browser with Javascript, HTML5, AngularJS

javascripthtmlangularjspdf

提问by philhan

I'm loading a Base64 encoded PDF as a String into my JavaScript from my server. My client application is using AngularJS, HTML5.

我正在将 Base64 编码的 PDF 作为字符串从我的服务器加载到我的 JavaScript 中。我的客户端应用程序使用的是 AngularJS、HTML5。

My HTML looks like this:

我的 HTML 如下所示:

<div id="printablePdfContainer">
  <iframe id="printablePdf" width="100%" height="100%"></iframe>
</div>

My JavaScript looks like this:

我的 JavaScript 看起来像这样:

var pdfName = 'data:application/pdf;base64,' + data[0].PrintImage;
var embeddedPdf = document.getElementById('printablePdf');
embeddedPdf.setAttribute('src', pdfName);
$scope.printDocument(embeddedPdf);

My printDocumentfunction looks like this:

我的printDocument函数如下所示:

$scope.printDocument = function() {
      var test = document.getElementById('printablePdf');
      if (typeof document.getElementById('printablePdf').print === 'undefined') {

        setTimeout(function(){$scope.printDocument();}, 1000);

      } else {

        var x = document.getElementById('printablePdf');
        x.print();
      }
    };

The printDocumentfunction has been taken from a pre-existing question in stack overflow (Silent print an embedded PDF) which gives this as an answer to print an embedded PDF. However, this doesn't seem to work anymore. I'm always getting 'undefined' for the

printDocument函数取自堆栈溢出(Silent print an Embedded PDF)中的一个预先存在的问题,该问题将其作为打印嵌入 PDF 的答案。但是,这似乎不再起作用。我总是得到“未定义”的

typeof document.getElementById('printablePdf').print === 'undefined'

check. Seems like .printdoesn't exist or something.

查看。好像.print不存在什么的。

So, my question is this: How can I print an embedded PDF in HTML5, using JavaScript, and without opening a popup window?

所以,我的问题是:如何使用 JavaScript 在 HTML5 中打印嵌入的 PDF,并且不打开弹出窗口?

回答by philhan

Also answered here: Print Pdf from javascript embed tag

也在这里回答:Print Pdf from javascript embed tag

I'm going to post what I learned here after a lot of research for anyone in the future who might find this.

经过大量研究后,我将在这里发布我所学到的知识,供将来可能会发现此内容的任何人使用。

PDF's are displayed differently based on browser, browser version, browser configuration, and Operating System. There are a lot of variables so I'll talk about the most common situations here.

PDF 的显示方式因浏览器、浏览器版本、浏览器配置和操作系统而异。有很多变量,所以我将在这里讨论最常见的情况。

  • On all browsers I was unable to call any sort of print() method through Javascript, I was only able to use PdfActions. The OPENACTION would call print. I embedded these into the PDF using iText.

  • Chrome uses Adobe's viewer, which doesn't give access to any sort of print() method but does execute PdfActions embedded in the PDF. So you can embed an 'OpenAction' in a PDF and have the PDF call print whenever it's opened from any application that looks at those actions.

  • Firefox (above a certain version, all recent versions though) uses the Adobe viewer in Windows, which also recognizes PdfActions. However, in OSX it loses support for the Adobe viewer and switches to the baked in Firefox viewer (pdf.js). Which does not support PdfActions.

  • IE: I didn't really test much on IE. Mostly because I gave up on printing PDF's from Javascript after Firefox didn't work on OSX (a req. for me).

  • 在所有浏览器上,我无法通过 Javascript 调用任何类型的 print() 方法,我只能使用 PdfActions。OPENACTION 将调用打印。我使用 iText 将这些嵌入到 PDF 中。

  • Chrome 使用 Adob​​e 的查看器,它不能访问任何类型的 print() 方法,但会执行嵌入在 PDF 中的 PdfActions。因此,您可以在 PDF 中嵌入“OpenAction”,并在从查看这些操作的任何应用程序打开时打印 PDF 调用。

  • Firefox(特定版本以上,但所有最新版本)使用 Windows 中的 Adob​​e 查看器,它也识别 PdfActions。但是,在 OSX 中,它失去了对 Adob​​e 查看器的支持并切换到了 Firefox 查看器 (pdf.js)。哪个不支持 PdfActions。

  • IE:我并没有在 IE 上进行太多测试。主要是因为在 Firefox 不能在 OSX 上工作后,我放弃了从 Javascript 打印 PDF(对我来说是一个要求)。

My PDF's were being generated by a server that I control so I ended up making service changes in my server and adding a get PNG service that generated a PNG based on the same markup that the PDF generation uses. Browsers handle images much better than PDFs, which I knew going in, but hoped that I would just be able to re-use the PDF generation service since it's used elsewhere in my code.

我的 PDF 是由我控制的服务器生成的,所以我最终在我的服务器中进行了服务更改,并添加了一个 get PNG 服务,该服务根据 PDF 生成使用的相同标记生成了一个 PNG。浏览器比 PDF 处理图像要好得多,我知道 PDF 是这样处理的,但希望我能够重新使用 PDF 生成服务,因为它在我的代码中的其他地方使用过。

It doesn't answer the question, but it's all the information I have. My suggestion to anyone who might find this in the future: ditch PDF if possible in this case and go simpler. Otherwise, please update this question if you know how to call print() through Javascript in FF preview pdf viewer in OSX.

它没有回答问题,但这是我拥有的所有信息。我对将来可能会发现此问题的任何人的建议:在这种情况下,如果可能,请放弃 PDF 并变得更简单。否则,如果您知道如何在 OSX 的 FF 预览 pdf 查看器中通过 Javascript 调用 print(),请更新此问题。

-Phil

-菲尔

回答by Sam-Graham

To print a base64 pdf you need to get around the fact that data URIs have no origin and are therefore blocked by modern browers.

要打印 base64 pdf,您需要避开数据 URI 没有来源并因此被现代浏览器阻止的事实。

See the note on the date URLs page on MDN: Data URLs.

请参阅 MDN 上日期 URL 页面上的注释:数据 URL

In order to get around this have to either reference the same pdf directly, which is a no-no in this case, or convert the pdf to an object/ blob url.

为了解决这个问题,必须直接引用相同的 pdf,在这种情况下这是禁忌,或者将 pdf 转换为对象/blob url。

See MDNs notes on creating an object/blob URL

请参阅有关创建对象/blob URL 的MDN 注释

function b64toBlob(b64Data, contentType) {
 var byteCharacters = atob(b64Data)

 var byteArrays = []

 for (let offset = 0; offset < byteCharacters.length; offset += 512) {
  var slice = byteCharacters.slice(offset, offset + 512),
   byteNumbers = new Array(slice.length)
  for (let i = 0; i < slice.length; i++) {
   byteNumbers[i] = slice.charCodeAt(i)
  }
  var byteArray = new Uint8Array(byteNumbers)

  byteArrays.push(byteArray)
 }

 var blob = new Blob(byteArrays, { type: contentType })
 return blob
}

var pdfObjectUrl = URL.createObjectURL(b64toBlob(data[0].PrintImage, 'application/pdf'))
var embeddedPdf = document.getElementById('printablePdf')
embeddedPdf.setAttribute('src', pdfObjectUrl)

// Then to print
embeddedPdf.contentWindow.print()

Once the data is inside an object URL the contentWindow will not be blocked by the browsers security. The print method will exist on the contentWindow of the iframe.

一旦数据位于对象 URL 内,浏览器安全性将不会阻止 contentWindow。打印方法将存在于 iframe 的 contentWindow 中。

回答by Cisco505

function b64toBlob(b64Data, contentType) {
 var byteCharacters = atob(b64Data)

 var byteArrays = []

 for (let offset = 0; offset < byteCharacters.length; offset += 512) {
  var slice = byteCharacters.slice(offset, offset + 512),
   byteNumbers = new Array(slice.length)
  for (let i = 0; i < slice.length; i++) {
   byteNumbers[i] = slice.charCodeAt(i)
  }
  var byteArray = new Uint8Array(byteNumbers)

  byteArrays.push(byteArray)
 }

 var blob = new Blob(byteArrays, { type: contentType })
 return blob
}

var pdfObjectUrl = URL.createObjectURL(b64toBlob(data[0].PrintImage, 'application/pdf'))
var embeddedPdf = document.getElementById('printablePdf')
embeddedPdf.setAttribute('src', pdfObjectUrl)

// Then to print
embeddedPdf.contentWindow.print()