简体   繁体   中英

xhtml2pdf Pisa css broken none functional

I am trying to generate a PDF using html+css using xhtml2pdf.pisa using Django. However, I'm running into all sorts of weird issues with the CSS.

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 basic and nothing special, they are just pretty much copied verbatim from the web. I'm running into lots of weird issues:

  1. font-size, background-color works in external css, but only when applied on body or html tag.
  2. width, line-height etc does not work whatsoever, no matter external, internal, or inlined.
  3. margin-bottom on a parent div gets applied to every single child div instead of the parent div...
  4. all sorts of other random issues...

I cannot observe a pattern from these symptoms other than just thinking the css parser and layout engine is just totally incomplete and non-functional. However I cannot find anyone online who has the same issues as me. Am I crazy? I'm not sure what is happening here... any help would be appreciated.

Under the covers, xhtml2pdf uses reportlab to actually create the PDF.

Doing some debugging - I followed the execution of parser.py in xhtml2pdf to see whether I could work out where the CSS was 'going missing' or being applied to the wrong elements.

I found that the CSS was successfully parsed and the translation into document fragments (here in the code) worked OK, with the correct CSS elements being applied to the correct elements.

I believe the problem comes with the reportlab pdf rendering engine. It is documented here. It does not have a 1:1 mapping between CSS and the directives you can pass into it.

I first became aware of it answering this question . For instance in the table rendering section of the reportlab documentation (open-source User Guide, chapter 7, page 76), it is obvious that there is no analogue for the border-style CSS attribute - so although in theory you can specify a border style and no error will be thrown, that value will be ignored.

While investigating CSS to pdf mapping, I found this software (Javascript) that also maps HTML/CSS to pdf. I tried that on the HTML from this question and the other one I linked to. This manages to render the pages correctly into the pdf document, so I believe this is not a fundamental limitation of the pdf document specification, but rather of the reportlab module.

It seems to me this is a problem for xhtml2pdf . It seems particularly bad for tables, but obviously affects other types of document too. Sorry not to resolve your problem, but I hope this goes some way towards explaining it.

As explained in this answer only few css properties are supported and also you can't link to an external css file. You must put your css directly in your html page (declare a style tag inside the head tag of your html page).

In my case I'll consider using wkhtmltopdf via pdfkit. pdfkit is a wrapper to wkhtmltopdf.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM