49

How to print a PDF in Firefox?

This function works in Chrome but not in Firefox

function print_pdf(url){
    var id = 'iframe', html = '<iframe id="'+id+'" src="'+url+'" style="display:none"></iframe>';
    $('#main').append(html);
    $('#'+id).load(function(){
        document.getElementById(id).contentWindow.print();
    }
}

error

Error: Permission denied to access property "print"
clarkk
  • 27,151
  • 72
  • 200
  • 340

7 Answers7

37

Firefox: Permission denied to access property "print"

This is a bug in firefox. Locally it can be disabled by going to about:config and set the property of pdfjs.disabled to true. Only possible workaround is to use a server-side script and modify the pdf. Using php you could use fpdf and embed extensions to implement js (inclunding the print() function) or simply convert the pdf to an image, return the url and print it. You could use FPDI to modify the existing pdf. I will give you an example on how I got it to work with PHP.

Generating a PDF file with inline javascript (autoprint) using FPDI and PDF_JS

require_once('fpdf.php');
require_once('fpdi.php');

class PDF_JavaScript extends FPDI {

    var $javascript;
    var $n_js;

    function IncludeJS($script) {
        $this->javascript=$script;
    }

    function _putjavascript() {
        $this->_newobj();
        $this->n_js=$this->n;
        $this->_out('<<');
        $this->_out('/Names [(EmbeddedJS) '.($this->n+1).' 0 R]');
        $this->_out('>>');
        $this->_out('endobj');
        $this->_newobj();
        $this->_out('<<');
        $this->_out('/S /JavaScript');
        $this->_out('/JS '.$this->_textstring($this->javascript));
        $this->_out('>>');
        $this->_out('endobj');
    }

    function _putresources() {
        parent::_putresources();
        if (!empty($this->javascript)) {
            $this->_putjavascript();
        }
    }

    function _putcatalog() {
        parent::_putcatalog();
        if (!empty($this->javascript)) {
            $this->_out('/Names <</JavaScript '.($this->n_js).' 0 R>>');
        }
    }
}

class PDF_AutoPrint extends PDF_JavaScript
{
    function AutoPrint($dialog=false)
    {
        //Open the print dialog or start printing immediately on the standard printer
        $param=($dialog ? 'true' : 'false');
        $script="print($param);";
        $this->IncludeJS($script);
    }

    function AutoPrintToPrinter($server, $printer, $dialog=false)
    {
        $script = "document.contentWindow.print();";
        $this->IncludeJS($script);
    }
}

$pdf=new PDF_AutoPrint();
$pdf->setSourceFile("mozilla.pdf");
//Open the print dialog
$tplIdx = $pdf->importPage(1, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tplIdx, 10, 10, 90);
$pdf->AutoPrint(true);
$pdf->Output('generated.pdf', 'F');

Now you can simply append the generated pdf to your page and the included javascript will call the print() function. You do not even have to call it manually anymore. However, in firefox this will only work with visibility: hidden and not with display: none.

function print_pdf(url){
    var iFrameJQueryObject = $('<iframe id="iframe" src="'+url+'" style="visibility: hidden"></iframe>');
    $('#foo').append(iFrameJQueryObject);
}
print_pdf('mozilla_generated.pdf');

Chrome: Security Error (cross-origin)

The pdf should be located at the same host. Firefox was okay with other domains in my tests, but chrome gave me cross-origin errors.


Firefox: Printed page includes about:blank only

You will get an empty page in firefox (jsfiddle), because it will print the iframe before it has loaded any content. Mentioned methods like $(document).onload() won't help, since they only wait for the DOM to load and setTimeout() can still result in errors, since you do not know how long it takes the iFrame to load.

You can simply resolve this issue by using jQuery's load(). (doc) This will give you the possibility to use a callback function as parameter.

if a "complete" callback is provided, it is executed after post-processing and HTML insertion has been performed. The callback is fired once for each element in the jQuery collection, and this is set to each DOM element in turn.

Code Example 1

function print_pdf(url){
    var id = 'iframe', html = '<iframe id="'+id+'" src="'+url+'" style="display:none"></iframe>';
    $('body').append(html);
    // wait for the iFrame to fully load and call the print() function afterwards
    $('#' + id).load(function () {
        document.getElementById(id).contentWindow.print();
    });
}

Alternatively you could directly create an jQuery object and use jQuery's on() (doc) to attach any event handler.

Code Example 2 (jsfiddle)

function print_pdf(url){
    var iFrameJQueryObject = $('<iframe id="iframe" src="'+url+'" style="display:none"></iframe>');
    $('body').append(iFrameJQueryObject);
    iFrameJQueryObject.on('load', function(){
        $(this).get(0).contentWindow.print();
    });
}
oshell
  • 8,923
  • 1
  • 29
  • 47
  • You would be better off creating the iframe as a JS object instead of as a string. That way you can add event handlers, such as onload, to it before you add it to the page. – Paul Allsopp Nov 24 '15 at 15:05
  • @HoschNok Can create stacksnippets , jsfiddle http://jsfiddle.net to demonstrate approach at solution ? – guest271314 Nov 24 '15 at 16:01
  • 1
    jsfiddle will have x-origin problems when using iframes, so this is inconvenient. I still got it to work, by using just the same url as url. – oshell Nov 24 '15 at 16:24
  • 6
    I get this error in Firefox: `Error: Permission denied to access property "print"` – clarkk Nov 29 '15 at 00:09
  • In the jsfiddle too? only on localhost? make sure you use same protocol like http:// and not file:// – oshell Nov 29 '15 at 20:53
  • 2
    If you put an actual PDF file into the function it does not work http://jsfiddle.net/zrp6sd6h/4/ `Error: Permission denied to access property "print"` – clarkk Nov 30 '15 at 10:56
  • 2
    - and i think it has something to do with Firefox uses its own javascript PDF viewer `pdf.js` – clarkk Nov 30 '15 at 11:18
  • which os/browser version are you using? I am currently using Ubuntu. – oshell Dec 03 '15 at 11:58
  • I have posted a working workaround in PHP. Seems pretty much overkill, you might consider using another approach such as simply downloading/open the PDF and let the user print it manually. – oshell Dec 03 '15 at 16:38
4

Edit, Updated

Try using window.onload event , document.createElement() , onload event , setTimeout() with duration set to 2000 , setting src of iframe after appending element to document

window.onload = function() {
    function print_pdf(url){
        var id = "iframe", frame = document.createElement("iframe");
        frame.setAttribute("id", id);
        frame.setAttribute("width", "800px");
        frame.setAttribute("height", "600px");
        frame.setAttribute("allowfullscreen", "true");
        frame.setAttribute("name", "printframe");
        document.body.appendChild(frame);
        frame.onload = function() {
          this.requestFullScreen = this.mozRequestFullScreen 
                                   || this.webkitRequestFullScreen;
          this.requestFullScreen();
          setTimeout(function() {
            print()
          },2000)
        }
        frame.setAttribute("src", url);
    }
    print_pdf("http://zeitreisen.zeit.de/wp-content/uploads/2014/09/pdftest2.pdf");
}

plnkr http://plnkr.co/edit/mHBNmc5mdM0YJRwRbYif?p=preview

guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    The code triggers an `alert` before the print dialog comes up saying: pdf.js is not fully loaded – clarkk Nov 18 '15 at 20:43
  • 1
    @clarkk _"The code triggers an alert before the print dialog comes"_ Adjust individual firefox browser print preferences for default action at print ? _"and the PDF has to be hidden "_ Not certain interpret "PDF has to be hidden" ? Load iframe with `display:none` adjust `iframe` to `display:block` before calling `.print()`? If `iframe` is loaded and `.print()` called immediately print window should display `iframe` contents and have immediate focus before parent `window` regains focus when print dialog canceled or documented printed to filesystem. – guest271314 Nov 18 '15 at 21:17
  • @clarkk Can a server side solution be used to meet requirement ? – guest271314 Dec 02 '15 at 22:01
  • I would prefer a javascript solution.. But show me what you had in mind – clarkk Dec 02 '15 at 22:09
  • @clarkk See updated post , added `window.onload` event , added `duration` of `2000` to `setTimeout`. Tried at nightly, chromium ; appear to return same results at each. – guest271314 Dec 03 '15 at 06:08
  • I tried this and it returns an empty page in chrome on my machine. – oshell Dec 08 '15 at 09:56
  • @HorstJahns _" tried this and it returns an empty page in chrome on my machine."_ Were plugins allowed for page ? – guest271314 Dec 08 '15 at 16:34
  • This appears to be printing the iframe rather than the pdf. That means the pdf will get cut off if it's larger than the dimensions of the iframe. Also, triggering the print dialog after some arbitrary timeout will be very unreliable since the pdf's load time could vary greatly depending on its size, the user's connection speed, system resources, etc. – DoctorDestructo Dec 08 '15 at 20:01
  • @DoctorDestructo There is not actually a `.pdf` file displayed , but a rendering of `.pdf` file as `html` by either firefox or chrome `js` plugin. Yes, `setTimeout` is not optimal solution , without adjusting `js` that renders `.pdf` as `html` ; which appears slightly different for each browser – guest271314 Dec 08 '15 at 20:26
  • @guest271314 My point was that you're printing the iframe (or rather, its parent window) instead of the iframe's content. Doesn't matter if the content is html or pdf; if it's larger than the iframe, it will get cut off. That's the consequence of using `print()` instead of `frame.documentWindow.print()`. – DoctorDestructo Dec 09 '15 at 00:14
  • @DoctorDestructo _"My point was that you're printing the iframe (or rather, its parent window) instead of the iframe's content."_ , _"That's the consequence of using print() instead of frame.documentWindow.print()"_ Good points. Approach is to avoid `Uncaught SecurityError: Blocked a frame with origin "http://run.plnkr.co" from accessing a frame with origin "http://zeitreisen.zeit.de". Protocols, domains, and ports must match.` Can dynamically adjust `width`, `height` of `iframe`, or `parent` to address possible clipping of print job. – guest271314 Dec 09 '15 at 00:44
  • @guest271314 I don't think Firefox allows JavaScript to access most of the properties and methods of the iframe's contentWindow or any of its descendants, so you probably couldn't use JS to determine the pdf's size. If you could measure it server-side somehow, then you'd be in business. – DoctorDestructo Dec 09 '15 at 01:01
  • @DoctorDestructo Since no `.pdf` is actually displayed at `document` , `html` rendering of `.pdf` could be adjusted, or "resized" based on screen. Used arbitrary `width`, `height` at `html` at post , and attempted to incorporate `requestFullScreen` to cover viewport of user. Could determine user screen size before creating or setting `iframe` `src` , then render `iframe` to fill `viewport` without clipping document. This is , perhaps, fine-tuning portion ; beyond scope of Question. Solution at post printed `window` at chrome / chromium , firefox ; have not yet tried at mac or opera – guest271314 Dec 09 '15 at 01:12
  • @guest271314 Were you actually able to reference and manipulate elements of the converted pdf via JavaScript? If you can do that, then you might as well just do a simulated `click()` on the pdf viewer's built-in print button, or just run its `onclick` function directly. In my testing, though, Firefox denied access to *everything* within the iframe once the pdf was loaded. If you have a workaround, you should incorporate it into your post. Your current solution prints the iframe's parent window, which isn't the same thing as printing its content document. – DoctorDestructo Dec 09 '15 at 01:31
  • @DoctorDestructo _"Were you actually able to reference and manipulate elements of the converted pdf via JavaScript?"_ This is more involved. If open plnkr at firefox, open `console` and navigate to `Script` tab, should observe that `pdf.js` is loaded. This can also be viewed at `css` tab as well, where `viewer.css` is listed as ``. This presents at least two challenges; 1) accessing cross-domain `iframe` , 2) accessing `` resources. Source of both `viewer.css` and `pdf.js` can be viewed at GitHub. Firefox and chrome appear to implement rendering `.pdf` documents differently. – guest271314 Dec 09 '15 at 01:47
  • @DoctorDestructo Stopped short of modifying `pdf.js` for this specific Question, as users at large browsers' would not have same resources available natively. Simplest approach would be to use `pdftohtml` or similar library to render `.pdf` as `html` , adjust `style` as necessary - without browser attempting to render `.pdf`. That is, save `.pdf` locally, render to `html` , adjust styles , when user visits page display `.pdf` as `html` without browser plugins automatically trying to load plugin and render `.pdf` as `html` – guest271314 Dec 09 '15 at 01:53
