【问题标题】:Opening PDF String in new window with javascript使用 javascript 在新窗口中打开 PDF 字符串
【发布时间】: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

标签: javascript pdf


【解决方案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>body{margin: 0px;}iframe{border-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 width="100%" height="100%" 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 值?
            • 你能为stackoverflow.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");
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-07-01
                • 2013-03-07
                • 2019-01-25
                • 2012-12-17
                • 2014-05-01
                相关资源
                最近更新 更多