Pdf.js: PDF kann nicht gedruckt werden, wenn es in iFrame geladen wird

Erstellt am 11. Okt. 2014  ·  21Kommentare  ·  Quelle: mozilla/pdf.js

Ich versuche, Javascript zu verwenden, um eine PDF-Datei zu fokussieren und zu drucken, die in einen Iframe geladen wird, den ich dynamisch in das DOM platziert habe. Dieses Problem tritt speziell bei mir in Firefox auf.

Mein Code sieht wie folgt aus:

<iframe name="printer_frame" id="printer_frame" src="http://domain.com/media/eparcel_label_1413020567.pdf"></iframe>
window.frames['printer_frame'].window.focus();
window.frames['printer_frame'].window.print();

Ich erhalte die folgende Fehlermeldung:

Fehler: Berechtigung zum Zugriff auf die Eigenschaft „print“ verweigert

Meine Forschung sagt mir, dass dies funktionieren sollte, weiteres Lesen hat mich zu der Annahme geführt, dass dies ein Fehler sein könnte. Jede Hilfe wäre willkommen.

Bearbeiten

Ich habe die Funktionalität getestet, indem ich die PDF-Datei durch einen Screenshot im PNG-Format der ersten darin enthaltenen Seite ersetzt habe, und die Druckfunktion hat funktioniert.

Bearbeiten

Weitere Tests. pdfjs zu meiner Chrome-Installation hinzugefügt und versucht, mit dem gleichen Code oben zu drucken. gleicher Fehler:

SecurityError: Blockiert einen Frame mit Ursprung " http://domain.com " für den Zugriff auf einen Cross-Origin-Frame.

code: 18
message: "Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame."
name: "SecurityError"
stack:
"Error: Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame.
    at Error (native)
    at <anonymous>:2:34
    at Object.InjectedScript._evaluateOn (<anonymous>:730:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:669:52)
    at Object.InjectedScript.evaluate (<anonymous>:581:21)"

Ich sollte klarstellen, dass die PDF-Datei auf derselben Domäne geladen wird.

3-upstream 4-printing

Hilfreichster Kommentar

Ich glaube, ich kenne den Grund dafür, zumindest in Firefox. Wenn Sie in einem einfachen Beispiel wie dem obigen die Firefox DevTools verwenden, um document.domain sowohl auf der Hauptseite als auch im Iframe zu untersuchen, habe ich festgestellt, dass document.domain für pdf.js steht der PDF.js-Renderer – also greifen die Cross-Origin-Beschränkungen des Browsers.

Wenn ich PDF.js aus der Quelle erstellt und meinen iframe auf web/viewer.html?file= gesetzt und dann den iframe zum Drucken aufgefordert habe (wie im OP), hat es gut funktioniert.

Gibt es eine Möglichkeit für PDF.js (zumindest wenn es in Firefox ausgeführt wird), Nachrichten von anderen Fenstern zu akzeptieren, vielleicht über so etwas wie window.postMessage ? (Ich habe es noch nie verwendet, daher weiß ich nicht, ob es für diesen Anwendungsfall geeignet ist oder nicht.)

Alle 21 Kommentare

Möglicherweise ein Duplikat von Fehler 874200 .

Für alle, die auf dieses Problem stoßen und eine mögliche Problemumgehung wünschen (wenn man bedenkt, dass dieses Problem seit über einem Jahr ohne Lösung besteht), habe ich schließlich ImageMagick in PHP zusammen mit GhostScript verwendet, um Bilder der PDF auf dem Server zu generieren , lieferte diese Bild-URLs dann in einer JSON-Antwort zurück, wobei das Drucken des Ergebnisses trivial war.

Wie ich mich kenne, gibt es wahrscheinlich einen besseren und einfacheren Weg, es zu tun ...

in about:config habe ich pdfjs.disabled=true eingestellt, aber pdf start download Ich nehme an, wenn es plugin.disable_full_page_plugin_for_types = application/pdf verwendet, kann es pdf nicht herunterladen und im Viewer sehen

Ich glaube, ich kenne den Grund dafür, zumindest in Firefox. Wenn Sie in einem einfachen Beispiel wie dem obigen die Firefox DevTools verwenden, um document.domain sowohl auf der Hauptseite als auch im Iframe zu untersuchen, habe ich festgestellt, dass document.domain für pdf.js steht der PDF.js-Renderer – also greifen die Cross-Origin-Beschränkungen des Browsers.

Wenn ich PDF.js aus der Quelle erstellt und meinen iframe auf web/viewer.html?file= gesetzt und dann den iframe zum Drucken aufgefordert habe (wie im OP), hat es gut funktioniert.

