Menu

#1045 Unable to use setFooterMargin from Footer() in class

v1.0_(example)
open
nobody
1
2015-10-07
2015-04-08
NiklasBr
No

I am attaching a proof of concept where setFooterMargin does not work when set in a class which is extending TCPDF.

1 Attachments

Related

Bugs: #1085

Discussion

  • NiklasBr

    NiklasBr - 2015-05-18

    I reported this with version 6.2.6 and the issue is still present in the most recent version of TCPDF (6.2.8). Is there anything you are wondering about or do you need any further info to proceed?

     
  • NiklasBr

    NiklasBr - 2015-06-26

    I tried 6.2.9, but it does not seem to contain any fixes for this bug. I will gladly provide any more info if you request it.

     
  • NiklasBr

    NiklasBr - 2015-08-04

    I tried version 6.2.11 just now, but no changes. Please tell me what you need!

     
  • NiklasBr

    NiklasBr - 2015-09-04

    It would be appreciated if you at least gave some indication on the status of this issue. It has been four months now and I have previously tried emailing you offering to pay for development time but did not receive a response. A 'wontfix' is much better than you just keeping quiet. What is the problem here? I would like to help (both with my time and money) getting this solved, but you are unresponsive? Are you in the process of abandoning the TCPDF project altogether?

     
  • NiklasBr

    NiklasBr - 2015-10-05

    I am still offering to pay you for your time to fix this. If you could only tell me what you need to fix it. If you don't want to fix it for any reason whatsoever please close this issue, at least please just stop ignoring it.

     
  • Mikko Salminen

    Mikko Salminen - 2015-10-06

    Hey Niklas,

    Just checked your code and I guess your problem causes from this:

        public function endPage($tocpage=false) {
            // check if page is already closed
            if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) {
                return;
            }
    /* ... */
    }
    

    Which means, that the Footer -method is not called 'cause you're on page zero. You can see that by yourself by just adding another page:

    // create new PDF document
    $pdf = new customTCPDF(
        PDF_PAGE_ORIENTATION, 
        PDF_UNIT, 
        PDF_PAGE_FORMAT, 
        true,   // unicode
        'UTF-8', 
        false,  // cache
        true    // true = pdf 1.4
    );
    $pdf->addPage();
    $pdf->addPage();
    
    // returns "int 99".
    var_dump($pdf->getFooterMargin());
    

    Conclusion: your code works and tcpdf works, but not just in a way you thought :)

    PS. your constructor with "call_user_func_array" really shocked my object-oriented mind, but for wierd PHP-reasons it actually works... so what ever rocks your boat :)

     
  • NiklasBr

    NiklasBr - 2015-10-06

    Mikko, thanks for looking into this!

    In tcpdf.php (line 3119 or thereabout), some debug with print_r:

        /**
         * Terminate the current page
         * @param $tocpage (boolean) if true set the tocpage state to false (end the page used to display Table Of Content).
         * @public
         * @since 4.2.010 (2008-11-14)
         * @see AddPage(), startPage(), addTOCPage(), endTOCPage()
         */
        public function endPage($tocpage=false) {
            // check if page is already closed
            print "\ncheck if page is already closed\n";
            print_r([
                '($this->page == 0)' => ($this->page == 0),
                '($this->numpages > $this->page)' => ($this->numpages > $this->page),
                '(!$this->pageopen[$this->page])' => (!$this->pageopen[$this->page])
            ]);
            if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) {
                return;
            }
            // print page footer
            $this->setFooter();
            // close page
            $this->_endpage();
            // mark page as closed
            $this->pageopen[$this->page] = false;
            if ($tocpage) {
                $this->tocpage = false;
            }
        }
    

    Updated index.php from my test case:

    class customTCPDF extends TCPDF {
        public function __construct() {
            // "Transfers" arguments to parent class
            call_user_func_array('parent::__construct', func_get_args());
    
            // Make sure that the footer prints
            $this->SetPrintFooter(true);
            $this->setFooterData(array(0,0,0),array(0,0,0));
        }
        public function Footer() {
            $this->setFooterMargin(99);
    
            $this->writeHTMLCell(
                0, // width
                11, // height
                10, // pos x
                282, // pos y
                "Page " . $this->getAliasNumPage() . " of " . $this->getAliasNbPages(),
                "TRBL", // borders
                $ln = 0, // line on next row
                false, // background
                true, // reset h
                'C', // alignment
                false // autopadding
            );
        }
        public function get_page() {
            return $this->page;
        }
        public function get_page_open() {
            return $this->pageopen;
        }
    }
    
    // create new PDF document
    $pdf = new customTCPDF(
        PDF_PAGE_ORIENTATION, 
        PDF_UNIT, 
        PDF_PAGE_FORMAT, 
        true,   // unicode
        'UTF-8', 
        false,  // cache
        true    // true = pdf 1.4
    );
    print "<pre>";
    
    print "Before first addPage()\n";
    
    print_r([
        'footer margin' => $pdf->getFooterMargin(),
        'page' => $pdf->get_page(),
        'page open' => $pdf->get_page_open()
    ]);
    
    $pdf->addPage();
    
    print "\nAfter first addPage()\n";
    
    print_r([
        'footer margin' => $pdf->getFooterMargin(),
        'page' => $pdf->get_page(),
        'page open' => $pdf->get_page_open()
    ]);
    
    $pdf->addPage();
    
    print "\nAfter second addPage()\n";
    
    print_r([
        'footer margin' => $pdf->getFooterMargin(),
        'page' => $pdf->get_page(),
        'page open' => $pdf->get_page_open()
    ]);
    
    $pdf->addPage();
    
    print "\nAfter third addPage()\n";
    
    print_r([
        'footer margin' => $pdf->getFooterMargin(),
        'page' => $pdf->get_page(),
        'page open' => $pdf->get_page_open()
    ]);
    

    This gives the following output:

    Before first addPage()
    Array
    (
        [footer margin] => 
        [page] => 0
        [page open] => Array
            (
            )
    )
    
    check if page is already closed
    Array
    (
        [($this->page == 0)] => 1
        [($this->numpages > $this->page)] => 
        [(!$this->pageopen[$this->page])] => 1
    )
    
    After first addPage()
    Array
    (
        [footer margin] => 
        [page] => 1
        [page open] => Array
            (
                [1] => 1
            )
    )
    
    check if page is already closed
    Array
    (
        [($this->page == 0)] => 
        [($this->numpages > $this->page)] => 
        [(!$this->pageopen[$this->page])] => 
    )
    
    After second addPage()
    Array
    (
        [footer margin] => 99
        [page] => 2
        [page open] => Array
            (
                [1] => 
                [2] => 1
            )
    )
    
    check if page is already closed
    Array
    (
        [($this->page == 0)] => 
        [($this->numpages > $this->page)] => 
        [(!$this->pageopen[$this->page])] => 
    )
    
    After third addPage()
    Array
    (
        [footer margin] => 99
        [page] => 3
        [page open] => Array
            (
                [1] => 
                [2] => 
                [3] => 1
            )
    )
    

    What you will notice is that setFooterMargin() does not work properly untill the second page, this means that setFooterMargin() does not work the first and second pages. Starting by the second page it does work. Do you have any suggestion how I can get it working on page 1? While I do use setFooterMargin(99) the number is actually dynamically calculated in my code but I opted not to include the calculation to simplify the test case as much as possible.

    I need setFooterMargin() working on the first call to Footer(). I suppose I could do a workaround by using deletePage() but that seems like a hacky bandaid:

    // create new PDF document
    $pdf = new customTCPDF(
        PDF_PAGE_ORIENTATION, 
        PDF_UNIT, 
        PDF_PAGE_FORMAT, 
        true,   // unicode
        'UTF-8', 
        false,  // cache
        true    // true = pdf 1.4
    );
    $pdf->addPage();
    $pdf->addPage();
    /*
     ... do stuff ...
    */
    $pdf->deletePage($page=0);
    
     

    Last edit: NiklasBr 2015-10-06
  • Mikko Salminen

    Mikko Salminen - 2015-10-07

    Hi Niklas,

    Okay, now I guess I see your point. The setFooterMargin -method is called as wished, but that doesn't occur before the page is ended (ie. adding a second page, closing a document). But the real question is that before the Footer -method is called X and Y -postions are set to footer position. This means that only place where the footermargin is used is before the Footer -method.

    This means that footerMargin cannot be changed in Footer (well it can, but it really affects only the next time the footer is called) so the changing of footer must be triggered somewhere else.

    Here's one way to do it:

    // Include the main TCPDF library (search for installation path).
    require_once('tcpdf/tcpdf.php');
    
    class customTCPDF extends TCPDF {
        /**
         *
         * @var float store for the dynamic margin. used in this test case
         */
        protected $dynamic_footer_margin = 50;
    
        public function __construct() {
            // "Transfers" arguments to parent class
            call_user_func_array('parent::__construct', func_get_args());
    
            // Make sure that the footer prints
            $this->SetPrintFooter(true);
            $this->setFooterData(array(0,0,0),array(0,0,0));
        }
        public function Footer() {
            /* changed so that footer margin is also displayed */ 
            /* postion is changed to getX and GetY, so we actually use the margin we setted */
            $this->writeHTMLCell(
                0, // width
                11, // height
                $this->GetX(), // pos x
                $this->GetY(), // pos y
                "Page " . $this->getAliasNumPage() . " of " . $this->getAliasNbPages() . ' fm: ' . $this->getFooterMargin(),
                "TRBL", // borders
                $ln = 0, // line on next row
                false, // background
                true, // reset h
                'C', // alignment
                false // autopadding
            );
        }
        /**
         * Simple method just show the dynamic (though very simple :) ) changing of footer margin 
         * It simply adds 50 to margin by each call.
         */
        public function setDynamicFooter() {
            $this->setFooterMargin($this->dynamic_footer_margin);
            $this->dynamic_footer_margin += 50;
        }
    
        /**
         * Copied from tcpdf -"core"
         * Terminate the current page
         * @param $tocpage (boolean) if true set the tocpage state to false (end the page used to display Table Of Content).
         * @public
         * @since 4.2.010 (2008-11-14)
         * @see AddPage(), startPage(), addTOCPage(), endTOCPage()
         */
        public function endPage($tocpage=false) {
                // check if page is already closed
                if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) {
                        return;
                }
                /* NOTE this is only change to real endPage-method. Here we set the footer dynamically NOTE */
                /* CHANGE STARTS */
                $this->setDynamicFooter();
                /* CHANGE ENDS */
    
                // print page footer
                $this->setFooter();
                // close page
                $this->_endpage();
                // mark page as closed
                $this->pageopen[$this->page] = false;
                if ($tocpage) {
                        $this->tocpage = false;
                }
        }
    
    }
    
    // create new PDF document
    $pdf = new customTCPDF(
        PDF_PAGE_ORIENTATION, 
        PDF_UNIT, 
        PDF_PAGE_FORMAT, 
        true,   // unicode
        'UTF-8', 
        false,  // cache
        true    // true = pdf 1.4
    );
    $pdf->addPage();
    $pdf->addPage();
    $pdf->addPage();
    
    $pdf->Output('footer_margin_example.pdf', 'I');
    

    In this example we change the margin in endPage so that margin is changed before setFooter is called (the setFooter calls the Footer -method).

    Hope this answers to some of your questions.

    • Mikko
     
  • Mikko Salminen

    Mikko Salminen - 2015-10-07

    Whoops,

    Now that I gave it a try some "real" content it looked bad 'cause the content didn't actually follow the rules of footermargin I made another effort:

    <?php
    // Include the main TCPDF library (search for installation path).
    require_once('tcpdf/tcpdf.php');
    
    class customTCPDF extends TCPDF {
        /**
         *
         * @var float store for the dynamic margin. used in this test case
         */
        protected $dynamic_footer_margin = 50;
    
        public function __construct() {
            // "Transfers" arguments to parent class
            call_user_func_array('parent::__construct', func_get_args());
    
            // Make sure that the footer prints
            $this->SetPrintFooter(true);
            $this->setFooterData(array(0,0,0),array(0,0,0));
        }
        public function Footer() {
            /* changed so that footer margin is also displayed */ 
            /* postion is changed to getX and GetY, so we actually use the margin we setted */
            $this->writeHTMLCell(
                0, // width
                11, // height
                $this->GetX(), // pos x
                //$this->GetY(), // pos y
                $this->h - $this->footer_margin, // pos y
                "Page " . $this->getAliasNumPage() . " of " . $this->getAliasNbPages() . ' fm: ' . $this->getFooterMargin(),
                "TRBL", // borders
                $ln = 0, // line on next row
                false, // background
                true, // reset h
                'C', // alignment
                false // autopadding
            );
        }
        /**
         * Simple method just show the dynamic (though very simple :) ) changing of footer margin 
         * It simply adds 50 to margin by each call.
         */
        public function setDynamicFooter() {
            $this->setFooterMargin($this->dynamic_footer_margin);
            $this->dynamic_footer_margin += 20;
        }
    
        public function AddPage($orientation='', $format='', $keepmargins=false, $tocpage=false) {
            if ($this->inxobj) {
                    // we are inside an XObject template
                    return;
            }
            if (!isset($this->original_lMargin) OR $keepmargins) {
                    $this->original_lMargin = $this->lMargin;
            }
            if (!isset($this->original_rMargin) OR $keepmargins) {
                    $this->original_rMargin = $this->rMargin;
            }
            // terminate previous page
            $this->endPage();
            // start new page
            $this->setDynamicFooter();
            $this->SetAutoPageBreak(true, $this->getFooterMargin());
            $this->startPage($orientation, $format, $tocpage);
        }
    
    }
    
    function getLorem($paragraphs = 1) {
        $lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris nec sapien eros. Praesent nisi ex, tempor sit amet tempor sit amet, mattis a libero. Pellentesque convallis lorem risus, volutpat volutpat tellus posuere quis. Vivamus ut vulputate ex. Phasellus feugiat porttitor justo vel pretium. Curabitur interdum quam velit, ut sodales est cursus nec. Praesent auctor ligula ac nunc suscipit commodo gravida sed ipsum. Nunc eget nulla ante. Maecenas luctus ultricies lacus eu tincidunt. Curabitur nulla dolor, vehicula sed ex at, dignissim dictum erat. Vestibulum facilisis ipsum sit amet lacus cursus tempus. Aliquam mauris libero, efficitur sit amet rhoncus quis, finibus non magna. Praesent quis velit porta, pharetra nulla at, tincidunt ante.';
        $ret = '';
        for ($i = 0; $i < $paragraphs; $i++) {
            $ret .= $lorem . "\n\n";
        }
        return $ret;
    }
    
    // create new PDF document
    $pdf = new customTCPDF(
        PDF_PAGE_ORIENTATION, 
        PDF_UNIT, 
        PDF_PAGE_FORMAT, 
        true,   // unicode
        'UTF-8', 
        false,  // cache
        true    // true = pdf 1.4
    );
    $pdf->addPage();
    /* dynamic footer-margin example with content */
    $pdf->writeHTMLCell(
                0, // width
                11, // height
                $pdf->GetX(), // pos x
                $pdf->GetY(), // pos y
                getLorem(25),
                "TRBL", // borders
                $ln = 0, // line on next row
                false, // background
                true, // reset h
                'C', // alignment
                false // autopadding
            );
    
    $pdf->Output('footer_margin_example.pdf', 'I');
    

    Here we have a great big content (of repeated lorem ipsum) so that the content spans over multiple pages. Now the footer-margin is applied in addPage and the SetAutoPageBreak is called (so the content actually works with the dynamic margin).

    Hopefully this will satisfy your needs :)

    • Mikko
     
    • Prakash Reddy N

      Prakash Reddy N - 2017-09-29

      Hi Mikko, this is a great example regarding tcpdf and it will auto break page based on dynamic content. But how can do like
      for normal pages, footer margin will be 20, and same will be used for autopagebreak
      but for last page of pdf need footer margin as 60 and same be used as autopagebreak for the last page only.

      what I meant to ask is show dynamic footer, only to last page irrespective of number of pages in pdf and the pdf got common header for all pages. you can see the sample as attached. Is there solution for this kind of situation.

       

Log in to post a comment.