Seite wählen

NETWAYS Blog

Automatic PDF Generation with Google Chrome

Many developers get, sooner or later, the task to generate PDF documents automatically. Though, less developers put their experiences and insights then into a blog-post to save others some hassle. So let me do you a favor by explaining how we utilize Google Chrome in headless mode to generate pretty PDF files from HTML.

I won’t go into the details why Google Chrome. If you found this blog entry I suppose you already tried other options without success or satisfying results. We sure have tried several other options (e.g. wkhtmltopdf, dompdf, tcpdf) but only Google Chrome provided us with the results we wanted.

Another advantage of Google Chrome is the possibility to instrument a remotely running instance. And that’s exactly how we instruct it to generate a PDF file for us. Though, not with Puppeteer but with plain chrome devtools protocol (CDP) communication over a websocket.

I’ll avoid any programming language specific examples. You can take a look here at our implementation in PHP. So, let’s start with it.

The Process to Print HTML to PDF

First you’ll need to connect with the browser by use of a websocket connection at: ws://10.11.12.13:9222/devtools/browser/79744167-25f0-41a8-9226-382fa2eb4d66

This is printed on stderr right at launch of the process and also available on the JSON api: 10.11.12.13:9222/json/version

The important bit is the browser id (79744167-25f0-41a8-9226-382fa2eb4d66) at the end of the URI. This changes every time the process is launched and can’t be configured.

Communicating with the browser now takes place over this socket by transmitting and receiving JSON messages. They are divided into four types:

Calls

These primarily originate from ourselves. They contain an id, a method and parameters:

{ „id“: <mixed>, „method“: <string>, „params“: <object> }

The id is chosen by us and should be different for each call. It’s sent back with the response so it’s possible to later associate it with the call we made. Though this is mostly relevant if you are not communicating synchronously, which we do. So this may just as well be an integer incremented by 1 each time.

Results

These are sent by the browser in response to an API call.

{ „id“: <mixed>, „result“: <mixed> }

Errors

If it’s not a response, it’s an error.

{ „id“: <mixed>, „error“: { „code“: <int>, „message“: <string> } }

Events

These may be sent by the browser at any time.

{ „method“: <string>, „params“: <object> }

Some of these are of interest to us. Some of them are not and can be ignored.

Operating the Browser As Usual

In order to let the browser print us a web page (or HTML) to PDF we need to instrument it the same as when we do it manually on the desktop.

First we need to open a new tab:

Call: { „id“: 1, „method“: „Target.createTarget“, „params“: { „url“: „about:blank“ } }

Result: { „id“: 1, „result“: { „targetId“: „418546565-d4f9-4d9f-8569-9ad8f9db7f9de“ } }

Now we have to communicate with the tab, which requires a new websocket connection to: ws://10.11.12.13:9222/devtools/page/418546565-d4f9-4d9f-8569-9ad8f9db7f9de

Before we can print anything we have to tell the browser where to load the content to print from. This may either be a URI (which then needs to be accessible for the browser) or raw HTML. I’ll stick to raw HTML here, since it’s the most flexible option anyway:

Call: { „id“: 2, „method“: „Page.setDocumentContent“, „params“: { „frameId“: „418546565-d4f9-4d9f-8569-9ad8f9db7f9de“, „html“: <html> } }

Result: { „id“: 2, „result“: { } }

The next step is the instruction to print the page’s content to PDF:

Call: { „id“: 3, „method“: „Page.printToPDF“, „params“: <object> }

Result: { „id: 3, „result“: { „data“: <string> } }

What parameters you can use to influence the generation (e.g. the layout) are outlined in the official documentation.

The string you will get back is probably encoded in Base64, so decode it and store it where you want. The PDF file has been successfully generated.

If you are planning to use a single process to generate multiple PDFs with, remember to clean up afterwards. (i.e. closing the tab) Otherwise you will soon have a memory usage issue.

Call: { „id“: 4, „method“: „Target.closeTarget“, „params“: { „targetId“: „418546565-d4f9-4d9f-8569-9ad8f9db7f9de“ } }

Result: { „id“: 4, „result“: { „success“: <bool> } }

I hope this proves useful to you or convinces you to give Google Chrome a try to generate pretty PDFs. 🙂

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

