使用 javascript 在新窗口中打开 PDF 字符串

Posted

技术标签:

【中文标题】使用 javascript 在新窗口中打开 PDF 字符串【英文标题】:Opening PDF String in new window with javascript 【发布时间】:2011-02-17 19:39:51 【问题描述】:

我有一个格式化的 PDF 字符串,看起来像

%PDF-1.73 0 obj<<< /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 2 0 R/Contents 4 0 R>> endobj4 0 obj<> streamx��R=o�0��+��=|vL�R���l�-��ځ,���Ge�JK�������Y5�����Z˯k�vf�a��`G֢ۢ��Asf�z�ͼ��`%��aI#�!;�t���GD?!���<�����B�b��

...

00000 n 0000000703 00000 n 0000000820 00000 n 0000000926 00000 n 0000001206 00000 n 0000001649 00000 n trailer << /Size 11 /Root 10 0 R /Info 9 0 R >>startxref2015%%EOF

我正在尝试在新窗口中将此字符串作为 PDF 文件打开。每当我使用 window.open() 并将字符串写入新选项卡时,它认为文本应该是 html 文档的内容。我希望它识别出这是一个 PDF 文件。

非常感谢任何帮助

【问题讨论】:

你是如何“写”这个字符串的?你的意思是它是由后端返回的(如果是,什么平台?)。如果后端正在生成 PDF 数据,请确保设置正确的 Content-Type 标头。 最佳答案:在这种情况下您不应该使用 AJAX。 @Josh - 他从未提到过 AJAX。它可以是 CD 上的独立 HTML 页面,为我们所知动态生成自定义字符串。我怀疑这是可能的。 它正在后端创建,但无法/优雅地保存在服务器上。此外,在生成 pdf 之前,内容已经被写入页面......因此将标题设置为 pdf 将不起作用。 @Josh Stodola 为什么在这种情况下不应该使用 AJAX 【参考方案1】:

仅供参考,以下

window.open("data:application/pdf," + encodeURI(pdfString)); 

在 Chrome 中不再起作用。昨天,我遇到了同样的问题并尝试了这个解决方案,但没有奏效(它是“不允许将顶部框架导航到数据 URL”)。您不能再在新窗口中直接打开数据 URL。 但是,您可以将其包装在 iframe 中并在如下所示的新窗口中打开。 =)

let pdfWindow = window.open("")
pdfWindow.document.write(
    "<iframe width='100%' height='100%' src='data:application/pdf;base64, " +
    encodeURI(yourDocumentBase64VarHere) + "'></iframe>"
)

【讨论】:

伙计,你拯救了我的一天:] 在 Chrome 中工作,但一旦加载它就会消耗 CPU 和 GPU,并且标签显示它仍在加载。尝试使用iframeembedobject @SivaKiran setTimeout-0 像这样解决我的问题setTimeout(() =&gt; pdfWindow.document.write(@987654327 @$title; , 0); 这项工作很棒,文档在新选项卡中打开。但是,当我单击右上角的下载图标时,什么也没有发生。如何让它可下载? 标签仍然加载的问题很奇怪。我们的 4 名团队成员使用相同的按钮打开 pdf,对于 2 个人来说,它会在图标中显示加载,但对于我们中的 2 个人来说,它没有显示加载动画..每个人都使用相同版本的 chrome.. .【参考方案2】:

@Noby Fujioka回答的更新版本:

function showPdfInNewTab(base64Data, fileName)   
  let pdfWindow = window.open("");
  pdfWindow.document.write("<html<head><title>"+fileName+"</title><style>bodymargin: 0px;iframeborder-width: 0px;</style></head>");
  pdfWindow.document.write("<body><embed width='100%' height='100%' src='data:application/pdf;base64, " + encodeURI(base64Data)+"#toolbar=0&navpanes=0&scrollbar=0'></embed></body></html>");

【讨论】:

【参考方案3】:

对于最新的 Chrome 版本,这对我有用:

var win = window.open("", "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top="+(screen.height-400)+",left="+(screen.width-840));
win.document.body.innerHTML = 'iframe   src="data:application/pdf;base64,"+base64+"></iframe>';

谢谢

【讨论】:

【参考方案4】:

使用函数"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;
;

【讨论】:

【参考方案5】:

//用于pdf查看

let pdfWindow = window.open("");
pdfWindow.document.write("<iframe width='100%' height='100%' src='data:application/pdf;base64," + data.data +"'></iframe>");

【讨论】:

【参考方案6】:

我在处理 FedEx 货运请求时遇到了这个问题。我使用 AJAX 执行请求。响应包括跟踪号、费用以及包含运输标签的 pdf 字符串。

这就是我所做的:

添加表单:

<form id='getlabel' name='getlabel' action='getlabel.php' method='post' target='_blank'>
<input type='hidden' id='pdf' name='pdf'>
</form>

使用 javascript 使用 pdf 字符串填充隐藏字段的值并发布表单。

getlabel.php 在哪里:

<?
header('Content-Type: application/pdf');
header('Content-Length: '.strlen($_POST["pdf"]));
header('Content-Disposition: inline;');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
print $_POST["pdf"];
?>

【讨论】:

此方法的问题是无法在文档下载时通知用户。 我相信 target='_blank' 会通知用户?【参考方案7】:

我只想加上@Noby Fujioka 的回复,Edge 不支持关注

window.open("data:application/pdf," + encodeURI(pdfString));

对于 Edge,我们需要将其转换为 blob,如下所示

//If Browser is Edge
            if (window.navigator && window.navigator.msSaveOrOpenBlob) 
                var byteCharacters = atob(<Your_base64_Report Data>);
                var byteNumbers = new Array(byteCharacters.length);
                for (var i = 0; i < byteCharacters.length; i++) 
                    byteNumbers[i] = byteCharacters.charCodeAt(i);
                
                var byteArray = new Uint8Array(byteNumbers);
                var blob = new Blob([byteArray], 
                    type: 'application/pdf'
                );
                window.navigator.msSaveOrOpenBlob(blob, "myreport.pdf");
             else 
                var pdfWindow = window.open("", '_blank');
                pdfWindow.document.write("<iframe width='100%' style='margin: -8px;border: none;' height='100%' src='data:application/pdf;base64, " + encodeURI(<Your_base64_Report Data>) + "'></iframe>");
            

【讨论】:

【参考方案8】:
var byteCharacters = atob(response.data);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) 
  byteNumbers[i] = byteCharacters.charCodeAt(i);