Gibt es eine Möglichkeit für PDF.js (zumindest wenn es in Firefox ausgeführt wird), Nachrichten von anderen Fenstern zu akzeptieren, vielleicht über so etwas wie window.postMessage ? (Ich habe es noch nie verwendet, daher weiß ich nicht, ob es für diesen Anwendungsfall geeignet ist oder nicht.)

Eine weitere Beobachtung: Ich hatte gehofft, das Drucken über das Ereignis onload auf dem iframe auszulösen, aber das PDF wurde noch nicht unbedingt gerendert. Sie sind sich nicht sicher, ob es eine zuverlässige Möglichkeit gibt, dies zu überprüfen?

Ich habe #5765 gesehen, aber anscheinend bezieht sich das nur auf Ereignisse, in die Sie sich einklinken könnten, wenn Sie PDF.js direkt ausführen und nicht die integrierte Firefox-Version?

Ich bin verblüfft, dass dies so ein Problem ist, etwas so Einfaches wie das Auslösen einer PDF-Datei zum Drucken mit Javascript zu tun. Dieses Problem scheint jetzt zwei oder so Jahre (möglicherweise länger) zurück zu liegen.

Hat jemand eine _clientseitige_ Lösung gefunden? Ich habe die @Petce- Lösung gesehen, aber diese Lösung würde für mich nicht funktionieren.

Halten Sie nicht den Atem an @Lynda333 , der Support für dieses Problem reagiert notorisch nicht. Ihre wirklich einzige Möglichkeit besteht meiner Meinung nach darin, einen geeigneten Kompromiss in der Funktionalität zu finden. Wenn Sie uns mehr über Ihre Situation erzählen, können ich und andere möglicherweise eine mögliche Problemumgehung vorstellen.

@Petce - Das werde ich nicht, wenn ich gesehen habe, wie lange dieses Problem her ist. Scheint lächerlich, diese Fähigkeit nicht einzuschließen. Ich habe mit dem Kunden gesprochen und werde unseren Ansatz für diese Website ändern. 1) Sie können das PDF herunterladen und 2) ich erstelle einen Teil des PDF-Inhalts in HTML neu und lasse den Benutzer wählen, was gedruckt werden soll. Das Erstellen dauert länger, aber es wird funktionieren.

Kann jemand eingebettetes Iframe drucken? Ich installiere gerade die letzte Erweiterungsversion und bekomme die Fehlerberechtigung verweigert. Außerdem kann ich keine PDF-Dateien bei normalem PDF-Zugriff anzeigen.

Mit Code aus diesen Commits (und dem pdfjs-Datenparser selbst) können Sie Ihr PDF als temporäres Blob umschreiben und eine Druckanweisung hinzufügen: https://github.com/mozilla/pdf.js/pull/6190/commits
Erstellen Sie ein Iframe mit dem Blob als Quelle und es wird mit dem Drucken beginnen (Beachten Sie, dass dh überhaupt keine Blobs in Iframes geladen werden, abgesehen davon, dass Sie der Druckanweisung nicht folgen).
Wie auch immer, dies ist ziemlich komplex, wenn Sie nicht bereits eine benutzerdefinierte Version des Viewers ausführen.
Alternativ können Sie die Druckanweisung auf dem Server oder überall dort hinzufügen, wo Sie die Daten des PDFs bearbeiten können.

Der lustige Teil ist, dass nur Firefox es braucht ... Es ist drei Jahre her, dass dieses Problem gemeldet wurde, und Firefox ist der einzige Browser, der sich über den Zugriff auf den Iframe beschwert.

Das scheint bei mir zu funktionieren

        setTimeout(function(){
            this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
        }.bind(this), 3000)

Ich konnte keine Ereignisse oder Möglichkeiten finden, mich in den Viewer einzuklinken, aber wenn Sie den Klick sogar auf die Druckschaltflächen auslösen (ich verwende Version 1.4.20), scheint es zu drucken. Das Settimeout gibt dem Betrachter Zeit zum Laden und so weiter

Können Sie auf contentWindow auf Firefox zugreifen? Bekommst du kein Sicherheitsproblem?

@paolocaminiti Ich lade alle Dateien aus derselben Domäne. Es scheint für mich zu funktionieren. Ich habe IE 10 und 11, IE Edge, Chrome unter Windows verwendet. Und Firefox 38 auf Ubuntu 14.04.

    handlePrintClick() {
        blurComponentRef(this.printButtonRef)
        this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
    }

    handlePrintLoad() {
        this.printIframeRef.contentWindow.addEventListener("documentload", function(){
            this.setState({canPrint: true})
        }.bind(this));
    }

