Der JavaScript-PDF-Kreator (9.3.2009) Zu den JavaScript-Seiten

English (translated by Google ;)

PDF-Ergebnis:

Debug:

(Popup-PDF nur mit Konqueror)

 

Was'n das?

Mit dem JavaScript-PDF-Kreator kann man auf einfache Weise PDF-Daten in JavaScript erzeugen.

Wie funktioniert's?

Antwort: ganz einfach :)

Einfach auf den Schalter Erzeuge die PDF klicken, und schon erhält man den PDF-Text im Textfeld PDF-Ergebnis. Den Text kopiert man in einen Texteditor (z. B. WordPad oder Editor) und speichert das Dokument als ganz normale Textdatei ab. Der Dateiname sollte natürlich mit .pdf enden, dann muss man nur doppelklicken und bekommt die Datei in Acrobat angezeigt.

Kreator ändern/andere Programmiersprachen

Der Kreator sollte relativ leicht in andere Programmiersprachen umsetzbar sein. Dazu muss man eigentlich nur diese HTML-Seite auf der eigenen Festplatte speichern (unbedingt den Menübefehl: Datei > Speichern unter ... nutzen, sonst wird der JavaScript-Code nicht mitgespeichert). Dann sollte man sich etwas Überblick über die Funktionsweise des Kreators verschaffen (das meiste wird mit Strings gemacht). Wenn man dann noch etwas Ahnung von Pdf hat, sollte man schon was drehen können.

Hier ein Beispiel für C++: PDF-Kreator-C++.zip (28 kByte).

Und ganz wichtig: Nicht die Nerven verlieren, wenn Acrobat wegen ominöser Fehler rummosert. Meist sind es Kleinigkeiten, die mit verständlicheren Fehlermeldungen schnell gefunden wären. Oft hilft es, die Fehlerursache durch Reduzierungen einzugrenzen.

Die Interna

Die PDF-Daten werden in der Funktion MakePDF () erzeugt (ziemlich am Ende der HTML-Datei). Für eigene PDF-Dateien muss die Funktion natürlich angepasst werden. Man nutzt dabei die JavaScript-Klassen PdfDoc und PdfGraphic.

Die Klasse PdfDoc verwaltet die Pdf-Bestandteile. Die Klasse PdfGraphic kümmert sich um Sachen wie Farben, Schriften, Lesezeichen (Bookmarks), Kommentare und Verknüpfungen.

Das komplette Programm für eine "Hallo Welt"-PDF-Seite sieht so aus:

function MakePDF ()
{
 //--- Die Pdf-Verwaltung erzeugen
 var Pdf = new PdfDoc ();
 Pdf.init ();

 //--- Die Grafikeinheit an die Pdf-Verwaltung koppeln
 var g = new PdfGraphic (Pdf);
 g.InitPage (0);             // die erste Seite öffnen

 g.SetFont ("/TimesNewRoman");
 g.SetFillColor ("0 0 .6");  // blauer Text
 g.TextOutBlock (100, 700, "Hallo Welt.");

 //--- Zum Erzeugen des Pdf-Textes, ruft man dann noch
 var string = Pdf.createPdf ();
}

und fertig.

Den String kann man dann weiterverarbeiten, wie man will. Zum Speichern der PDF-Daten ist man leider auf externe Hilfe angewiesen, weil es in JavaScript kein File-Objekt gibt. Im IE kann man JScript verwenden (siehe Quelltext). Wer ein PDF-Plugin installiert hat, kann den PDF-Text mit einem HTML-Embed anzeigen lassen, wenn der Browser die Inline-Anweisung (die PDF-Daten) standardkonform verarbeitet.

Will man weitere Seiten in der PDF-Datei haben, genügt ein g.InitPage (1); und man ist auf der zweiten Seite. (Ja, es muss wirklich 1 heißen, um auf die zweite Seite zu kommen.) Man sollte auch nicht vergessen, dass die Schriften für jede Seite neu mit g.SetFont (...); gesetzt werden müssen – eine PDF-Eigenheit.

Die Linien und Rechteckfunktionen sind nicht schwer zu verstehen. Beim Zusammensetzen des PDF-Textes muss man nur immer darauf achten, dass PDF, anders als PostScript, ein bisschen pingelig ist, was beim Aufruf bestimmter Kommandos gerade auf dem Parameter-Stack liegt. Kommen rätselhafte Acrobat-Fehlermeldungen wie z. B. Falsche Parameteranzahl für einen setcolor-Befehl, hat man nicht zu wenig oder zu viel Parameter codiert, sondern einen Befehle in der falschen Reihenfolge oder im falschen Kontext benutzt.

Die Klasse PdfGraphic trifft einige Vorkehrungen, um diese Probleme auszuräumen. Wenn man die Content-Streams aber selber bastelt, sollte man die Regeln für die Textblöcke, Pfadblöcke, Imageblöcke usw. im Hinterkopf behalten, um bei seltsamen Acrobat-Fehlermeldungen leichter auf die richtige Spur zu kommen. Am besten man liest mal die einschlägige Literatur von Adobe (Figure 8.1, Seite 212 der Version 1.2). Weiter unten stehen Links zu den Dokus.

Natürlich kann man mit dem Kreator auch Pixel-Grafiken auf den PDF-Seiten platzieren. Das geht mit der Funktion PaintBitmap (...). Es gibt auch eine Funktion, um schnell mal eine Schwarzweiß-Grafik als HexStream zu basteln (siehe Quelltext).