var byteArray = new Uint8Array(byteNumbers);
var file = new Blob([byteArray],  type: 'application/pdf;base64' );
var fileURL = URL.createObjectURL(file);
window.open(fileURL);

您从 API 或其他来源返回 base64 字符串。也可以下载。

【讨论】:

这似乎是迄今为止最好的解决方案。其他解决方案似乎充其量只能偶尔发挥作用。我一直在尝试对来自服务器的字符串响应进行编码,但这似乎是唯一可靠的方法。谢谢! 我收到错误“无法执行 atob 到 window.any 帮助 有没有办法混淆url。我想成为文件的名称。现在它显示为编码的 base 64 值? 你能为***.com/questions/61840240/…提供解决方案吗 希望我能投票一百次!几天来,我一直在努力打开更大的文件。非常感谢!【参考方案9】:

只需在 base 64 中编码格式化的 PDF 字符串。然后你应该这样做:

$pdf = 'data:application/pdf;base64,'.$base64EncodedString;

将此返回到 javascript 并在新窗口中打开:

window.open(return);

【讨论】:

【参考方案10】:

这个对我有用。

window.open("data:application/octet-stream;charset=utf-16le;base64,"+data64);

这个也有用

 let a = document.createElement("a");
 a.href = "data:application/octet-stream;base64,"+data64;
 a.download = "documentName.pdf"
 a.click();

【讨论】:

【参考方案11】:

一个建议是使用像 PDFJS 这样的 pdf 库。

您必须附加以下"data:application/pdf;base64" + 您的 pdf 字符串,并将您的元素的 src 设置为该字符串。

试试这个例子:

var pdfsrc = "data:application/pdf;base64" + "67987yiujkhkyktgiyuyhjhgkhgyi...n"

<pdf-element id="pdfOpen" elevation="5" downloadable src="pdfsrc" ></pdf-element>

希望对你有帮助:)

【讨论】:

救命稻草,我的客户不喜欢 pdf 被自动下载到电脑上,他们只是希望能够从浏览器打印。【参考方案12】:

我意识到这是一个很老的问题,但我今天也遇到了同样的问题并想出了以下解决方案:

doSomethingToRequestData().then(function(downloadedFile) 
  // create a download anchor tag
  var downloadLink      = document.createElement('a');
  downloadLink.target   = '_blank';
  downloadLink.download = 'name_to_give_saved_file.pdf';

  // convert downloaded data to a Blob
  var blob = new Blob([downloadedFile.data],  type: 'application/pdf' );

  // create an object URL from the Blob
  var URL = window.URL || window.webkitURL;
  var downloadUrl = URL.createObjectURL(blob);

  // set object URL as the anchor's href
  downloadLink.href = downloadUrl;

  // append the anchor to document body
  document.body.appendChild(downloadLink);

  // fire a click event on the anchor
  downloadLink.click();

  // cleanup: remove element and revoke object URL
  document.body.removeChild(downloadLink);
  URL.revokeObjectURL(downloadUrl);
);