PDF manipulieren mit pdftk


In diesem Beitrag möchte ich zeigen wie einfach man PDF’s mit pdftk manipulieren kann, zB. Seiten aus einem mehrseitigen PDF herausschneiden und daraus ein neues PDF generiert.
Was ich unter anderem auch schon gemacht habe, Seiten aus Büchern per Scanner als PDF erzeugt und dann mittel pdftk zu einem mehrseitigen PDF zusammengesetzt habe, Schwierigkeit hierbei ist, das die Seiten- Zahlen wieder wie im gedrucktem Buch übereinstimmen.
Zuerst müssen wir je nach Linux-Distribution das Paket pdftk installieren, falls nicht vorhanden, in meinem Fall:
zypper install pdftk
Für Redhat oder Debian based Distributionen:
apt-get install pdftk
aptitude install pdftk
yum install pdftk

Jetzt werde ich ein paar Anwendungsbeispiele  aufzeigen:
Seiten herausschneiden aus einem mehrseitigen PDF
pdftk datei.pdf cat 4-7 12 output Dokument.pdf
Es werden aus datei.pdf die Seiten 4 bis 7 plus Seite 12 herausgeschnitten und als Dokument.pdf gespeichert.
Einzelne PDF’s zu einem mehrseitigen PDF zusammenfügen:
pdftk datei1.pdf datei2.pdf datei3.pdf cat output gesamt.pdf
Verschiedene Seiten aus mehreren PDF-Dateien zu einer neuen PDF-Datei zusammenführen:
pdftk A=datei1.pdf B=datei2.pdf cat A3-7 B2-6 A10 output neu-gesamt.pdf
In diesem Beispiel werden mit sogenannten „Handels“(A,B) zuerst die eingelesenen Files und dann die extrahierten Seiten angegeben herausgeschnitten und in ein neues PDF zusammengesetzt.
Aus einem mehrseitigen PDF-Datei Einzelseiten generieren:
pdftk mehrseitiges-pdf.pdf burst output ~/Zielverzeichnis/Seite_%02d.pdf
Hier wird das mehrseitige PDF-Dokument in seine Einzelseiten zerlegt und als Namen Seite_Seitenzahl.pdf benannt, wobei 2 d für zwei Dezimalstellen steht.
Ich könnte hier noch mehr Anwendungsmöglichkeiten aufzählen, aber fürs erste sollte es mal reichen,
die Man-Page man pdftk gibt eine detaillierte Beschreibung über dieses Tool und seine Anwendungsmöglichkeiten.
Mir hat dieses Tool schon öfters geholfen, z.B früher bei Bewerbungsmappen wo Zeugnisse oder Anlagen in eine Gesamt-Bewerbung-mappe als PDF zusammengesetzt wurden oder Bücher als PDF-Datei generieren, wobei man das gedruckte Exemplar in seine Einzelseiten zerlegen musste um es einzuscannen.
Noch etwas WICHTIGES:
WIR SUCHEN NOCH NEUE KOLLEGEN!! Bewerbung unter jobs@netways.de
 

Johannes Carraro
Johannes Carraro
Senior Systems Engineer

Bevor Johannes bei NETWAYS anheuerte war er knapp drei Jahre als Systemadministrator in Ansbach tätig. Seit Februar 2016 verstärkt er nun unser Team Operations als Senior Systems Engineer. In seiner Freizeit spielt Johannes E-Gitarre, bastelt an Linux Systemen zuhause herum und ertüchtigt sich beim Tischtennisspielen im Verein, bzw. Mountainbiken, Inlinern und nicht zuletzt Skifahren.

PDF's mit Showoff

