Xhtml2pdf pisa css broken none functional
I am trying to create a PDF using html + css using xhtml2pdf.pisa using Django. However, I am running into all sorts of weird CSS issues.
Below is my code:
from django.template.loader import render_to_string
import cStringIO as StringIO
import xhtml2pdf.pisa as pisa
import cgi, os
def fetch_resources(uri, rel):
path = os.path.join(settings.STATIC_ROOT, uri.replace(settings.STATIC_URL, ""))
return path
def test_pdf(request):
html = render_to_string('pdf/quote_sheet.html', { 'pagesize':'A4', }, context_instance=RequestContext(request))
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("UTF-8")), dest=result, link_callback=fetch_resources)
if not pdf.err:
return HttpResponse(result.getvalue(), mimetype='application/pdf')
return HttpResponse('Gremlins ate your pdf! %s' % cgi.escape(html))
And my template:
<!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
{% load static from staticfiles %}
{% load i18n %}
<meta charset="utf-8"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="content-language" content='{% trans "g_locale2" %}'/>
<title>{% block title %}{% endblock %}</title>
<style type="text/css">
@page {
size: A4;
margin: 1cm;
@frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
font-family: "Microsoft JhengHei";
}
}
@font-face {
font-family: "Microsoft JhengHei";
src:url('{% static "ttf/msjh.ttf" %}');
}
@font-face {
font-family: "Microsoft JhengHei";
src:url('{% static "ttf/msjhbd.ttf" %}');
}
@font-face {
font-family: "Helvetica";
src:url('{% static "ttf/Helvetica_Reg.ttf" %}');
}
table.styled-table tr th {
color: gray;
background-color: blue;
font-size: 14px;
font-family:"Microsoft JhengHei";
border: 1px solid black;
}
.biz_phone, .biz_fax {
display: inline-block;
width: 100px;
line-height: 32px;
}
.biz-info {
margin-bottom: 20px;
}
</style>
<link rel="stylesheet" href='{% static "css/pdf.css" %}'/>
</head>
<body>
<div id="main-content">
<div class="container">
<div class="biz-info">
<div class="biz_name">{{ proj.biz.name }}</div>
<div class="biz_address">{{ proj.biz.address }}</div>
<div class="biz_phone">{{ proj.biz.phone }}</div>
<div class="biz_fax">{{ proj.biz.fax }}</div>
</div>
<div class="table-div">
<table class="styled-table">
<tr class="row_header">
<th class="col_order">{% trans "g_item_num" %}</th>
<th class="col_name">{% trans "g_item_name" %}</th>
<th class="col_provider">{% trans "g_provider_name" %}</th>
<th class="col_budget_quantity">{% trans "g_quantity" %}</th>
<th class="col_price">{% trans "g_item_price" %}</th>
<th class="col_total_price">{% trans "g_item_total" %}</th>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
My code is pretty simple and nothing special, they are just copied verbatim from the internet. I faced a lot of strange problems:
- font-size, background-color works in external css, but only when applied to body or html tag.
- width, line-height, etc. does not work regardless of external, internal, or embedded.
- margin-bottom in parent div is applied to each child div instead of parent div ...
- all sorts of other random problems ...
I can't observe the pattern from these symptoms other than just thinking that the css parser and layout engine are just completely incomplete and non-functional. However, I cannot find anyone online who has the same problems as me. I'm crazy? I'm not sure what's going on here ... any help would be appreciated.
source to share
Under the covers is xhtml2pdf
used reportlab
to actually create the PDF file.
Doing some debugging - I ran parser.py in xhtml2pdf
to see if I could work where CSS
"goes missing" or applied to the wrong items.
I found that the CSS was parsed successfully and the translation into document fragments (here in the code) worked fine, with the correct CSS elements applied to the correct elements.
I believe the problem is with the reportlab
pdf rendering engine . This is described here. It has no 1: 1 mapping between CSS and directives that you can pass into it.
I first learned about this while answering this question . For example, in the table rendering reportlab
documentation section (Open Source User Guide, Chapter 7, page 76), it is obvious that there is no equivalent for the border-style
CSS attribute , so while in theory you can specify a border style and no error dumped, that value will be ignored.
While researching CSS mapping in pdf, I found this software (Javascript) that renders HTML / CSS to pdf as well. I tried this on the HTML from this question and another one I linked to. This allows the pages to be displayed correctly in the pdf document, so I believe this is not a fundamental limitation of the PDF document specification, but rather a module reportlab
.
It seems to me that this is a problem for xhtml2pdf
. This looks especially bad for tables, but clearly affects other types of documents. Sorry for not solving your problem, but I hope this will be a way to explain it.
source to share