Wie ich sehe, laden Sie das PDF erneut von der Ferne und es ergibt dieselbe Domäne.
Auf Chrome/Opera/Safari verwende ich dies:

function directPrint () {
  PDFViewerApplication.pdfDocument.getData().then(function(res) {
    var b = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
    var printFrame = document.getElementById('print-frame')
    if (!printFrame) {
      printFrame = document.createElement('iframe')
      printFrame.id = 'print-frame'
      printFrame.src = b
      document.body.appendChild(printFrame)
    }
    setTimeout(function () {
      printFrame.contentWindow.print()
      // ...dispose iframe and blob.
    }, 0)
  })
}

Verwendet einfach die lokalen Daten, um ein Blob zu erstellen und dann print aufzurufen, das setTimeout 0 ermöglicht das Anhängen des Iframes.

Leider verbietet Firefox das contentWindow mit dem Blob, aber ein Blob mit einer Druckanweisung wird von selbst gedruckt.

Zum Beispiel keine Lösung mit lokalen Daten, aber vielleicht würde es ausreichen, einen Proxy auf einem eigenen Server zum Weiterleiten von PDF-Daten zu haben, damit alle dieselbe Domäne haben und Ihren Code anwenden können.

Hallo,

Was bedeutet „res“? Und PDFViewerApplication kommt von PDF.js?

Danke,

Ja, PDFViewerApplication wird vom PDFViewer-Build von pdfjs bereitgestellt, die Quelle befindet sich im /web-Verzeichnis, Sie sollten dort Änderungen vornehmen und einen neuen Build erstellen, damit das Master-Repo beim Aktualisieren einfacher zusammengeführt werden kann ...

res ist nur das Argument, das von getData zurückgegeben wird, sollte die Byte-Rappresentation der PDF-Datei sein, hier wird verwendet, um eine lokale Blob-URL zu erstellen, die ohne weitere Netzwerkanforderungen geladen werden kann.

Wenn Sie nach etwas wie dem obigen Code suchen, möchten Sie es vielleicht ein wenig aufräumen:

function directPrint () {
  var printFrame = document.getElementById('print-frame')
  if (printFrame) {
    printFrame.contentWindow.print()
  } else {
    PDFViewerApplication.pdfDocument.getData().then(function(res) {
      var src = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
      printFrame = document.createElement('iframe')
      printFrame.id = 'print-frame'
      printFrame.style.display = 'none'
      printFrame.src = src
      document.body.appendChild(printFrame)
      setTimeout(function () {
        printFrame.contentWindow.print()
      }, 0)
    })
  }
}

Am Ende habe ich mich entschieden, den Iframe nicht zu entsorgen, da es sich als kompliziert herausstellte, zu verstehen, wann es zu tun ist. Ich lasse ihn einfach dort und verwende ihn jedes Mal wieder, wenn der Benutzer drucken möchte, vorausgesetzt, das PDF kann sich zwischendurch nicht ändern.

Ich hoffe es hilft.

@thenewguy Nur um diesen Thread für andere Leser zu verdeutlichen, es scheint, dass wir ziemlich unterschiedliche Dinge tun:
Ich versuche, den PDF-Viewer des nativen Browsers zu verwenden, um in voller Qualität zu drucken (ich habe keine Möglichkeit gefunden, auf das contentWindow sowohl auf dh als auch auf Edge zuzugreifen, unabhängig davon, ob dieselbe Domäne verwendet wird).
Sie laden den PDFjs-Viewer in einem möglicherweise sichtbaren Iframe und steuern das Drucken über die Hostanwendung.

Es ist lustig, weil ich versucht habe, @paolocaminiti zu erreichen, indem ich ein Skript in meinen iframe einfüge und es als Funktion aufrufe, aber jetzt bekomme ich "offsetParent ist nicht festgelegt - kann nicht scrollen" 😢. Ich werde den Chrom-Kioskdruck verwenden und das vergessen.

Bisher wurde noch keine Lösung vorgeschlagen

Brauche ich noch eine serverseitige Lösung oder gibt es diesbezüglich Fortschritte? Ist es möglich, PDFPrintService aus pdf-js zu verwenden? Wäre das ein funktionaler Workaround? Wenn ja, wie ist es möglich, diesen Dienst zu nutzen, ohne den gesamten PDF-Viewer verwenden zu müssen?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

azetutu picture azetutu  ·  4Kommentare

smit-modi picture smit-modi  ·  3Kommentare

sujit-baniya picture sujit-baniya  ·  3Kommentare

zerr0s picture zerr0s  ·  3Kommentare

liuzhen2008 picture liuzhen2008  ·  4Kommentare