从 javascript 触发 base64 编码 PDF 的打印预览

Posted

技术标签:

【中文标题】从 javascript 触发 base64 编码 PDF 的打印预览【英文标题】:Trigger print preview of base64 encoded PDF from javascript 【发布时间】:2017-03-21 01:06:49 【问题描述】:

我已经环顾 *** 一段时间,试图找到一种方法来做到这一点,但找不到合适的答案。我需要能够通过 base64 编码的字符串在新窗口或 iframe 中加载 PDF,并在加载后立即触发它的打印预览。我可以使用这两种方法轻松加载 PDF,但实际上无法正确显示打印预览。这是我尝试过的:

    在新窗口中使用embed 元素。调用 window.print() 是空白的,即使在内容加载之后也是如此。 使用隐藏的、动态创建的iframesrc="data:application/pdf;base64,JVBERi0..." 并调用myFrame.contentWindow.print()。但这会产生 CORS 错误。我不知道为什么,因为我没有通过 iframe 加载新域,只是内容。 打开一个新窗口,其中只有一个iframe 元素,如#2 中的元素,并在整个窗口上调用打印。这也显示了一个空白的白页。 使用数据 uri 打开一个新窗口并打印它。 window.open('data:application/pdf;base64,JVBERi0...').print();。这也不起作用,因为它甚至根本不显示打印预览。我也尝试过使用setTimeout 延迟它,但这也无济于事。

此时我很困惑为什么这些都不起作用,特别是因为在 Chrome 中它显示的自定义菜单栏是这样的:

如果我点击那里的实际打印图标,打印预览是完美的。当我单击该按钮时,无论 Chrome 正在做什么,这正是我想要完成的。反正有触发该功能吗?还是有另一种方法来完成我想要的?澄清一下,我只需要它在 Chrome 中工作,我不需要担心其他浏览器。

【问题讨论】:

你设法让它工作了吗?我尝试了同样的方法似乎没有任何效果 @db306 不,我真的不认为这是可能的,我已经尝试了我能想到的一切。 Chrome 中的 PDF 查看器实际上是一个插件,我认为不可能通过 javascript 与之交互。我认为使用 PDF.js 可能可以实现这一点,但我还没有时间尝试实现它 我实际上设法让它在弹出窗口上打印,但是,该函数会很快被触发,并且鉴于每个浏览器,我无法在 pdf 格式化程序上添加事件侦听器有不同的读者。我可以让它工作的唯一方法是将 pdf 文件保存在服务器上,在隐藏的 iframe 上提供 pdf 并在 iframe 加载后打印。希望这对某人有所帮助。谢谢 这适用于使用 iframe 的 chrome,但我在使用 Safari 时遇到问题,它会在 PDF 呈现之前尝试打印,并且 onload 不起作用 【参考方案1】:

这是第 3 点的解决方案:

打开一个新窗口,其中只有一个 iframe 元素,如 #2 中的那个,并在整个窗口上调用打印。这也显示了一个空白的白页。

在您的情况下,它会引发 CORS 错误,因为对于 iframe src,您提供的是 base64String 而不是 URL。这是你可以做的事情

    获取 base64String,将其转换为 Blob 从 Blob 生成 URL 将生成的 URL 提供给 iframe。 之后,您可以使用iframe.contentWindow.print() 打印内容;

这是将base64转换为Blob的代码

'use strict';

const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => 
    const byteCharacters = atob(b64Data);
    const byteArrays = [];

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

        byteArrays.push(byteArray);
    

    const blob = new Blob(byteArrays,  type: contentType );
    return blob;



const contentType = "application/pdf",
    b64Data = "YourBase64PdfString", //Replace this with your base64String
    blob = this.b64toBlob(b64Data, contentType),
    blobUrl = URL.createObjectURL(blob);

使用blobUrl到iframe的src,完成后就可以在iframe上调用print()如下图

const iframeEle = document.getElementById("Iframe");
if (iframeEle) 
    iframeEle.contentWindow.print();

希望这会有所帮助...

更多关于base64到Blob的细节在这里Creating a Blob from a base64 string in JavaScript

【讨论】:

这非常有效。我只需要添加一个 setTimeout(),这样浏览器就有时间渲染 PDF。否则它只会打印一个空白页。 这会为我返回 Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame. 错误。我有Allow-Origin=* 感谢您为这项工作提供的解决方案,但我不明白 sliceSize 是什么以及什么??【参考方案2】:

你可以用这个,

函数"printPreview(binaryPDFData)"获取二进制pdf数据的打印预览对话框。

printPreview = (data, type = 'application/pdf') => 
    let blob = null;
    blob = this.b64toBlob(data, type);
    const blobURL = URL.createObjectURL(blob);
    const theWindow = window.open(blobURL);
    const theDoc = theWindow.document;
    const theScript = document.createElement('script');
    function injectThis() 
        window.print();
    
    theScript.innerhtml = `window.onload = $injectThis.toString();`;
    theDoc.body.appendChild(theScript);
;

b64toBlob = (content, contentType) => 
    contentType = contentType || '';
    const sliceSize = 512;
     // method which converts base64 to binary
    const byteCharacters = window.atob(content); 

    const byteArrays = [];
    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) 
        const slice = byteCharacters.slice(offset, offset + sliceSize);
        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) 
            byteNumbers[i] = slice.charCodeAt(i);
        
        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
    
    const blob = new Blob(byteArrays, 
        type: contentType
    ); // statement which creates the blob
    return blob;
;

【讨论】:

这在 Chrome 和 Firefox 中完美运行,但在 IE 中却不行。 IE中是否有任何修复。无法将 blob url 添加到 IE 中的窗口。 无论如何要让它在打印后自动关闭?我对图像有类似的工作,我可以使用window.close() 来实现这一点,但是当我将window.close() 放在上面的代码中时,它会在我有机会打印之前关闭窗口,即使设置了很短的 setTimeout。

以上是关于从 javascript 触发 base64 编码 PDF 的打印预览的主要内容,如果未能解决你的问题,请参考以下文章

JSON 编码/解码 JavaScript 中的 base64 编码/解码

从输入表单中获取 Base64 编码文件数据

Base64 编码一个 javascript 对象

将 AWS KMS ECDSA_SHA_256 签名从 DER 编码的 ANS.1 格式转换为 JWT base64url 编码的 R || NodeJS/Javascript 中的 S 格式

用javascript实现base64编码器

在 Javascript 中将 PDF 转换为 Base64 编码的字符串