Flask/xhtml2pdf: CSS-Parsing Problem

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

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?
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

@__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.
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich kenne das `xhtml2pdf` nicht, aber das HTML ist kein gültiges XML.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

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.
When we say computer, we mean the electronic computer.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

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
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

@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*).
When we say computer, we mean the electronic computer.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

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
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

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.
When we say computer, we mean the electronic computer.
Antworten