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

Print embedded PDF from browser with Javascript, HTML5, AngularJS

本文关键字:打印 嵌入式 浏览器 PDF AngularJS Javascript HTML5 使用      更新时间:2023-09-26

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

我的HTML如下所示:

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

我的JavaScript如下:

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

我的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();
      }
    };

printDocument函数取自堆栈溢出(Silent print an embedded PDF)中的一个预先存在的问题,该问题给出了打印嵌入式PDF的答案。然而,这似乎已经不起作用了。我总是对感到"不确定"

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

检查。似乎.print不存在什么的。

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

这里也有答案:从javascript嵌入标签打印Pdf

经过大量研究,我将把我学到的东西发布在这里,供未来可能发现这一点的人使用。

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

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

  • Chrome使用Adobe的查看器,该查看器不允许访问任何类型的print()方法,但可以执行嵌入PDF中的PdfActions。因此,您可以在PDF中嵌入"OpenAction",并在从任何查看这些操作的应用程序打开PDF时打印PDF调用。

  • Firefox(高于某个版本,但都是最新版本)在Windows中使用Adobe查看器,该查看器也可以识别PdfActions。然而,在OSX中,它失去了对Adobe查看器的支持,转而使用在Firefox中烘焙的查看器(pdf.js)。它不支持PdfActions。

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

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

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

-Phil

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

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

为了避免这种情况,必须直接引用同一个pdf(在这种情况下是否定的),或者将pdf转换为对象/blob url。

请参阅MDN关于创建对象/blob URL 的说明

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()

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