web-dev-qa-db-ja.com

javascriptを使用してWebサービスから返されたバイナリ文字列からPDFファイルをビルドする方法

Ajaxリクエストからの応答として受け取るバイナリストリームからPDFファイルを作成しようとしています。

XmlHttpRequest経由で、次のデータを受け取ります。

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

これまで試したのは、data:uri経由でデータを埋め込むことでした。今、それは何の問題もありませんし、うまく動作します。残念ながら、IE9およびFirefoxでは機能しません。考えられる理由は、FFとIE9がdata-uriのこの使用法に問題があることです。

現在、私はすべてのブラウザで機能するソリューションを探しています。私のコードは次のとおりです。

// 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 = '<embed width=100% height=100%'
                     + ' type="application/pdf"'
                     + ' src="data:application/pdf,'
                     + escape(pdfText)
                     + '"></embed>'; 

                // Open PDF in new browser window
                var detailWindow = window.open ("", winlogicalname, winparams);
                detailWindow.document.write(htmlText);
                detailWindow.document.close();

私が言ったように、OperaおよびChrome(Safariはテストされていません)。IEまたは、FFは空白の新しいウィンドウを表示します。

ユーザーがダウンロードできるようにするために、ファイルシステムにPDFファイルを作成するようなソリューションはありますか?すべてのブラウザー、少なくともIE、FF、Opera、 ChromeおよびSafari。

Webサービスの実装を編集する権限がありません。そのため、クライアント側でソリューションにする必要がありました。何か案は?

43
Sebb0

ユーザーがダウンロードできるように、ファイルシステムにPDFファイルを作成するような解決策はありますか?

responseTypeXMLHttpRequestblobに設定して、downloadからの応答のダウンロードを許可するためにa要素のXMLHttpRequest属性をwindow.openに置き換えてください。 _ as .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();
23
guest271314

これはかなり古い質問であることがわかりますが、今日私が思いついた解決策は次のとおりです。

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);
}
12
Chris Cashwell

これを変更しました:

var htmlText = '<embed width=100% height=100%'
                 + ' type="application/pdf"'
                 + ' src="data:application/pdf,'
                 + escape(pdfText)
                 + '"></embed>'; 

var htmlText = '<embed width=100% height=100%'
                 + ' type="application/pdf"'
                 + ' src="data:application/pdf;base64,'
                 + escape(pdfText)
                 + '"></embed>'; 

そしてそれは私のために働いた。

4

PHPで作業し、サーバーから返されたバイナリデータをデコードする関数を使用します。情報を入力して単純なfile.phpに入力し、サーバーとすべてのブラウザーでファイルを表示します。 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);

?>
3
Fabiolus

ブラウザを検出し、ChromeにData-URIを使用し、他のブラウザには以下のように PDF.js を使用します。

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!
});
2
Ghostoy

最近、このトピックに関する別の質問を見ました( dataurlを使用してPDFをiframeにストリーミングすると、chromeでのみ機能します )。

AstでPDFを作成し、ブラウザにストリーミングしました。最初にfdfで作成し、次に自分で作成したpdfクラスで作成しました。それぞれの場合、pdfは、URLを介して渡されたいくつかのGETパラメーターに基づいてCOMオブジェクトから取得したデータから作成されました。

Ajax呼び出しで受信したデータを見ると、ほとんどそこにいるように見えます。数年前からこのコードで遊んでおらず、思い描いていたほど文書化もしていませんでしたが、iframeのターゲットをURLに設定するだけでいいと思いますpdfを取得します。これは機能しない可能性がありますが、pdfを無効にするファイルは、最初にhtml応答ヘッダーも無効にする必要があります。

一言で言えば、これは私が使用した出力コードです。

//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;

そのため、ajax呼び出しの完全な応答テキストを見ずに、それが何であるかを本当に確信することはできませんが、あなたが要求しているpdfを出力するコードは最後のものに相当するだけだと思う​​傾向があります上記のコードの行。あなたが制御できるコードであれば、ヘッダーを設定してみます-そうすれば、ブラウザーは応答テキストを処理するだけで済みます-わざわざそれをする必要はありません。

必要なpdf(タイムテーブル)のURLを作成し、作成したURLをsrcとして使用する目的のsie、idなどのiframeのhtmlを表す文字列を作成しました。 divの内部htmlを作成されたhtml文字列に設定するとすぐに、ブラウザーはpdfを要求し、それを受け取ったときにそれを表示しました。

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 = "<iframe onload=\"centerElem(byId('box'))\" src='"+url+"' width=\"700px\" height=\"500px\"></iframe>";
}

編集:言及するのを忘れた-あなたはこの方法でバイナリPDFを送信することができます。それらに含まれるストリームは、ascii85または16進エンコードである必要はありません。 PDFのすべてのストリームでflateを使用しましたが、正常に機能しました。

2
enhzflep

Base64での@alexandreの答えがそのトリックです。

IEで機能する理由の説明はこちら

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

ヘッダー「フォーマット」の下には

一部のブラウザー(Chrome、Opera、Safari、Firefox)は、; base64と; charsetの両方が指定されている場合、非標準の順序を受け入れますが、Internet Explorerでは、charsetの仕様がbase64トークンよりも前にある必要があります。

2
Hace

PDF.js を使用して、JavaScriptからPDFファイルを作成できます...コーディングは簡単です...これがあなたの疑問を解決することを願っています!!!

よろしく!

1
Fernando Canul