Seite 1 von 1

Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 09:59
von sls
Folgendes Problem:

ich habe eine winzige Flask-App die via Web-Frontend über einige Forms Benutzereingaben entgegen nimmt und in einer Methode verarbeitet. Dabei werden die Werte in ein einem Jinja2-HTML-Template gerendert und der Rückgabewert davon (das gerenderte HTML) vom xhtml2pdf als PDF auf Platte gelegt. Das *tut* perse auch, nur hat xhtml2pdf Probleme das CSS zu parsen.

Konkret:

Code: Alles auswählen

@app.route('/test/', methods=('POST', 'GET'))
def test():
    if request.method == 'POST':
        html = render_template('output.html', foo=bar, fancy=value)       
        result_file = open('output.pdf', "w+b")
        pisa.CreatePDF(html, dest=result_file)
        result_file.close()

    return render_template('output.html')
CSS:

Code: Alles auswählen

#logo {
  margin-top: 60px;
  padding-left: 60px;
  padding-right: 60px;
  float: left;
}

#address {
  margin-top: 60px;
  padding-left: 5px;
  padding-right: 90px;
  padding-bottom: 20px;
  padding-top: 20px;
  float: right;
  border-style: solid;
  border-width: 0.5px;
  font-family: 'Times';
  font-size: 12pt;
}

#date {
  margin-top: 270px;
  padding-right: 130px;
  text-align: right;
  font-family: 'Helvetica';
  font-size: 12pt;

}

#text {
  margin-top: 150px;
  padding-left: 60px;
  padding-right: 60px;
  font-family: 'Helvetica';
  font-size: 12pt;
}

#greetings {
  margin-top: 60px;
  margin-left: 60px;
  margin-right: 450px;
  border-style: solid;
  border-width: 0.5px;
  padding: 3px;
  font-family: 'Helvetica';
  font-size: 12pt;
}

body {
  height: 297mm;
  width: 210mm;
  margin-left: auto;
  margin-right: auto;
  border-style: solid;
  border-width: 0.5px;
}
Und der Hinweis:

Code: Alles auswählen

127.0.0.1 - - [28/Jul/2018 10:50:28] "GET /static/style.css HTTP/1.1" 200 -
Selector name or qualifier expected:: ('', '"#logo {\\n  margin-t')
127.0.0.1 - - [28/Jul/2018 10:50:28] "GET /static/logo.png HTTP/1.1" 200 -
127.0.0.1 - - [28/Jul/2018 10:50:28] "GET /static/logo.png HTTP/1.1" 200 -
127.0.0.1 - - [28/Jul/2018 10:50:28] "POST /test/ HTTP/1.1" 200 -
Ich habe keinen blassen von CSS, es wird *so* allerdings korrekt von Flask als auch via direkten Browser-Aufruf gerendert, nur das PDF-Tool kommt damit nicht klar. Was mache ich falsch?

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 10:20
von __blackjack__
@sls: Flask ist CSS völlig egal, das reicht so etwas ja nur durch, und Browser fressen so ziemlich alles irgendwie. Ausser bei XHTML versuchen die aus den kaputtesten Sachen noch irgendwie etwas Anzeigbares zu machen.

Versuch doch mal Flask aus der Gleichung zu nehmen und zeige ein minimales, nachvollziebares Beispiel von CSS+HTML das zu dem Problem führt.

Das CSS ist übrigens valide.

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 10:36
von sls
@__blackjack__: als Ergänzung, das HTML kann natürlich nicht rein vom Browser korrekt verarbeitet werden, da die Ressourcen durch Flask / Jinja aufgelöst werden. Hier nochmal das HTML:

Code: Alles auswählen

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <link href="{{ url_for('static', filename='style.css', _external=True) }}" rel="stylesheet">
    </head>
    <body>
        <div id="logo">
            <img src="{{ url_for('static', filename='logo.png', _external=True) }}" witdh="233.28" height="62.4">
        </div>
        <div id="address">
            <p>some content here</p>
        </div>
        <div id="date">
            {{ foo }}
        </div>
        <div id="text">
            <p>some content there {{ fancy }} </p>
        </div>
        <div id="greetings">
            <p>And here of course</p>
            <img src="{{ url_for('static', filename='logo.png', _external=True) }}" witdh="233.28" height="62.4">
        </div>
    </body>
</html>
Vielleicht ist der Ansatz naiv, aber ich dachte mir dass es möglich ist dass man Flask/Jinja das HTML so rendern lässt und das "fertige" HTML-File dann als PDF erzeugt.

EDIT: ab einem Punkt hat Flask durchgedreht weil ich den Form-Input übergeben wollte, die Ressourcen aber nicht durch Flask auflösen lassen wollte sondern ganz normal via <img src="/pfad/zu/css"> usw.

EDIT2: ich habe es nochmal ausprobiert, und es scheint zu funktionieren wenn ich als href direkt den absoluten Pfad zum css und logo.png angebe, ABER: dieses schrottige PDF-Tool vermurkst das CSS so das am Ende nur Müll rauskommt.

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 11:47
von __blackjack__
Ich kenne das `xhtml2pdf` nicht, aber das HTML ist kein gültiges XML.

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 11:52
von sls
Mit pdfkit hat es auch nicht funktioniert. Das Ergebnis des PDFs schaut immer so aus, als wenn er mit dem A4-Format nicht klarkommt was ich im CSS definiert habe.

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 16:23
von noisefloor
Hallo,

ich hatte mir irgendwann auch mal xhtml2pdf angesehen, fand das aber (für meine Zwecke) nicht zufriedenstellend. HTML/CSS ist nun mal nicht für Drucksachen gemacht.

Mit ReportLab oder alternativ LaTeX -> PDF hast du die volle Layoutkontrolle, um ein schönes PDF zu bauen.

Gruß, noisefloor

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Samstag 28. Juli 2018, 20:19
von sls
@noisefloor: so wie ich das verstanden habe nutzt xhtml2pdf unter der Haube ReportLab. Es spricht aber eigentlich, eigentlich, nichts dagegen es direkt mit ReportLab zu treiben. Das einzige was ich noch nicht ganz geblickt habe ist, ob man dort auch externe css-Files einbinden kann, oder ob man das direkt irgendwo im Code verwurschteln muss und ob das so easy ist (das was ich bis dato sah ist mehr als das was ich in css *kann*).

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Sonntag 29. Juli 2018, 08:25
von noisefloor
Hallo,

ReportLab kann kein CSS. Da erfolgt das "stylen" des PDF in der Regel über Attribute der diversen Klassen. Wenn du ReportLab nutzt dann schau' dir direkt Platypus an, das ist die "high level" API. Direkt auf den Canvas zeichnen ist ziemlich aufwendig, weil du dich um alles selber kümmern musst.

Gruß, noisefloor

Re: Flask/xhtml2pdf: CSS-Parsing Problem

Verfasst: Montag 30. Juli 2018, 19:19
von sls
Mit `weasyprint` hat es nun letztlich geklappt. Ich muss dazu auch kein DIN-A4-Format im CSS angeben, das geschieht automatisch beim Erzeugen des PDFs, der HTML-Content orientiert sich dabei dann an diesen "Grenzen". Prinzipiell würde es auch mit xhtml2pdf / pdfkit und wie sie nicht alle heißen, funktionieren, die hauen aber immer irgendwelchen komischen Mist rein so dass der PDF-Plot einfach nicht so aussieht, wie er aussehen soll.