Ein besonderes Goodie ist die kleine Absatzumbruchhilfe. Mit ihr können linksbündige, rechtsbündige, zentrierte und blockformatierte Absätze erzeugt werden -- und das in JavaScript! Damit es nett aussieht, werden auch bedingte Trennstriche unterstützt (Asc 173). Die Funktion layoutAbsatz () nimmt als Argument ein Array von Zeichenbreiten. Dieses Array kann mit Hilfe des kleinen Windows-Programms Zeichenbreiten.exe, das in der JavaScript-PDF-Kreator-Box enthalten ist, erstellt werden. Im Sub-Projekt PDF-eBook-Kreator ist der Umgang mit verschiedenen Schriften, Schriftschnitten, Zeichengrößen, Absatzformatierungen, Seitennummerierung und das Zusammenspiel mit PDF demonstriert.

Eine weitere interessante Sache bei PDF sind die Lesezeichen (Outlines bzw. Bookmarks). Normalerweise grenzt es an Folter die Outline-Strukturen für PDF zu programmieren, beim Kreator genügt ein AddBookmark () mit ein paar Parametern für Titel, Einrückungsebene und Sprungziel oder Aktionsanweisung. Fertig codiert sieht das dann so aus, um auf Seite zwei zu kommen.

g.AddBookmark ("Titel", "Level:0; /Dest [{Page1} /Fit]")

Ist doch wirklich einfach. Ach ja ... es muss wirklich {Page1} heißen, um auf Seite zwei zu kommen. Und es sind geschweifte Klammern.

Ähnlich einfach ist die Verwendung von so genannten Annotations. Das sind z. B. die Kommentarfelder, die man auf und zu klappen kann, Verknüpfungen, die Sprünge oder andere Aktionen ausführen oder Klänge und Filme starten.

Ein Kommentar geht so:

g.AddAnnot ("/Text"
	, "/Rect [200 600 400 650] "
	+ "/Contents (Das ist ein Kommentar)");

Eine Verknüpfung zur ersten Seite geht so:

g.AddAnnot ("/Link"
	, "/Rect [200 500 405 518] "
	+ "/Border [16 16 1] "
	+ "/Dest [{Page0} /Fit]");

Sieht alles nicht wahnsinnig schwer aus, und wenn man mal durch die PDF-Spezifikation von Adobe durchgeblättert hat, versteht man was /Rect, /Border und /Dest zu bedeuten haben ;). Ach ja, wo wir gerade bei PDF-chinesisch sind, für Strings, die von Acrobat im PDFDocEncoding erwartet werden, gibt es die Funktion Win2PdfEncoding () im JavaScript-PDF-Kreator.

Sollte es ein oder zwei Petitessen geben, die noch unklar sind und die mehr mit dem PDF-Kreator als mit PDF zu tun haben. Kann man natürlich mailen: E-Mail an Thilo Brai.

Ach ja, ...

... ich habe irgendwann aufgehört neue Acrobat-Versionen zu installieren. Die neueren Programme leiden alle an Verfettung und dickem Blut. Der Kreator müsste aber eigentlich auch mit den 3D- und Dolby-Surround-Versionen von Acrobat funktionieren.

Doku-Links

PDF-Infos von Adobe mit der Adobe® Acrobat® 8.1 implementation of the PDF specification und andere evtl. nützliche Infos.

Die Version 1.2 der Spezifikation gibt's z. B. hier (gnädige 400 Seiten, manchmal ist weniger mehr ;).

Sonstiges

• Die Idee des Popup-PDF-Schalters und seine Realisierung als "Inline-Embed" ist von Frank Kirchhoff. Der Embed-Aufruf funktioniert leider nur, wenn der Browser die Inline-Anweisung standardgemäß an ein PDF-Plugin weiterleitet. Wer die Popup-Funktion mal testen will und wessen Browser nicht recht mitspielen mag, kann die Funktionsweise z. B. mit einer Knoppix-Live-CD und dem darin enthaltenen HTML-Browser Konqueror testen.

Bei der Gelegenheit − mir ist aufgefallen, dass im Konqueror der PDF-Kommentar auf Seite 2 des Beispiels nicht richtig funktioniert. Hat jemand ähnliche Beobachtungen bei anderen PDF-Viewern gemacht?

• Der Kreator funktioniert jetzt auch im Internet-Explorer ... und jetzt funktionieren auch die weichen Worttrennungen in der Absatz-Funktion.

• In der JavaScript-PDF-Kreator-Box ist die PDF-Datei, die mit dem Firefox erzeugt wurde, enthalten. Sie hilft vielleicht, eventuelle Fehler zu finden, wenn der eigene Browser andere Auffassungen hat, wie JavaScript zu funktionieren hat. (Wäre möglich, dass sowas passiert. Für Hinweise bin ich dankbar.)

• Verbesserungen 23.9.2009: EscapePsText () wegen '\' und Asc(160), lineLayout () wegen -()[]{} bei Blocksatz, InitPage () wegen self..., PdfDoc.init (dx, dy) wegen MediaBox und einige ander Kleinigkeiten.

E-Mail an Thilo Brai

<< Zum Kapitelverzeichnis | Der JavaScript-PDF-eBook-Kreator >>