Drucken Sie ein PDF, ohne es visuell zu öffnen

Lesezeit: 9 Minuten

Was ich bauen möchte, ist, dass ich durch Klicken auf eine Schaltfläche den Druck einer PDF-Datei auslösen möchte, ohne sie jedoch zu öffnen.

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

Die Art und Weise, wie ich es zuerst versucht habe, ist die Verwendung eines Iframes:

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);
}

Dies funktioniert auf Safari (Desktop & iOS) und Chrome (können wir es vielleicht auf Webkit verallgemeinern?).

Auf Firefox, PDF.contentWindow.print() endet mit a permission denied Fehler (sogar das PDF wird von derselben Domain geladen).

Auf IE (11), die onload Handler funktioniert einfach nicht.


Nun ist meine Frage: Gibt es eine andere bessere Möglichkeit, das PDF zu drucken, ohne es dem Benutzer visuell zu öffnen?

Die Cross-Browser-Sache ist hier kritisch. Wir sollten so viele Browser wie möglich unterstützen.

Was ist der beste Weg, dies zu erreichen? Ist mein Start gut? Wie vervollständige ich es?

Wir sind jetzt im Jahr 2016 und ich habe das Gefühl, dass dies immer noch mühsam in den Browsern zu implementieren ist.

  • Also wenn ich das richtig verstehe willst du das PDF nicht zeigen aber trotzdem ausdrucken… also einfach mit anderen Worten runterladen? Oder tun Sie es einfach so, wie Sie es normalerweise tun würden, und blenden Sie diesen Abschnitt aus.

    – Jorrex

    28. Juli 2016 um 14:51 Uhr

  • Kann das PDF nicht so eingestellt werden, dass es beim Öffnen automatisch gedruckt wird?

    – escarello

    28. Juli 2016 um 14:53 Uhr

  • @Jorrex Nein, öffne es in einem versteckten Iframe und öffne den Druckdialog im Kontext dieses Iframes. Der Iframe ist keine Voraussetzung, aber es war mein erster Versuch. Ich bin mir nicht sicher, ob es andere Möglichkeiten gibt, dies zu tun … Kurz gesagt: Wenn ich auf die Schaltfläche klicke, sollte sich der Druckdialog öffnen und dieses PDF drucken.

    – Ionică Bizău

    28. Juli 2016 um 14:58 Uhr

  • @epascarello Was meinst du?

    – Ionică Bizău

    28. Juli 2016 um 14:58 Uhr

  • nvision.co/blog/tips-and-tricks/auto-print-pdf-file-open

    – escarello

    28. Juli 2016 um 15:04 Uhr

Benutzer-Avatar
Balah

AKTUALISIEREN: Dies Verknüpfung beschreibt eine elegante Lösung, die das Bearbeiten der Seiteneigenschaften für die erste Seite und das Hinzufügen einer Aktion beim Öffnen der Seite beinhaltet. Funktioniert in allen Browsern (da Browser das im Aktionsbereich platzierte JavaScript ausführen). Erfordert Adobe Acrobat Pro.


Es scheint, dass 2016 keine neuen Fortschritte beim Druckproblem bringt. Hatte ein ähnliches Problem und um das Drucken browserübergreifend zu machen, habe ich es gelöst PDF.JS musste aber der Quelle einen Einzeiler hinzufügen (sie bitten Sie sowieso, darauf aufzubauen).

Die Idee:

  • Laden Sie die vorgefertigte stabile Version von herunter https://mozilla.github.io/pdf.js/getting_started/#download und fügen Sie dem Projekt die Ordner „build“ und „web“ hinzu.
  • Das viewer.html file rendert PDFs mit einer reichhaltigen Benutzeroberfläche und enthält Druckfunktionen. Ich habe in dieser Datei einen Link zu meinem eigenen JavaScript hinzugefügt, der nach einer Verzögerung einfach window.print() auslöst.

Der Link zum Viewer hinzugefügt:

    <script src="https://stackoverflow.com/questions/38639769/viewer.js"></script>
    <!-- this autoPrint.js was added below viewer.js -->
    <script src="autoPrint.js"></script>
</head>

Das autoPrint.js Javascript:

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

    printWhenReady();
})();
  • Ich könnte dann Anrufe tätigen viewer.html?file= im src eines Iframes und verstecke es. Wegen Firefox musste Sichtbarkeit verwendet werden, keine Anzeigestile:

    <iframe src="https://stackoverflow.com/questions/38639769/web/viewer.html?file=abcde.pdf" style="visibility: hidden">
    

Das Ergebnis: Der Druckdialog wurde nach kurzer Verzögerung angezeigt, wobei das PDF für den Benutzer ausgeblendet wurde.

