To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit c87545a3 authored by moserfl's avatar moserfl 💬
Browse files

Add new file

parent 125e6a3d
PDF = PestesDateiFormat?
Dieser Artikel ist Teil des gleichnahmigen Vortrages vom 07.05.2021. Anmeldung für diesen Event und weitere der Free Software & Open Source Vortragsreihe REPLICATE unter events.thealternative.ch.
Geschichte
Das PDF hat als überteuerte, etwas schwergewichtige, "share document"-Alternative angefangen. Entwickelt wurde es von Adobe, bereits damals ein Schwergewicht mit alles Typographie. Adobe hatte als Erfinder von PostScript (das, was auch heute noch am Schluss beim Drucker landet) viel (vermutlich schmerzhafte) Erfahrung mit Interopability gesammelt.
Nach Jahren ohne grosse Begeisterung für ein 700$ Bearbeitungs- und 50$ Ansehprogramm hat Adobe den Preis fürs Ansehen erlassen: Geboren war der gratis Adobe Reader. Das Problem der "initial Population" wurde gelöst, in dem die US Tax Authorities einfach damit angefangen haben zu arbeiten. Jeder brave Steuerzahler hatte nun eine Version davon bei sich zu Hause, und mehr und mehr Unternehmen haben sich auch darauf verlassen.
Das initiale Investment zahlte sich aus; nachdem das Format auch in der Grafik- und Zeitungsindustrie Fuss fasste, konnte es die konkurrierenden Produkte langsam verdrängen. Dem Kampf wurde aber eine relativ kompakte Spezifikation geopfert; jährliche Iterationen fügten Formulare, Video, Verschlüsselung und weiteres hinzu. Auch - als Omen für die derzeitigen webshit-Jahre - JavaScript gehörte dazu.
Geendet hat es in der Version 1.7 (mit besserem 3D Support!), seit 2008 auch ein ISO Standard: ISO 32000-1:2008. Da aber seither nur noch die ISO weitere Versionen herausgeben kann, hat Adobe (clever!) "Extensions" erfunden. Seit der "Version 1.7 Adobe Extension Level 3" scheint das aber nun auch sein Ende gefunden zu haben. 2017 ist schliesslich das zurzeit aktuelle ISO PDF 2.0 erschienen.
Zweck
PDFs sind dazu da, Sachen darzustellen. Gleich wichtig wie der Inhalt ist dabei das Layout: Auf allen Geräten muss das Dokument exakt gleich aussehen. Anders als man dies vom Web kennt, passt es sich auch nicht an das darstellende Gerät an. Der Use-Case sind Dokumente: Man möchte nicht, dass die teuer designte "Corporate Identity" (CI) durch so nebensächliches wie "Realität" und "Lesbarkeit" Schaden nimmt. Druckerzeignisse von hoher Qualität profitieren davon, das sie beim Designer genau gleich aussehen, wie das was am Schluss beim Drucker herauskommt (ausser den Farben, aber das ist ein Thema für ein anderes Mal).
Wenn man dieses Grundkonzept mal akzeptiert hat, dann funktioniert es eigentlich ganz gut: PDFs stellen Sachen dar, und zwar überall genau gleich. Die Kontrolle des Erzeugnisses auf diversen Endgeräten fällt weg, und auch wenn das .pdf Millionen Empfänger erreicht, bleibt der Schlaf tief und erholsam. Der Erfolg des Formates ist erklärt.
Das Dateiformat
PDF ist ein Textformat, strukturiert ähnlich wie XML, einfach etwas weniger Struktur. Am besten einmal ein kleines PDF im Texteditor öffnen und durchschauen. Zum Beispiel vom Kontoauszug; diese PDFs haben oft etwas weniger komischer binary Anteil wie dies z.B. Tex generierte Dokumente haben. Es würde mich nicht erstaunen, wenn das meiste über das Format von solchen simplen PDFs selber zusammengereimt werden kann: Abgesehen von den Auswüchsen wie Formulare oder Schriftarten ist es nämlich ganz schön simpel gehalten.
Der Parser muss eigentlich nur Dictionaries (key-value Datenstruktur) und Streams (binary blobs) verstehen. Das ist praktisch: Die meisten PDFs Dateien sind streng genommen fehlerhaft generiert, und in dem die Parsers nur diese beiden Objekte unterscheiden müssen, können trotzdem die allermeisten PDFs angezeigt werden. Die meisten Readers sind auch ganz gut darin; schliesslich gibt der Nutzer dem PDF-Viewer Schuld, wenn etwas nicht funktioniert, und nicht dem Generator.
Eine Abstraktionsebene höher gibt es dann einen Header (die PDF Version), einen Trailer mit der Cross Reference Table (Byte Offsets zu den verschiedenen Teilen des PDFs) und den Body (mit dem ganzen Inhalt). Die Cross Reference Table war früher einmal nützlich, um die relevanten Teile des PDFs schnell anzuzeigen. Bei aktuellen Readers wird diese Sektion aber vermutlich ignoriert; auch komplett falsche Werte haben keinen Einfluss auf die Darstellung.
Als Inhaltsarten gibt es nenneswerterweise Bilder, Text und Schriftarten. Jeder dieser Inhalte ist an eine jeweilige "Page" gebunden, mit spezifizierten x/y Koordinaten. Ganz nach PDF-Konzept gibts hier keine magic: Alle Angaben sind absolut und keine automatische Zentrierung oder Skalierung wird angeboten. Auch beim Text müssen so Umbrüche in einem Paragraph oder der Abstand zwischen den Buchstaben im Blocksatz explizit definiert werden.
Wirklich toll wirds aber erst mit Schriftarten. Das PDF hat ganze 14 Standardschriftarten; es sind die allseits beliebten Times Roman, Courier und Helvetica, und ZapfDingbats und Symbol (Emojis bevors Emojis gab). Dazu gibts diverse Standard Ein-Byte Encodings; das brauchbarste für Europäer ist das WinAnsiEncoding. Für anspruchslose Kunden und deutsche, französische oder italienische Korrespondez mag man damit wegkommen. Ab dem ersten Smørrebrød ist aber Schluss: Dann muss man mit eigenen "Embedded Fonts" arbeiten.
TrueType
Adobe war neben PostScript (und auch wegen PostScript) auch an der Entstehung von Schriftarten merklich beteiligt. Zuerst "Barsch" gennant, wurde das noch heute weit verbreitete TrueType Format mit der Dateiendung .ttf in den 1980er Jahren entwickelt (also kurz vor Erscheinung des PDF Formats).
Das .ttf Format war einfach erweiterbar: In einer Art Inhaltsverzeichnis am Anfang der Datei wird definiert, welche "Tabellen" die Datei enthält. In dieses Inhaltsverzeichnis einfach neue Tabellen aufzunehmen (die von alten Programmen einfach ignoriert wurden) war ein Leichtes. Sowohl Adobe, also auch Apple und Microsoft, haben in den vergangenen Jahrzenten munter von dieser Möglichkeit gebraucht gemacht. Als neueste Errungenschaften dieser Weiter(?)entwicklung sind die Formeln in Word, aber auch die hautfarbenen Emojis zu nennen.
Unter den nützlichen Tabellen ist eine mit den Glyphen (den Vektoren, die den Charakter tatsächlich darstellen) sowie mehrere Tabellen mit Grösseninformationen davon. Auch zentral ist die CMap Tabelle, die Unicode Charaktere ihren Glyphen zuweist. Minimal braucht es 13 Tabellen; viele davon haben mehrere Versionen (die CMap Tabelle beglückt mit fünf vielgenutzten Formaten und noch ein paar esoterischen) oder werden je nach Betriebssystem zu unterschiedlichen Ausprägungen interpretiert oder ignoriert.
Schriftarten einbetten
TrueType Schriftarten können als CIDFontType2 ins PDF aufgenommen werden. Dafür braucht es zwei Elemente: Eine CMap (als PostScript definiert) und das TTF (als binary stream). Warum das PDF nicht einfach die CMap Tabelle der TrueType Schriftart verwendet, kann ich nicht beantworten.
Man ahnt es: Damit die PDF CMap geschrieben werden kann, muss die TTF Datei bis ins Detail gekannt werden, insbesondere wie Charaktere im TTF aufeinander folgen. Möchte also ein PDF mit "Embedded Fonts" generiert werden, müssen auch die entsprechenden TTF Dateien gelesen und geschrieben werden können.
PDF Libraries
Obwohl alle mit dem PDF Format arbeiten (frei nach Zawinksi: "Every program attempts to expand until it can generate PDFs."), möchte sich niemand wirklich damit befassen. So scheint es im PHP Universum gerade eine einzige ernstzunehmende Implementierung eines PDF Generators zu geben. Zwar existieren einige andersnamige PDF libraries; beim genau Hinsehen sind diese aber alle entweder eine a) Abstraktion des richtigen Generators, oder b) ein Rewrite des gleichen Authors (mittlerweile deren drei). Der Code des originalen Authors bleibt dabei unverwechselbar; das unkonventionelle Naming Schema (private methoden werden klein geschrieben, öffentliche gross) und der Klassenkampf (eine reicht doch!) sucht seinesgleichen.
Bevor jetzt in anderen Technolgien gelacht wird; zumindest für python gilt das gleiche: Die einzige ernstzunehmende Python library ist schlicht eine 1:1 Übersetzung des PHP codes, inklusive Gross- und Kleinschreibung. Der Maintainer der Rust library hat nach Version "0.3.2" bereits keine Lust mehr, und die JavaScript library publiziert die Code Coverage lieber auch nicht.
Viele webshit Entwickler haben resiginiert: Sie generieren HTML & CSS, und fahren kurzerhand Chrome Headless (= Chrome ohne UI) hoch, um dort das "Drucken" Feature zu verwenden. "Fixed it, Boss".
Die Lösung
Die Lösung ist natürlich: Einfach alles selber neu schreiben. Die Hufeisentheorie der Informatik ist schliesslich, dass sich "mühsam" und "interessant" im Extremum wieder trifft.
Da schon gut 100 Seiten der 900 Seiten Spezifikation umgesetzt sind, sind bereits fast alle relevanten Funktionen implementiert. Es fehlt nur noch herauszufinden, warum der Text in meinen generierten PDFs nicht selektiert werden kann (Contributions welcome!), und wie Paragraphen optimal mit Textumbrüche versehen werden können. Zumindest letzteres hat Donald Knuth bereits 1981 gelöst, und was Knuth nicht aufhält, hält mich schliesslich auch nicht auf.
Das Projekt ist unter https://github.com/famoser/pdf-generator aufrufbar. Viewer discretion advised, es ist in PHP geschrieben.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment