Bootstrap not rendering
Asked Answered
C

1

7

The question is splitted in different section:

  • Little preamble and sharing of the tries done
  • Folder structure and code to reproduce the problem
  • Showing and explaining the problem
  • Questions

Preamble

I have created a simple Flask 1.1.1 application with Python 3.8 on Raspbian.

I'm trying to implement the generation of PDF file using PdfKit, but I'm facing some problem with the bootstrap rendering.

I have alredy tried to search on google and I have found two articles:

As said in the repo README.md I has installed the static binary of wkhtmltopdf:

Warning! Version in debian/ubuntu repos have reduced functionality (because it compiled without the wkhtmltopdf QT patches), such as adding outlines, headers, footers, TOC etc. To use this options you should install static binary from wkhtmltopdf site or you can use this script.

There is an option called --user-style-sheet to use as workaround for something:

Warning This is a workaround for this bug in wkhtmltopdf. You should try --user-style-sheet option first.

The problem is that I don't know for which bug because the reference page is offline.


Code and folder

The project folder structure is the following:

WebServer/
├── Rembe
│   ├── __init__.py
│   ├── static
│   │   ├── content
│   │   │   ├── bootstrap.css
│   │   │   ├── bootstrap.min.css
│   │   ├── fonts
│   │   │   ├── glyphicons-halflings-regular.eot
│   │   │   ├── glyphicons-halflings-regular.svg
│   │   │   ├── glyphicons-halflings-regular.ttf
│   │   │   ├── glyphicons-halflings-regular.woff
│   │   │   ├── glyphicons-halflings-regular.woff2
│   │   ├── scripts
│   │   │   ├── bootstrap.js
│   │   │   ├── bootstrap.min.js
│   ├── templates
│   │   ├── test_page.html
│   │   └── test_pdf_report.html
│   └── views.py
└── runserver.py

The code to reproduce the problem (avoid the bootstrap stuff, you can download it from the official website, I have the code from it):

init.py

from flask import Flask

app = Flask(__name__)

db = SQLAlchemy(app)

import Rembe.views

runserver.py

from os import environ, path, walk
from Rembe import app

if __name__ == '__main__':
    # Folder to monitor and check if the server needs to be reloaded
    extra_dirs = ['/home/pi/WebServer/', '/home/pi/WebServer/Rembe/', '/home/pi/WebServer/Rembe/templates/']
    extra_files = extra_dirs[:]
    for extra_dir in extra_dirs:
        for dirname, dirs, files in walk(extra_dir):
            for filename in files:
                filename = path.join(dirname, filename)
                if path.isfile(filename):
                    extra_files.append(filename)

    app.run('0.0.0.0', 80, False, extra_files=extra_files)

views.py

from flask import render_template, url_for, send_from_directory
from Rembe import app
import pdfkit

@app.route('/')
@app.route('/test_page')
def test_page():
    return render_template(
        'test_page.html', title='test'
    )

@app.route('/test_view', methods=['GET', 'POST'])
def test_view():
    return render_template('test_pdf_report.html', my_custom_value='TEST PARAMETER')

@app.route('/test_download', methods=['GET', 'POST'])
def test_download():
    filename = 'report.pdf'

    string_page = render_template('test_pdf_report.html', my_custom_value='TEST PARAMETER')
    options = {'enable-local-file-access': ""}
    pdfkit.from_string(string_page, f'/tmp/{filename}')

    return send_from_directory(directory='/tmp/', filename=filename)

test_page.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }} - TEST</title>
    <link rel="stylesheet" type="text/css" href="/static/content/bootstrap.min.css" />
</head>

<body>

    <div class="container body-content">
        <a href="{{url_for('test_view')}}">test</a>
        <label> | </label>
        <a href="{{url_for('test_download')}}">Download</a>
    </div>

</body>
</html>

test_pdf_report.html

<html>
<head>
    <link href="{{ url_for('static', filename='content/bootstrap.min.css', _external=True) }}" rel="stylesheet">