Graphite_TrainingShowoff habe ich ja bereits in einem früheren Blogpost näher behandelt. Heute möchte ich nun etwas über die PDF-Generierung mit Showoff berichten, da hier die ein oder andere Stolperstelle überwunden werden muss.
Generell gibt es drei Möglichkeiten um über Showoff PDF’s zu erstellen, für die ersten beiden muss Showoff zwingend im Präsentationsmodus mit showoff serve gestartet sein. Über den Aufruf http://localhost:9090/pdf, der übrigens auch über einen Button im Presenter-Modus ausgewählt werden kann, ist es nun möglich ein PDF der Präsentation zu erstellen. Leider funktioniert diese Methode nur mit der Masterpräsentation, d.h. supplementäre Aufrufe wie für Exercises oder Solutions (siehe: https://github.com/puppetlabs/showoff/blob/master/documentation/AUTHORING.rdoc) funktionieren damit nicht.
Die zweite Möglichkeit ist der Aufruf über http://localhost:9090/print im Druckmodus. Das Drucken wird hier noch manuell durchgeführt, also brauchen wir dafür einen lokalen PDF-Drucker. Im Gegensatz zur ersten Methode können hier auch die ergänzenden Bereiche beispielsweise über http://localhost:9090/supplemental/exercises aufgerufen werden. Beide bisher vorgestellten Möglichkeiten haben jedoch einige Probleme gemeinsam: Unterschiedliche Browservarianten und teilweise auch verschiedene Browserversionen interpretieren das dahinter liegende CSS oft anders. Dadurch bekommt man leider oft sehr schlechte Druckergebnisse. Ein weiteres Problem ist das diese Vorgänge nicht automatisierbar sind und daher immer von jemandem manuell durchgeführt werden müssen.
Daher nun also die dritte Möglichkeit: Das Showoff-Kommando lässt sich auf der CLI mit einem Parameter namens static aufrufen, dazu muss die Präsentation also nicht einmal gestartet werden. Dieser static-Parameter unterstützt auch die supplementären Teile:

# showoff static print
# showoff static supplemental exercises

Danach befindet sich im neuen Unterordner „static“ eine HTML-Datei (index.html). Mit weiteren Tools wie beispielsweise wkhtmltopdf kann nun daraus im Anschluss ein PDF-Dokument erstellt werden. Der große Vorteil dabei ist, das nun ganz einfach auch Seitenzahlen oder ein Copyright-Hinweis hinzugefügt werden kann. Ein Beispielaufruf von wkhtmltopdf sieht so aus:

# wkhtmltopdf -s A5 --print-media-type --footer-left [page] --footer-right '© NETWAYS' static/index.html /HAPPY/NEW/YEAR.pdf

Wer nun schon ganz gespannt auf das Ergebnis ist, dem möchte ich unsere Trainings nahe legen, denn da kommt genau das zum Einsatz.

Markus Waldmüller
Markus Waldmüller
Head of Strategic Projects

Markus war bereits mehrere Jahre als Sysadmin in Neumarkt i.d.OPf. und Regensburg tätig. Nach Technikerschule und Selbständigkeit ist er nun Anfang 2013 bei NETWAYS als Senior Manager Services gelandet. Seit September 2023 kümmert er sich bei der NETWAYS Gruppe um strategische Projekte. Wenn er nicht gerade die Welt bereist, ist der sportbegeisterte Neumarkter mit an Sicherheit grenzender Wahrscheinlichkeit auf dem Mountainbike oder am Baggersee zu finden.

Neue Firmware für Neon110 verfügbar

Ab sofort steht für unser Neon110 Netzwerkthermometer eine neue Firmware (Version 1.5) bereit. Sie behebt einige Probleme in der Passwortverwaltung und lässt nun einige Sonderzeichen im Passwort zu. Vorher kam es zu Problemen, wenn Passworneon-110-netzwerksensor-fur-temperatur-und-luftfeuchtigkeitt Sonderzeichen enthielt. Das Gerät ließ sich in diesem Fall nicht mehr unlocken. Die Anforderung mit Sonderzeichen im Passwort kam bei einem unserer Kunden auf. Kurzer Hand haben wir die Anfrage mit dem Hersteller durchgesprochen und dieser lieferte eine entsprechende Anpassung via Softwareupdate. Die aktuelle Firmware für das Neon 110 können Sie sich hier herunter laden. In der Anleitung ist die Vorgehensweise für das Update ausführlich beschrieben.
Sie möchten auch eine angepasste Firmware für Ihr Gerät? Fragen Sie doch einfach einmal bei uns an, wir finden sicher eine Lösung für Ihre Anforderung.

neon-110-netzwerksensor-fur-temperatur-und-luftfeuchtigkeit (1)

Ansicht Webinterface Neon110