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

时间:2014-11-12 00:28:37

标签: javascript html html5 angularjs pdf

我将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 a embedded PDF)中的预先存在的问题,这是打印嵌入式pdf的答案。但是,这似乎不再起作用了。我总是得到“未定义的”#39;对于

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

检查。似乎.print不存在或其他什么。

所以,我的问题是:如何使用Javascript在HTML5中打印嵌入式PDF,而无需打开弹出窗口?

此致 菲尔

3 个答案:

答案 0 :(得分:13)

此处也回答:Print Pdf from javascript embed tag

我将在经过大量研究之后发布我在这里学到的知识,以及将来可能会发现这一点的人。

根据浏览器,浏览器版本,浏览器配置和操作系统,PDF的显示方式不同。有很多变量,所以我会谈谈这里最常见的情况。

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

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

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

  • IE:我对IE没有太多考试。主要是因为我在Firefox无法在OSX上工作后放弃了从Javascript打印PDF(对我来说是一个要求)。

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

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

-Phil

答案 1 :(得分:0)

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

请参阅MDN上日期网址页面上的说明:Data URLs

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

请参阅creating an object/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()

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

答案 2 :(得分:0)

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