web-dev-qa-db-ja.com

視覚的に開かずにPDFを印刷する

私が構築したいのは、ボタンをクリックすることでPDFファイルを開くことなく、印刷をトリガーしたいということです。

_+-----------+
| Print PDF |
+-----------+
     ^ Click *---------> printPdf(pdfUrl)
_

私が最初に試した方法は、iframeを使用することです。

_var $iframe = null;

// This is supposed to fix the onload bug on IE, but it's not fired
window.printIframeOnLoad = function() {
  if (!$iframe.attr("src")) { return; }
  var PDF = $iframe.get(0);
  PDF.focus();

  try {
    // This doesn't work on IE anyways
    PDF.contentWindow.print();

    // I think on IE we can do something like this:
    // PDF.document.execCommand("print", false, null);
  } catch (e) {
    // If we can't print it, we just open it in the current window
    window.location = url;
  }
};

function printPdf(url) {

  if ($iframe) {
    $iframe.remove();
  }

  $iframe = $('<iframe>', {
    class: "hide",
    id: "idPdf",
    // Supposed to be a fix for IE
    onload: "window.printIframeOnLoad()",
    src: url
  });

  $("body").prepend($iframe);
}
_

これはSafari(デスクトップおよびiOS)およびChrome(Webkitに一般化できますか?).

Firefoxでは、PDF.contentWindow.print()は_permission denied_エラーで終了します(pdfが同じドメインからロードされた場合でも)。

IE(11)]では、onloadハンドラーが機能していません。


さて、私の質問は、ユーザーに視覚的に開かずにPDFを印刷する別のより良い方法はありますか?

ここではクロスブラウザのことが重要です。できるだけ多くのブラウザをサポートする必要があります。

これを達成する最良の方法は何ですか?私のスタートは良いものですか?どのように完了するのですか?

私たちは2016年になりましたが、これはまだブラウザ間で実装するのが苦痛だと感じています。

26
Ionică Bizău

[〜#〜] update [〜#〜]:これは link のページプロパティの編集を含むエレガントなソリューションの詳細最初のページで、ページを開くときにアクションを追加します。すべてのブラウザーで機能します(ブラウザーはアクションセクションに配置されたJavaScriptを実行するため)。 Adobe Acrobat Proが必要です。


2016年は印刷の問題に新たな進歩をもたらさないようです。同様の問題があり、印刷用のクロスブラウザを作成するには、 PDF.JS を使用して解決しましたが、ソースに1行追加する必要がありました(とにかくビルドするように求められます)。

アイデア:

  • https://mozilla.github.io/pdf.js/getting_started/#download からビルド済みの安定版リリースをダウンロードし、プロジェクトに「build」および「web」フォルダーを追加します。
  • viewer.htmlファイルは、豊富なインターフェースを備えたPDFをレンダリングし、印刷機能を含むものです。そのファイルに、遅延後にwindow.print()を単純にトリガーするJavaScriptにリンクを追加しました。

ビューアーに追加されたリンク:

    <script src="viewer.js"></script>
    <!-- this autoPrint.js was added below viewer.js -->
    <script src="autoPrint.js"></script>
</head>

autoPrint.js javascript:

(function () {
    function printWhenReady() {
        if (PDFViewerApplication.initialized) {
            window.print();
        }
        else {
            window.setTimeout(printWhenReady, 3000);
        }
    };

    printWhenReady();
})();
  • その後、iframeのsrcにviewer.html?file=への呼び出しを配置し​​て非表示にすることができます。 Firefoxの表示スタイルではなく、可視性を使用する必要がありました。

    <iframe src="web/viewer.html?file=abcde.pdf" style="visibility: hidden">
    

結果:短い遅延の後に印刷ダイアログが表示され、PDFはユーザーから隠されました。

Chrome、IE、Firefoxでテスト済み。

15
Balah

過去数時間を費やしてこれを見つけ出し、ここで多くの検索を行ったことが、私が決定したことです...

印刷用のHTML5 Web API仕様 は、printing stepsのいずれかが beforeprint 、単純なイベント(キャンセル不可のイベント)を起動する必要があることを示します。印刷するドキュメントのウィンドウオブジェクト(およびネストされたブラウジングコンテキスト、iframeに関連)は、印刷前にドキュメントを変更できるようにします。このステップはブラウザ内部のものであり、調整できるものではありません。このプロセス中に、ブラウザの印刷ダイアログにファイルのプレビューが表示される場合があります(Chromeがこれを行います)...目的がファイルをビューアに表示しないことである場合、スタックする可能性があります。

これを達成するために最も近かったのは、コンテキストを提供するdata- *属性を含むボタンを持つindex.htmlファイルを作成することでした。 data-print-resource-uri属性のpath/filename.extを独自のローカルファイルに変更します。

<!DOCTYPE html>
<html>
    <head>
        <title>Express</title>
        <link rel="stylesheet" href="/stylesheets/style.css">
    </head>
    <body>
        <h1>Express</h1>
        <p>Welcome to Express</p>
        <button name="printFile" id="printFile" data-print-resource-uri="/binary/paycheckStub.pdf" data-print-resource-type="application/pdf">Print File</button>
        <iframe name="printf" id="printf" frameborder="0"></iframe>
        <script src="/javascripts/print.js"></script>
    </body>
</html>

それからprint.jsファイルでいくつか試してみましたが、まったく機能しませんでした(コメントで遊んでいたさまざまなものを残しています)。

// Reference vars
var printButton = document.getElementById('printFile');
var printFrame = document.getElementById('printf');

// onClick handler
printButton.onclick = function(evt) {
    console.log('evt: ', evt);
    printBlob('printf', printButton.getAttribute('data-print-resource-uri'), printButton.getAttribute('data-print-resource-type'));
}

// Fetch the file from the server
function getFile( fileUri, fileType, callback ) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', fileUri);
    xhr.responseType = 'blob';
    xhr.onload = function(e) {
        // Success
        if( 200 === this.status ) {
            // Store as a Blob
            var blob = new Blob([this.response], {type: fileType});
            // Hang a URL to it
            blob = URL.createObjectURL(blob);
            callback(blob);
        } else {
            console.log('Error Status: ', this.status);
        }
    };
    xhr.send();
}

function printBlob(printFrame, fileUri, fileType) {
    // Debugging
    console.log('inside of printBlob');
    console.log('file URI: ', fileUri);
    console.log('file TYPE: ', fileType);

    // Get the file
    getFile( fileUri, fileType, function(data) {
        loadAndPrint(printFrame, data, fileType);
    });
}

function loadAndPrint(printFrame, file, type) {
    // Debugging
    console.log('printFrame: ', printFrame);
    console.log('file: ', file);

    window.frames[printFrame].src = file;
    window.frames[printFrame].print();

    /*
    // Setup the print window content
    var windowContent = '<!DOCTYPE html>';
    windowContent += '<html>'
    windowContent += '<head><title>Print canvas</title></head>';
    windowContent += '<body>'
    windowContent += '<embed src="' + file + '" type="' + type + '">';
    windowContent += '</body>';
    windowContent += '</html>';

    // Setup the print window
    var printWin = window.open('','','width=340,height=260');
    printWin.document.open();
    printWin.document.write(windowContent);
    printWin.document.close();
    printWin.focus();
    printWin.print();
    printWin.close();
    */
}

Blobを使用して適切に機能させることができれば、必要なクロスブラウザメソッドで最適に機能すると思います。

このトピックに関する参考になる参考文献をいくつか見つけました。

6
Benjamin Dean