【讨论】:

这是一个很好的解决方案!根据MDN,仅适用于 IE10+ 在 chrome 上我得到 document.body.append 不是一个函数,所以我使用了:document.getElementsByTagName('body')[0].appendChild(downloadLink); 谢谢@manuel-84,你发现了一个错字。从一开始就应该是appendChild 请注意,添加下载属性(如示例中所示)将导致文件下载而不是在新窗口/选项卡中打开。而且 Safari 不支持它。 嗨@ChrisCashwell,我有同样的问题。我想知道参数downloadedFile 是什么。为什么它包含data 属性?是data 字符串还是blob【参考方案13】:

根据其他旧答案:

escape() 函数现已弃用,

请改用encodeURI() 或encodeURIComponent()。

在我的情况下有效的示例:

window.open("data:application/pdf," + encodeURI(pdfString)); 

编码愉快!

【讨论】:

因为这会打开一个新选项卡,其中 url 是 PDF 内容,有 PDF 限制大小吗?我确实尝试了很多解决方案,但只有这个有效,但是......如果我有一个 2 MB 的 PDF? @Mistre83 - 不完全确定我理解你的问题,但我已经在一些相当大的 PDF 上多次使用它并且它有效,现在无法测试,在一个大的 PDF 上试试看,但它应该可以工作,如果有大小限制,我会假设它非常大,比如 2-4GB(纯猜测)【参考方案14】:
window.open("data:application/pdf," + escape(pdfString)); 

上面是在 URL 中粘贴编码的内容。这使得 URL 中的内容长度受到限制,因此 PDF 文件加载失败(因为内容不完整)。

【讨论】:

警告:chrome 将此检测为弹出窗口并阻止 这在 MSIE 中不起作用,因为 MS 决定强加 2048 个最大字符 URL 长度。 此限制不适用于数据 URI,仅适用于普通导航 URL。参考:msdn.microsoft.com/en-us/library/cc848897(v=vs.85).aspx 有谁知道为什么您打开这个窗口后无法与它进行交互?像这样var wdw = window.open("data:application/pdf," + escape(pdfString)); wdw.print(); 打印功能不做任何事情。而且我什至尝试使用setTimeout 来延迟打印,但这也不起作用。就像它失去了对 window 对象的引用一样。如果我做同样的事情但传入一个实际的网址,它就可以工作。 内容过长时如何解决此类问题?【参考方案15】:

您可能希望使用数据 URI 进行探索。它看起来像。

window.open("data:application/pdf," + escape(pdfString));

我无法立即让它工作,可能是因为提供了二进制字符串的格式。在使用数据 URI 时,我通常也使用 base64 编码的数据。如果您能够从后端编码传递内容,您可以使用..

window.open("data:application/pdf;base64, " + base64EncodedPDF);

希望这是您需要的正确方向。另请注意,这在 IE6/7 中根本不起作用,因为它们不支持数据 URI。

【讨论】:

在 IE 8+ 中也不起作用,因为 URL 大小很可能是 IE 对 URL 施加的 > 2048 个字符的限制 我相信此限制不适用于数据 URI,仅适用于 URL。 IE8 的 32KB 数据 URI 限制已在 IE9 中删除。 这很好,但 window.open(url) 需要一个 URL,而不是 URI。 IE 会在 2048 个字符之后删除任何内容,即使您使用数据 URI。在 IE 中试试这个 jsfiddle,你会发现它不起作用:jsfiddle.net/bpdj7ksv 这对我不起作用 window.open('data:application/pdf;base64,' + btoa(unescape(encodeURIComponent(resp))), "_blank", "toolbar=yes,滚动条=yes, resizable=yes");

以上是关于使用 javascript 在新窗口中打开 PDF 字符串的主要内容,如果未能解决你的问题,请参考以下文章

在新窗口中打开 PDF

markdown 使用Rails FORM_FOR在新窗口中打开PDF

在新选项卡/窗口中打开页面并将当前窗口定向到新 url

如何在新选项卡或窗口中打开 PDF 文件而不是下载它(使用 asp.net)?

可以使用 Javascript 打开 PDF 文件的打印对话框吗?

从 GSP 页面中的变量路径名在新窗口中打开 pdf 文件