使用 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,并且标签显示它仍在加载。尝试使用iframe
、embed
和object
。
@SivaKiran setTimeout-0 像这样解决我的问题setTimeout(() => 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 字符串的主要内容,如果未能解决你的问题,请参考以下文章
markdown 使用Rails FORM_FOR在新窗口中打开PDF
如何在新选项卡或窗口中打开 PDF 文件而不是下载它(使用 asp.net)?