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:
- First without usefull answer.
- Second on github that refer to this SO question but the accepted answer is not working (I have download the BS without the Print media styles checked). Reading in the comment someone point to this answer but is related to the background color.
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
Clicking on the text test the rendered page is correct and the bootstrap correctly work, the rows/columns are in the right place.
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.
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.
bootstrap.min.css
on thetest_pdf_report.html
page. I suspect that something's going wrong with the path thaturl_for
generates seing that Bootstrap is successfully loaded when you don't useurl_for
. – Martyrize<head>
I can see<link href="http://10.10.4.195/static/content/bootstrap.min.css" rel="stylesheet">
sourl_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. – Councilwomantoc = {'xsl-style-sheet': 'toc.xsl'}
, but i don't know what is supposed to go in that file... – Beatify