2

PDFs have Javascript support. I needed to have auto print capabilities when a PHP-generated PDF was created and I was able to use FPDF to get it to work:

http://www.fpdf.org/en/script/script36.php

vrtech77
  • 149
  • 3
  • 14
0

@clarkk i would recommend to use something more powerful which has been covered from many people my suggestion is to use http://pdfmake.org/#/ .

I have use this pdfmake in my datatables and it works absolutely perfect. Keep in mind if you print more then 10 000 rows from tables or something it run out the memory of the browser :)

  • Creating the PDF on client side is not an option.. Then you have to maintain both the serverside PDF genereator and the client side PDF generator.. The client side PDF generator is the primary – clarkk Dec 06 '15 at 23:04
  • Yes you are right but in little information i can tell you that it is super fast. Also it relay on html5 and when you want a cross browser compatibility is great, Also it is a free library and you do not support anything everything is done by the guys you need only to replace the library so it is not a big deal of support. – George Plamenov Georgiev Dec 07 '15 at 08:01
0

I haven't use this for a while, but this what I was used to do to print pdf's from an iframe...

function printfile() {
    window.frames['objAdobePrint'].focus();
    window.frames['objAdobePrint'].print();
}

<iframe src="urlOfPdf" name="objAdobePrint" id="objAdobePrint"></iframe>
<button onclick="printfile();">Print</button>
raphie
  • 3,285
  • 2
  • 29
  • 26