</head>
<body>

    <div class="row">
        <div class="col-sm-12">
            <h2 style="text-align: center">REPORT TITLE - {{my_custom_value}}</h2>
        </div>
    </div>

    <div class="row">
        <div class="col-sm-6">
            <p>ROW 1 - COLUMN 1</p>
        </div>

        <div class="col-sm-6">
            <p>ROW 1 - COLUMN 2</p>
        </div>
    </div>

    <div class="row">
        <div class="col-sm-6">
            <p>ROW 2 - COLUMN 1</p>
        </div>

        <div class="col-sm-6">
            <p>ROW 2 - COLUMN 2</p>
        </div>
    </div>

    <div class="row">
        <div class="col-sm-6">
            <p>ROW 3 - COLUMN 1</p>
        </div>

        <div class="col-sm-6">
            <p>ROW 3 - COLUMN 2</p>
        </div>
    </div>

</body>
</html>

Problem

This project generate a white page with two clickable text: test and download

ClickableText

Clicking on the text test the rendered page is correct and the bootstrap correctly work, the rows/columns are in the right place.

testImage

Clicking on the text Download the pdf open but bootstrap is not rendered and the rows/columns are aligned to the left of the page.

downloadImage

The output of the server tell me all is good:

Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done

I has also tried to generate the PDF directly with the wkhtmltopdf library as follow:

wkhtmltopdf --enable-local-file-access test_pdf_report.html /tmp/mypdf.pdf

The command execute and generate the PDF without rendering bootstrap, the console output is:

Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done

Questions

I have two questions:

  • PdfKit module is compatible with bootstrap?

  • There is a way to solve my problem and download the PDF file rendered as the HTML page with the rows/columns correctly formatted?

Thank you for your time.

Councilwoman answered 6/10, 2020 at 15:35 Comment(8)
According to what i have been looking at, I can answer your first question. Yes it is compatible. As other questions link to using PdfKit such as: https://mcmap.net/q/1628409/-module-that-converts-html-to-pdf-module-compatible-with-bootstrap-and-flaskHaematothermal
Thank you @PythonLuaMaster, probably i'm missing something in the code or something else.Councilwoman
No problem, hope you figure it out.Haematothermal
Can you open your browser's DevTools and check that the browser can find bootstrap.min.css on the test_pdf_report.html page. I suspect that something's going wrong with the path that url_for generates seing that Bootstrap is successfully loaded when you don't use url_for.Martyrize
Hi @SimeonNedkov, If I open the DevTools and inspect the page <head> I can see <link href="http://10.10.4.195/static/content/bootstrap.min.css" rel="stylesheet"> so url_for is correctly working. Opening the url 10.10.4.195/static/content/bootstrap.min.css I can see my boostrap file. There is no error in console.Councilwoman
Good! So the problem is that the columns should be aligned to the right of the page, correct?Martyrize
This is the expected PDF output. The bootstrap default view for rows/columnsCouncilwoman
please can you help me make the TOC? i believe i need to pass toc = {'xsl-style-sheet': 'toc.xsl'}, but i don't know what is supposed to go in that file...Beatify
G
1

I ran into this same problem today. In addition I observed that it did load and use some of bootstrap. Like you, all my columns were renderings as full width. I believe I found that the issue was actually in wkhtmltopdf. It seems to have a problem with the media queries. This doesn't solve them problem but it explains what is happening. Some people have found work arounds for their specific situations but I haven't found one that works for me at this point.

Converting Twitter bootstrap page into PDF with wkhtmltopdf : span issue

https://github.com/barryvdh/laravel-snappy/issues/258

UPDATE

I was able to downgrade to Bootstrap 3 and update my markup to account for this change in class names and had much better results. I believe the problem is the addition of Flexbox in Bootstrap 4 which isn't working in wkhtmltopdf

Geek answered 27/1, 2022 at 15:52 Comment(1)
The problem still exists with Bootstrap 5. Following @Nexeh, I used Bootstrap 3 with wkhtmltopdf from wkhtmltopdf.org instead of the pre-packaged one for Debian.Grady

© 2022 - 2024 — McMap. All rights reserved.