Print PDF in Firefox

21,589

Solution 1

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

Solution 2

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

Solution 3

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

Share:
21,589

Related videos on Youtube

clarkk
Author by

clarkk

https://dynaccount.dk https://dynaccount.dk/bogfoeringsprogram/ https://dynaccount.dk/regnskabsprogram/

Updated on July 09, 2022

Comments

  • clarkk
    clarkk almost 2 years

    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"
    
    • sailens
      sailens over 8 years
      It doesn't just work or it shows some error? Can you provide a jsfiddle for us to take a look?
    • clarkk
      clarkk over 8 years
      The printed page is empty.. Like an empty webpage with URL in the header and date in the footer
    • clarkk
      clarkk over 8 years
      TypeError: document.frames is undefined
    • sailens
      sailens over 8 years
      I just noticed, you have style="display:none". If the item is not showing, it won't get printed. Think as if the printed page is a screen. If there is no item showing, it won't get printed.
    • Aidas Bendoraitis
      Aidas Bendoraitis over 8 years
      the DOM variable/object is undefined.
    • james emanon
      james emanon over 8 years
      I'd try wrapping a setTimeout around the "print()".. ala.. setTimeout(function() {document.getElementById(id).contentWindow.print();}, 2000);
    • Jacobi
      Jacobi over 8 years
      Hi @clarkk, you wan't to open the page preview or just send to the printer?
    • clarkk
      clarkk over 8 years
      I just want to send to the printer..
    • Ultimater
      Ultimater over 8 years
      Why can't you use display:block and just position the iframe absolutely in some negative coordinates?
    • Jay
      Jay over 8 years
      @clarkk check this out, it may help : developer.mozilla.org/en-US/docs/Printing
  • clarkk
    clarkk over 8 years
    The code triggers an alert before the print dialog comes up saying: pdf.js is not fully loaded
  • guest271314
    guest271314 over 8 years
    @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.
  • Paul Allsopp
    Paul Allsopp over 8 years
    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.
  • guest271314
    guest271314 over 8 years
    @HoschNok Can create stacksnippets , jsfiddle jsfiddle.net to demonstrate approach at solution ?
  • oshell
    oshell over 8 years
    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.
  • clarkk
    clarkk over 8 years
    I get this error in Firefox: Error: Permission denied to access property "print"
  • oshell
    oshell over 8 years
    In the jsfiddle too? only on localhost? make sure you use same protocol like http:// and not file://
  • clarkk
    clarkk over 8 years
    If you put an actual PDF file into the function it does not work jsfiddle.net/zrp6sd6h/4 Error: Permission denied to access property "print"
  • clarkk
    clarkk over 8 years
    - and i think it has something to do with Firefox uses its own javascript PDF viewer pdf.js
  • guest271314
    guest271314 over 8 years
    @clarkk Can a server side solution be used to meet requirement ?
  • clarkk
    clarkk over 8 years
    I would prefer a javascript solution.. But show me what you had in mind
  • guest271314
    guest271314 over 8 years
    @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.
  • oshell
    oshell over 8 years
    which os/browser version are you using? I am currently using Ubuntu.
  • oshell
    oshell over 8 years
    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.
  • clarkk
    clarkk over 8 years
    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
  • George Plamenov Georgiev
    George Plamenov Georgiev over 8 years
    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.
  • oshell
    oshell over 8 years
    I tried this and it returns an empty page in chrome on my machine.
  • guest271314
    guest271314 over 8 years
    @HorstJahns " tried this and it returns an empty page in chrome on my machine." Were plugins allowed for page ?
  • DoctorDestructo
    DoctorDestructo over 8 years
    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.
  • guest271314
    guest271314 over 8 years
    @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
  • DoctorDestructo
    DoctorDestructo over 8 years
    @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().
  • guest271314
    guest271314 over 8 years
    @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.
  • DoctorDestructo
    DoctorDestructo over 8 years
    @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.
  • guest271314
    guest271314 over 8 years
    @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
  • DoctorDestructo
    DoctorDestructo over 8 years
    @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.
  • guest271314
    guest271314 over 8 years
    @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 <System>. This presents at least two challenges; 1) accessing cross-domain iframe , 2) accessing <System> 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
    guest271314 over 8 years
    @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
  • Hengjie
    Hengjie over 7 years
    contentWindow.print() does not work in Firefox because it returns Error: Permission denied to access property "print"
  • Gary
    Gary over 7 years
    It is because of your firefox default pdfjs config. It is a known issue. bugzilla.mozilla.org/show_bug.cgi?id=911444 Please try this. stackoverflow.com/questions/15011799/… or this stackoverflow.com/questions/15011799/…