Why in pdf file generated with spatie/browsershot no header and last line of any page is cut off?

4.2k views Asked by At

In Laravel 8 app I make pdf file with browsershot and it mostly works ok for me, except case my data contains several pages, I have 2 problems :

  1. I do not see header which I define with footer (code below) : https://i.stack.imgur.com/nujuf.jpg

  2. I see last line of any page is cut off : https://i.stack.imgur.com/63o1k.jpg

I do it with code passing into control html content and generated filename:

        $filename_to_save = $option_output_filename . '.' . $option_output_file_format;
        $save_to_file     = 'generate_profile_card_' . Session::getId() . '_' . $filename_to_save;

        $today_date = getCFFormattedDate(Carbon::now(config('app.timezone')));
        $site_name  = config('app.name', '');

        $footerHtml = '<div class="card-text d1" style="background-color: #ffffff !important; width: 100%; margin : 0 !important;">
            <table style="width: 100%; font-family: \'system-ui\'; font-size: 12px !important; padding : 20px 0 0 0 !important; margin: 0 !important;
                color:#101010 !important; ;" >

                <tbody>';
        $footerHtml .= '
                <tr>
                    <td style="width:100%; border:0; border-top: 8px solid #c1c1c1; padding: 0; WWmargin: 21px 32px 2px 32px !important;" colspan="3">
                        <table style="width:100%;  ">
                            <tr>
                                <td style="width:30%;" class="d-2">
                                    Printed on: ' . $today_date . '
                                </td>
                                <td style="width:30%; " >
                                    <span class="pageNumber"></span><span>out of</span><span class="totalPages"></span>
                                </td>
                                <td style="width:40%;" >
                                    ' . $site_name . '
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
';

        $footerHtml .= '            </tbody></table>
        </div>';

        if (strtolower($option_output_file_format) == 'pdf') {
            Browsershot::html(htmlspecialchars_decode($this->requestData['adCardContent']))
                       ->showBrowserHeaderAndFooter()
                       ->headerHtml('<div style="height:280px !important; background : maroon !important; ">Ad Card</div>')
                       ->footerHtml($footerHtml)
                       ->showBackground()
                       ->margins(20, 10, 20, 10)
                       ->setOption(
                           'addStyleTag', // I inject some tailwindcss classes
                           json_encode([
                               'content' => '

.d1 {
    --tw-border-opacity: 1;
    border-color: rgba(220, 38, 38, var(--tw-border-opacity));
    border-width: 2px;
}

.d2 {
    --tw-border-opacity: 1;
    border-color: rgba(245, 158, 11, var(--tw-border-opacity));
    border-width: 4px;
}



    h3 {
       font-size: 32px;
       padding:4px;
    }
    h4 {
       font-size: 24px;
        padding:3px;
    }

.md:h-4/6 {
    height: 66.666667%;
}

.sm:h-4/5 {
    height: 80%;
}

.text-left {
    text-align: left;
}
.shadow-lg {
    --tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
    box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.p-2 {
    padding: 0.5rem;
}
.px-6 {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
}
.py-4 {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

.mb-5 {
    margin-bottom: 1.25rem;
}

.max-h-screen {
    max-height: 100vh;
}
.justify-between {
    justify-content: space-between;
}

.card-text {
    background : maroon !important;
    border: 4px dotted red !important;
}

.pageNumber {
    background : yellow !important;
}

.totalPages {
    background : blue !important;
}

.flex-col {
    flex-direction: column;
}
.flex {
    display: flex;
}

.modal_container {
    color: green !important;
    border-radius: 0.5rem;
    border-width: 2px;
    padding: 0.5rem;
    border: 4px dotted blue !important;
}


.overflow-y-auto {
    overflow-y: auto;
    border: 4px dotted green !important;
}


.float-left {
    float: left;
}

.big_badge {
    border-color: rgba(209, 213, 219, var(--tw-border-opacity));
    border-radius: 0.5rem;
    border-bottom-width: 2px;
    display: flex;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    margin: 0.5rem;
    padding: 0.75rem;
}

.mt-3 {
    margin-top: 0.75rem;
}

.pt-3 {
    padding-top: 0.75rem;
}'
                           ])
                       )
                       ->save($save_to_file);
            \Response::download(
                $save_to_file,
                $save_to_file,
                array('Content-Type: application/octet-stream', 'Content-Length: ' . $option_output_file_format)
            );

            return response()->download($save_to_file, $filename_to_save)->deleteFileAfterSend(true);

in composer.json :

"laravel/framework": "^8.12",
"spatie/browsershot": "^3.40",

How can it be fixed ?

MODIFIED : I still have these problems with pdf generating : I uploaded example on live server. Please open http://tads-back.my-demo-apps.tk/admin/ads/2/edit at login page credentials are already filled. Just click Login By the link above modal page will be opened and please click on “Generate" button. By default pdf file will be generated with problem I show in printscreens of my topic. I used this library with bootstrap 4.5 and did not have such problems. Also in the description of https://github.com/spatie/browsershot I did not see any errors description with page footer.

I my code I show how I set tailwind classes in

->setOption('addStyleTag'
    ...

    

Maybe tailwind has some rendering features which I missed?

Thanks!

1

There are 1 answers

4
MHIdea On

browsershot uses puppeteer package. According to puppeteer, footer and header are different htmls. So if you've included any css library like tailwindcss or bootstrap in the main page you intend to save, it doesn't mean they will be loaded for footer and header. in case of tailwindcss, you need to make sure any css classes used in footer and header are included in production build as postcss will eliminate unused classes to reduce final build assets.

To get a correct positioning and sizing you need to play with margins in browsershot and also correct styling of footer and header. As an example you need to increase vertical margin for this footer and font size in footer:

footer.blade.html:

<style>
    * {
        box-sizing: content-box;
    }

    footer {
        width: 100%;
        border: 1px solid yellowgreen;
        display: flex;
        flex-direction: row;
    }

    footer>div {
        color: blue;
        width: 100%;
        height: 20px;
        font-size: 10rem;
        text-align: center;
    }
</style>
<footer>
    <div>
        Printed on: {{$today_date}}
    </div>
    <div>
        {{$site_name}}
    </div>
    <div>footer</div>
</footer>

Then load footer html and use it with correct margins:

    $footerHtml =  view('footer', compact(['today_date', 'site_name']))->render();
        Browsershot::html($content)
            ->showBrowserHeaderAndFooter()
            ->headerHtml(view('header')->render())
            ->footerHtml($footerHtml)
            ->showBackground()
//->margins(20, 10, 20, 10) doesn't work with above footer html.
            ->margins(30, 10, 30, 10)
            ->save($save_to_file);