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.
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.
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.
Possibly a duplicate of bug 874200.
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...
in about:config I set pdfjs.disabled=true but pdf start download I suppose if it use plugin.disable_full_page_plugin_for_types = application/pdf it can't download pdf and in see in the viewer
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鈥攕o 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.)
Another observation: I was hoping to trigger printing via the onload
event on the iframe
, but the PDF hasn't necessarily been rendered yet. Not sure if there is a reliable way to check for that?
I saw #5765, but it appears that only refers to events you could hook into if you were running PDF.js directly and not the built-in Firefox version?
I am baffled that this is such an issue to do something as simple as trigging a PDF file to print using javascript. This issue appears to date back two or so years (possibly longer) now.
Has anyone found a _client side_ solution? I saw @Petce solution but that solution wouldn't work for me.
Don't hold your breath @Lynda333, the support for this problem is notoriously unresponsive. Your real only option in my opinion is to find a suitable compromise in functionality. If you tell us more about your situation myself and others might be able to present a possible work around.
@Petce - I won't when I saw how long ago this issue started. Seems ridiculous to not include this ability. I spoke with the client and going to change our approach for this site. 1) They can download the PDF and 2) I am recreating some of the PDF content in HTML and letting the user choose what to print. Takes more time to create but it will work.
Does anybody can print embedded iframe? i just install the last extension version and im getting error permission denied, also i can't view pdf files on normal pdf access.
Using code from this commits (and pdfjs data parser itself) you can rewrite your pdf as a temporary blob and add a print instruction: https://github.com/mozilla/pdf.js/pull/6190/commits
Create an iframe with the blob as source and it will start printing (Note that ie won't load blobs into iframes at all, apart from not following the print istruction).
Anyway this is pretty complex if you are not already running a custom version of the viewer.
Alternatively you can add the print instruction on the server or anywhere you are able to edit the data of the pdf.
The funny part is only firefox needs it... It's been three years this issue was reported and firefox is the only browser complaining about accessing the iframe contentWindow: looks like nobody really cares about printing nowadays, which maybe is a good thing.
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
Are you able to access contentWindow on firefox? Don't you get a security issue?
@paolocaminiti I am loading all files from the same domain. It seems to work for me. I've used IE 10 and 11, IE Edge, Chrome on Windows. And FireFox 38 on 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));
}
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.
Hello,
What does it means "res"? And PDFViewerApplication comes from PDF.js?
Thanks,
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.
@thenewguy Just to clarify this thread for other readers, it seems we are doing quite different things:
I'm trying to use the native browser pdf viewer to print in full quality (I found no way to access the contentWindow on both ie and edge not matter using same domain).
You are loading the PDFjs viewer in an iframe, possibly visible, and controlling it's printing from the host application.
Its funny because i was trying to achieve @paolocaminiti inserting an script to my iframe and calling it as a function but now i get "offsetParent is not set -- cannot scroll" 馃槩. I will use chrome kiosk printing and forgot this.
So far, no solution has been proposed
Do I still need to have a server-side-solution or is there any progress on this subject? Is it possible to use the PDFPrintService
from pdf-js? Would this be a functional workaround? If yes, how is it possible to use this service without having to use the whole pdf-viewer?
Most helpful comment
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 thatdocument.domain
ispdf.js
for the PDF.js renderer鈥攕o 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.)