0

You can implement print function without create new iframe (only with css) to prevent security problems:

var style = document.createElement("style");
style.setAttribute("media", "print"); //style.setAttribute("media", "screen,print");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
var width = $("#printDiv").width();
var height = $("#printDiv").height();
style.sheet.insertRule("body { width: 210mm !important, height: 25.4mm !important; visibility: hidden; }", 0);
style.sheet.insertRule("#printDiv { visibility: visible; position: fixed !important;top: 5px;  left: 5px; width:" + width + "px;height:" + height + ";  page-break-after: avoid;}", 0);

window.focus();
window.print(true);
style.remove();
Pedram
  • 828
  • 9
  • 24
-1

Print a pdf with javascript or jquery

Create a iframe in html:

<iframe id="pdf-iframe">

Then change the src of that iframe and on load, print it:

$('#pdf-iframe').attr("src", pdf_url).load(function(){
    document.getElementById('pdf-iframe').contentWindow.print();
});

Or, you might want to try https://mozilla.github.io/pdf.js/

Community
  • 1
  • 1
Gary
  • 2,293
  • 2
  • 25
  • 47
  • 2
    `contentWindow.print()` does not work in Firefox because it returns `Error: Permission denied to access property "print"` – Hengjie Nov 01 '16 at 05:28
  • It is because of your firefox default pdfjs config. It is a known issue. https://bugzilla.mozilla.org/show_bug.cgi?id=911444 Please try this. http://stackoverflow.com/questions/15011799/firefox-19-print-pdf-from-javascript#answer-21500997 or this http://stackoverflow.com/questions/15011799/firefox-19-print-pdf-from-javascript#answer-25490208 – Gary Nov 02 '16 at 02:03