pdf.js: Unable to Print PDF when loaded in iFrame

I am attempting to use Javascript to focus and print a PDF file that is loaded within a iframe I dynamically placed into the DOM. This issue is specifically occurring for me in Firefox.

My code resembles the following:

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

I receive the following error:

Error: Permission denied to access property ‘print’

My research is telling me that this should work, further reading has lead me to believe that this may be a bug. Any help would be appreciated.

Edit

I tested the functionality by replacing the PDF file with a screen shot in PNG format of the first page within it and the print functionality worked.

Edit

Further testing. Added pdfjs to my chrome install, and attempted to print with the same code above. same error:

SecurityError: Blocked a frame with origin “http://domain.com” from accessing a 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)"

I should make it clear that the PDF file is being loaded on the same domain.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 9
  • Comments: 25

Commits related to this issue

Most upvoted comments

I think I know the reason for this, at least in Firefox. In a simple example such as the above, if you use the Firefox DevTools to examine document.domain in both the main page and in the iframe, I found that document.domain is pdf.js for the PDF.js renderer—so the browser’s cross-origin restrictions are kicking in.

Additionally, if I built PDF.js from source, and set my iframe to web/viewer.html?file=, then calling telling the iframe to print (as in the OP), it worked fine.

Is there a way for PDF.js (at least when running in Firefox) to accept messages from other windows, perhaps via something like window.postMessage? (I’ve never used it, so I don’t know if it is appropriate for this use-case or not.)

So far, no solution has been proposed

I see, you are loading the pdf again from remote and it results same domain. On chrome/opera/safari I’m using this:

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

Simply uses the local data to create a blob and then call print, the setTimeout 0 allows the iframe to be attached.

Unfortunately firefox disallows the contentWindow with the blob, but a blob with a print instruction will print on its own.

For ie no solution using local data, But maybe having a proxy on one owns server to route pdfs data would do to allow all to be same domain and apply your code.

For anyone who stumbles upon this issue and would like a possible work around (considering this issue has been around for over a year now with no fix), I ended up using ImageMagick in PHP along with GhostScript to generate images of the PDF on the server, then served these image URLs back in a json response, printing the result from that was trivial.

Knowing me however, there is probably a better and easier way to do it…

Yes PDFViewerApplication is provided by the PDFViewer build of pdfjs, the source is under the /web directory, you should modify there an make a new build so it will be easier to merge the master repo as it updates…

res is just the argument passed back by getData, should be the byte rappresentation of the pdf file, here is used to build a local blob url to load without further network requests.

If you are going for something like the code above you may want to clean it up a bit:

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

In the end I chose not to dispose the iframe as it proved to complicate to understand when to do it, I’m just leaving it there and reusing it every time the user wants to print, assuming the pdf can’t change in between.

Hope it helps.

This seems to be working for me

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

I couldn’t find any events or ways to hook into the viewer, but if you trigger the click even on it’s print buttons (I’m using version 1.4.20) then it seems to print. The settimeout allows the viewer time to load and such