How do I set header and footer in a PDF, from HTML, with knp-snappy-bundle?
Asked Answered
H

2

3

Long story short

With knp-snappy-bundle I can't generate a header in the PDF, while I can actually generate a footer.

Is it a bug, a feature, or I'm doing something wrong?

Details

1. Environment

I'm testing the knp-snappy-bundle, I've also installed the wkhtmltopdf binary from h4cc. This is part of my composer.json:

"h4cc/wkhtmltopdf-amd64": "^0.12.3",
"knplabs/knp-snappy-bundle": "^1.5",

The resulting binary of wkhtmltopdf says this:

$ vendor/bin/wkhtmltopdf-amd64 --version
wkhtmltopdf 0.12.3 (with patched qt)

2. Without headers or footers, it works

I've setup a controller that uses the knp-snappy-bundle and it works:

This is my PdfController:

public function downloadPdfAction( string $docName ) : Response
{
    $pdf = $this->getPdf( $docName );

    return new PdfResponse( $pdf, $this->getFilename( $docName ) );
}

private function getPdf( string $docName ) : string
{
    $html = $this->renderView( 'AppBundle:documents:' . $docName . '.pdf.twig' );

    $options = [];

    $generator = $this->getPdfGenerator();
    $pdf = $generator->getOutputFromHtml( $html, $options );

    return $pdf;
}

private function getPdfGenerator() : Pdf
{
    $generator = $this->get( 'knp_snappy.pdf' );

    return $generator;
}

It basically:

  • Has a downloadPdf action that
      1. Gets a PDF document by its name, passed in as a parameter. In this example we'll use 'helloWorld'.
      1. Returns a new Response created with the content of the PDF, using the PdfResponse class in the bundle.
  • To get the PDF
      1. it renders a view with the twigengine.
      1. gets the service (splitted into another function getPdfGenerator()).
      1. uses the service to getOutputFromHtml() with no options passed-in.

This is my helloWorld.pdf.twig:

<html>
    <body>
        <div class="pdfPageBody">
            <h1>
                Hello, World!
            </h1>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </div>
    </body>
</html>

And here it is the resulting PDF, exactly as expected:

enter image description here

3. With headers and footers, it fails!

So I now add the header and footer. To do so, I just add a couple of twigs, render the HTMLs into a couple of variables, and pass them in into the options of the Pdf renderer:

private function getPdf( string $docName ) : string
{
    $html = $this->renderView( 'AppBundle:documents:' . $docName . '.pdf.twig' );

    $header = $this->renderView( 'AppBundle:documents:header.pdf.twig' );
    $footer = $this->renderView( 'AppBundle:documents:footer.pdf.twig' );

    $options = [
        'header-html' => $header,
        'footer-html' => $footer,
    ];

    $generator = $this->getPdfGenerator();
    $pdf = $generator->getOutputFromHtml( $html, $options );

    return $pdf;
}

The header and footer are identical one to each other, except for the contained text:

This is my header.pdf.twig:

<html>
    <body>
        <div style="border: 5px dashed crimson; color: maroon; background-color: darksalmon">
            This is a header
        </div>
    </body>
</html>

And the footer.pdf.twig:

<html>
    <body>
        <div style="border: 5px dashed crimson; color: maroon; background-color: darksalmon">
            This is a footer
        </div>
    </body>
</html>

And wow!!! The footer gets rendered but the header does not!!

This is what I get:

enter image description here

To be noted in the image:

  1. There is "something" in the header. I can see the text of the page content like "clipped".
  2. The footer does not fully render, as it hides all the bottom border-lines, and the text base-line is aligned to the bottom edge of the page.

Soooo, hence my question!!

  • What should I do to get the header rendered as well?
  • Should'nt it be that I could see the header rendered in the PDF with this simple setup? Why does it not appear?
Hardcastle answered 30/11, 2017 at 22:22 Comment(0)
H
7

Solved!

Well, it seems that wkhtmltopdf is really strict to consider the doctype and it does weird things if not.

Inspired here: https://mcmap.net/q/596791/-fix-wkhtmltopdf-headers-clipping-content

So, I changed all the twigs to include <!DOCTYPE html>:

helloWorld.pdf.twig

<!DOCTYPE html>
<html>
    <body>
        <div class="pdfPageBody">
            <h1>
                Hello, World!
            </h1>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </div>
    </body>
</html>

header.pdf.twig

<!DOCTYPE html>
<html>
    <body>
        <div style="border: 5px dashed crimson; color: maroon; background-color: darksalmon">
            This is a header
        </div>
    </body>
</html>

footer.pdf.twig

<!DOCTYPE html>
<html>
    <body>
        <div style="border: 5px dashed crimson; color: maroon; background-color: darksalmon">
            This is a footer
        </div>
    </body>
</html>

Final result

I finally got this:

enter image description here

It happens to have:

  1. The header, with no weird clipping on the body
  2. The footer.

Hope to help!

Hardcastle answered 1/12, 2017 at 2:25 Comment(0)
T
0

I was still having this issue with my header even after making sure I had DocType set. It turns out it was because I was floating 2 divs in the header. Removed the float styles and it worked. There were still floated divs within the main content of the PDF which didn't cause any issues.

Thetes answered 12/5, 2021 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.