Getestet in Chrome, IE, Firefox.

  • Pdf.js ist definitiv eine Sache. In Bezug auf die Kompatibilität funktioniert es gut mit modernen Browsern. Der unangenehme Teil ist, dass es Druckfehler hat (verpixelte Ausgabe, falsche Schriftarten usw.). Das habe ich auch probiert.

    – Ionică Bizău

    7. August 2016 um 21:08 Uhr

  • Stimmt das. Um die Dinge voranzubringen, habe ich die Fehler in Pdf.js nach Möglichkeit eingeräumt und angepasst. Eines dieser Jahre wird das Drucken von PDFs einfach gemacht…

    – Balah

    8. August 2016 um 10:05 Uhr

  • Können Sie das bitte in Ihrer Antwort hinzufügen diese Lösung funktioniert? Browser führen dort abgelegte js aus, also durch Hinzufügen window.print() im pdf löst das Problem.

    – Ionică Bizău

    23. September 2016 um 7:10 Uhr

  • Ich suche schon ewig nach einer Lösung dafür! Vielen Dank! FYI, ich musste Ihre if-Anweisung leicht ändern: if (typeof PDFViewerApplication !== 'undefined' && PDFViewerApplication.initialized)

    – scolja

    26. Mai 2017 um 19:21 Uhr

  • Ein weiterer Check, der auf dem von @scolja aufbaut, damit er auch auf Safari funktioniert, ist use if (typeof PDFViewerApplication !== 'undefined' && PDFViewerApplication.initialized && PDFViewerApplication.pdfViewer.pageViewsReady)

    – Gulasch

    23. März 2018 um 4:03 Uhr


Benutzer-Avatar
Benjamin Dekan

Nachdem ich die letzten paar Stunden damit verbracht habe, das herauszufinden, und viel gesucht habe, ist hier das, was ich festgestellt habe …

Das HTML5-Web-API-Spezifikation für das Drucken weist darauf hin, dass einer der printing steps muss feuern Vorabdruck, ein einfaches Ereignis (ein Ereignis, das nicht abgebrochen werden kann), an das Fensterobjekt des zu druckenden Dokuments (sowie alle verschachtelten Browsing-Kontexte, dies bezieht sich auf iFrames), um Änderungen am Dokument vor dem Drucken zu ermöglichen. Dieser Schritt ist browserintern und kann nicht angepasst werden. Während dieses Vorgangs zeigt der Druckdialog des Browsers manchmal eine Vorschau der Datei (Chrome tut dies) … wenn Sie also die Datei niemals dem Betrachter anzeigen möchten, stecken Sie möglicherweise fest.

Dem kam ich am nächsten, indem ich eine erstellte index.html Datei, die eine Schaltfläche mit data-*-Attributen hat, die Kontext bereitstellten. Ändern Sie den Pfad/Dateiname.ext in der data-print-resource-uri -Attribut in eine eigene lokale Datei.

<!DOCTYPE html>
<html>
    <head>
        <title>Express</title>
        <link rel="stylesheet" href="https://stackoverflow.com/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>

Dann im print.js Datei habe ich ein paar Dinge ausprobiert, aber es hat nie ganz funktioniert (ich habe verschiedene Dinge, mit denen ich gespielt hatte, in den Kommentaren hinterlassen).

// 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();
    */
}

Ich denke, wenn Sie es mit dem richtig zum Laufen bringen können Blob funktioniert möglicherweise am besten in der von Ihnen gewünschten Cross-Browser-Methode.

Ich habe ein paar Referenzen zu diesem Thema gefunden, die hilfreich sein könnten:

  • Interessanter Ansatz, aber ich sehe keinen Unterschied zwischen der Einstellung der src zu einer Blob-URL oder setzen Sie einfach die Datei-URL direkt. Nachdem ich die kleinen Probleme im Code behoben habe, erhalte ich zumindest den gleichen Fehler in Firefox: Permission denied to access property "print".

    – Ionică Bizău

    7. August 2016 um 4:50 Uhr

Benutzer-Avatar
Paul

Ich werde hier die geänderten Funktionen des OP-Funktions auf IE 11 posten

    printPdf: function (url) {
        $('#mainLoading').show();
        let iframe = $('#idPdf');
        if (iframe) {
            iframe.remove();
        }

        iframe = $('<iframe>', {
            style: "display:none",
            id: "idPdf"
        });

        $("body").prepend(iframe);
        $('#idPdf').on("load", function(){
            utilities.printIframeOnLoad()
       })

        utilities.getAsyncBuffer(url, function(response){
            let path = utilities.getPdfLocalPath(response);
            $('#idPdf').attr('src', path);
        })
    },

     printIframeOnLoad: function () {
        let iframe = $('#idPdf');
        if (!iframe.attr("src")) { return; }

        var pdf = iframe.get(0);
        pdf.focus();
        $('#mainLoading').hide();
        pdf.contentWindow.print();
    },


    getPdfLocalPath: function (data) {
        var filename = "Application_" + utilities.uuidv4() + ".pdf";
        var blob = new Blob([data], { type: 'application/pdf' });
        if (window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
            return filename;
        }
        else {
            let url = window.URL || window.webkitURL;
            let href = url.createObjectURL(blob);
            return href;
        }
    },

    getAsyncBuffer: function (uriPath, callback) {

        var req = new XMLHttpRequest();
        req.open("GET", uriPath, true);
        req.responseType = "blob";
        req.onreadystatechange = function () {
            if (req.readyState === 4 && req.status === 200) {
                callback(req.response);
            }
        };
        req.send();
    }

1206340cookie-checkDrucken Sie ein PDF, ohne es visuell zu öffnen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy