Como construir um arquivo PDF a partir de uma string binária retornada de um serviço da web usando o javascript

Eu estou tentando construir um arquivo PDF fora de um stream binário que recebo como uma resposta de uma solicitação Ajax.

Via XmlHttpRequest recebo os seguintes dados:

 %PDF-1.4.... ..... ....hole data representing the file .... %% EOF 

O que eu tentei até agora foi incorporar meus dados via data:uri . Agora, não há nada de errado com isso e funciona bem. Infelizmente, isso não funciona no IE9 e no Firefox. Um possível motivo pode ser que o FF e o IE9 tenham seus problemas com esse uso do data-uri .

Agora, estou procurando por qualquer solução que funcione para todos os navegadores. Aqui está meu código:

 // responseText encoding pdfText = $.base64.decode($.trim(pdfText)); // Now pdfText contains %PDF-1.4 ...... data...... %%EOF var winlogicalname = "detailPDF"; var winparams = 'dependent=yes,locationbar=no,scrollbars=yes,menubar=yes,'+ 'resizable,screenX=50,screenY=50,width=850,height=1050'; var htmlText = ''; // Open PDF in new browser window var detailWindow = window.open ("", winlogicalname, winparams); detailWindow.document.write(htmlText); detailWindow.document.close(); 

Como eu disse, funciona bem com o Opera e o Chrome (o Safari não foi testado). Usar o IE ou o FF abrirá uma nova janela em branco.

Existe alguma solução como construir um arquivo PDF em um sistema de arquivos para permitir que o usuário faça o download? Eu preciso da solução que funciona em todos os navegadores, pelo menos no IE, FF, Opera, Chrome e Safari.

Não tenho permissão para editar a implementação do serviço da web. Então tinha que ser uma solução no lado do cliente. Alguma ideia?

Existe alguma solução como construir um arquivo pdf no sistema de arquivos para permitir que o usuário baixe o arquivo?

Tente configurar responseType de XMLHttpRequest para blob , substituindo o atributo download em a elemento por window.open para permitir o download da resposta de XMLHttpRequest como arquivo .pdf

 var request = new XMLHttpRequest(); request.open("GET", "/path/to/pdf", true); request.responseType = "blob"; request.onload = function (e) { if (this.status === 200) { // `blob` response console.log(this.response); // create `objectURL` of `this.response` : `.pdf` as `Blob` var file = window.URL.createObjectURL(this.response); var a = document.createElement("a"); a.href = file; a.download = this.response.name || "detailPDF"; document.body.appendChild(a); a.click(); // remove `a` following `Save As` dialog, // `window` regains `focus` window.onfocus = function () { document.body.removeChild(a) } }; }; request.send(); 

Eu percebo que esta é uma questão bastante antiga, mas aqui está a solução que eu criei hoje:

 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.append(downloadLink); // fire a click event on the anchor downloadLink.click(); // cleanup: remove element and revoke object URL document.body.removeChild(downloadLink); URL.revokeObjectURL(downloadUrl); } 

Eu mudei isso:

 var htmlText = ''; 

para

 var htmlText = ''; 

e funcionou para mim.

Eu trabalho em PHP e uso uma function para decodificar os dados binários enviados de volta do servidor. Eu extraio a informação de uma input para um arquivo simples.php e ver o arquivo através do meu servidor e todo o navegador exibir o artefato pdf.

 < ?php $data = 'dfjhdfjhdfjhdfjhjhdfjhdfjhdfjhdfdfjhdf==blah...blah...blah..' $data = base64_decode($data); header("Content-type: application/pdf"); header("Content-Length:" . strlen($data )); header("Content-Disposition: inline; filename=label.pdf"); print $data; exit(1); ?> 

Eu vi outra pergunta sobre apenas este tópico recentemente ( streaming de pdf em iframe usando o dataurl só funciona no chrome ).

Eu construí pdfs no ast e transmita-os para o navegador. Eu os criei primeiro com fdf, depois com uma aula de pdf eu escrevi a mim mesmo – em cada caso o pdf foi criado a partir de dados recuperados de um object COM baseado em um par de parâmetros GET passados ​​através do url.

Olhando seus dados enviados recebidos na chamada do ajax, parece que você está quase lá. Eu não jogo com o código há alguns anos e não o documento tão bem quanto gostaria, mas – acho que tudo que você precisa fazer é definir o alvo de um iframe para ser o url você obtém o pdf de. Embora isso possa não funcionar – o arquivo que supera o pdf também pode ter que gerar um header de resposta html primeiro.

Em suma, este é o código de saída que usei:

 //We send to a browser header('Content-Type: application/pdf'); if(headers_sent()) $this->Error('Some data has already been output, can\'t send PDF file'); header('Content-Length: '.strlen($this->buffer)); header('Content-Disposition: inline; filename="'.$name.'"'); header('Cache-Control: private, max-age=0, must-revalidate'); header('Pragma: public'); ini_set('zlib.output_compression','0'); echo $this->buffer; 

Então, sem ver o texto de resposta completo da chamada do ajax, não posso realmente ter certeza do que é, embora esteja inclinado a pensar que o código que gera o pdf que você está solicitando pode ser apenas equivalente ao último. linha no código acima. Se é um código que você controla, eu tentaria configurar os headers – então, dessa forma, o navegador pode simplesmente lidar com o texto de resposta – você não precisa se preocupar em fazer algo com ele.

Eu simplesmente construí um url para o pdf que eu queria (um cronograma), em seguida, criei uma string que representava o html para um iframe do sie, id etc., que usava o url construído como é src. Assim que eu configurei o html interno de um div para a string html construída, o navegador solicitou o pdf e o exibiu quando foi recebido.

 function showPdfTt(studentId) { var url, tgt; title = byId("popupTitle"); title.innerHTML = "Timetable for " + studentId; tgt = byId("popupContent"); url = "pdftimetable.php?"; url += "id="+studentId; url += "&type=Student"; tgt.innerHTML = ""; } 

EDIT: esqueci de mencionar – você pode enviar pdf binário desta maneira. Os streams que eles contêm não precisam ser ascii85 ou hex codificados. Eu usei flate em todos os streams no pdf e funcionou bem.

A resposta de @alexandre com base64 faz o truque.

A explicação por que isso funciona para o IE está aqui

https://en.m.wikipedia.org/wiki/Data_URI_scheme

No header ‘formato’, onde diz

Alguns navegadores (Chrome, Opera, Safari, Firefox) aceitam uma ordenação não padrão se ambos: base64 e; charset forem fornecidos, enquanto o Internet Explorer exige que a especificação do conjunto de caracteres preceda o token base64.

Você pode usar o PDF.js para criar arquivos PDF a partir do javascript … é fácil codificar … espero que isso resolva sua dúvida !!!

Saudações!

Detecte o navegador e use o Data-URI for Chrome e use o PDF.js abaixo para outros navegadores.

 PDFJS.getDocument(url_of_pdf) .then(function(pdf) { return pdf.getPage(1); }) .then(function(page) { // get a viewport var scale = 1.5; var viewport = page.getViewport(scale); // get or create a canvas var canvas = ...; canvas.width = viewport.width; canvas.height = viewport.height; // render a page page.render({ canvasContext: canvas.getContext('2d'), viewport: viewport }); }) .catch(function(err) { // deal with errors here! });