Facebook
Twitter
Google+
Kommentare
22

PDFs erstellen

Heute gibt’s mal einen Beitrag direkt aus dem Krankenbett. Ist doch was neues, oder? Naja die Münchner Luft muss ja nicht für jeden was sein, deswegen hat sich mein Körper überlegt, dass er jetzt einfach mal nicht mehr will. Muss ich wohl akzeptieren. Nichtsdestotrotz musste ich die Tage ein PDF generieren und zwar mit PHP. Dass das nicht immer so leicht ist, hab ich gemerkt, als ich ’nen Aufruf bei facebook nach Hilfe getätigt hatte.

Lars Jankowsky war der erste, der mich auf die Idee brachte mal Zend_Pdf anzusehen, nachdem ich 5 andere Bibliotheken vorher durch hatte, war das natürlich ok. Mein Problem bei der ganzen Sache war, dass ich mir sicher war, dass das PDF unheimlich komplex werden muss. Ich hatte einen PSD-Screen, den ich nachbauen musste und der hatte es in sich. Tja dumm gelaufen, da war ich nämlich schon krank und mein Hirn hat nur noch mit 50% Energie gearbeitet. Das PDF war nämlich gar nicht komplex, es gab nur einen Sehr komplexen Hintergrund, den man mit einfachen Daten füllen musste.

Wie bin ich also vorgegangen? Erstmal Word geöffnet. Ein Dokument erstellt, dass genau so wie mein leeres PDF aussieht und als PDF gespeichert. Zend_Pdf hat nämlich die lebensrettende Funktionalität, dass man einfach auf existierenden PDFs zeichnen kann. Man öffnet also die Datei und fängt dann an drauf rumzumalen. Ich will jetzt gar nicht wirklich auf alles drauf eingehen, dafür ist mein Kopf ein wenig zu brummend heute, aber trotzdem möchte ich ein kleines Beispiel zeigen, so dass ich sehr, wie einfach es doch geht.


$pdf = Zend_Pdf::load('master.pdf');
$page2 = $pdf->pages[1];
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
$page2->setFillColor(Zend_Pdf_Color_Html::color('#FFFFFF'));
$page2->setFont($font, 9);
$page2->drawText('Hallo dies ist ein Text', 145, 620);
$image = Zend_Pdf_Image::imageWithPath('images/section_1.png');
$page2->drawImage($image, 100, 100, 400, 200);
$pdf2->pages[1] = $page2;
$pdf2->save('test.pdf');

Schon fertig. Natürlich können das bestimmt 1000 Bibliotheken auch, aber ich fand die Syntax ganz nett und dass man existierende PDFs laden kann, war mein Heilsbringer.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

22 Comments

  1. Moin Moin,

    erstmal gute Besserung. Ich stand vor ein paar Tagen auch vor dem Problem ein ziemlich aufwendiges PDF mit PHP erstellen zu müssen. Bisher wurde mit FPDF gearbeitet. Der Code dafür war ziemlich umfangreich.
    Die Idee war einfach anhand der vorhandenen Template Engine aus HTML Dateien PDF Dokumente zu generieren. Hierzu verwende ich momentan die DOMPDF Bibliothek. Funktioniert ziemlich gut. Okay, der Code der Bibliothek ist ziemlich komisch. Aber es funktioniert …

    Reply
  2. Guten Morgen (und gute Besserung)!
    Für einen ähnlich komplexen Fall (Dokument mit schön gezeichneten Charts) musste ich gegen Ende letzten Jahres etwas ähnliches zaubern. Das Problem war, dass ich Daten aus einer TYPO3-Extension aufnehmen und letztlich ausgeben musste. Dummerweise hatte sich der ursprüngliche Macher der Erweiterung nicht allzu viele Gedanken um eine nette Architektur und Weiterverwendung von Code und Templates gemacht. So musste ich mir ein Klassenkonstrukt ausdenken, das sich einigermaßen locker an das bestehende andockt.
    PDFs generiere ich (eigentlich sehr gern!) mit fPDF, Charts lasse ich bei Google (Chart API) generieren. Leider sind die Charts nicht in einer für den Druck optimierten Auflösung (72dpi), aber dennoch nett per eigener Wrapper-Klasse per HTTP zu „generieren“. Denke, ein gangbarer (und wiederverwendbarer) Weg.
    Wer TYPO3 als „Framework“ nutzt, der hat im Falle einer „PDF-Druckfunktion“ eine sehr flexible API im Hintergrund, mit der sich die Inhalte in jedes beliebige Format pressen lassen. Sicherlich nicht ohne Aufwand, aber dafür sind solche Geschichten mit etwas Sorgfalt und durchdachter Architektur nachhaltig einzusetzen. Hätte da der damalige Entwickler mal besser aufgepasst und die Doku gelesen (RTFM 🙂 )…

    Reply
  3. LaTeX nutze ich seit dem Studium, und seither für so ziemlich alles in Schriftform. Bin Word-Legastheniker 🙂
    Mein „Diplom-Vater“ nutzt PHP und LaTeX um Rechnungen zu generieren. Sehr geniale Lösung, wenn man sich einmal eine LaTeX-Vorlage gebaut hat. Bis man an den Punkt angelangt, ist´s aber leider ein sehr weiter und steiniger Weg. Kann davon ein Lied singen: meine Diplomarbeit hat mich allein für die Vorlage knapp zwei Wochen über LaTeX brüten lassen…
    TYPO3 könnte man schön mit LaTeX PDFs rendern lassen: einfach TeX als Template nutzen, kurz den Parser via „exec( „pdflatex …“ );“ anwerfen, und man erhält ein wunderschönes PDF. Um ein paar temporäre Dateien kommt man dabei wohl nicht rum… aber alles Hirngespinste 😉

    Reply
  4. Kann Zend_PDF eigentlich inzwischen sowas wie automatischen Textumbruch innerhalb von bounding boxes? Ich habe zuletzt vor rund 2 Jahren auf Zend_PDF geguckt und war gelinde gesagt entsetzt, wie sehr die Bibliothek von den Features her den anderen Libs hinterherhinkte. Ich hab’s jetzt nicht so verfolgt, hatte aber subjektiv nicht den Eindruck, daß sich da viel getan hätte. Ok, zwischendurch hab ich mal den einen oder anderen Hack gesehen, der solche Funktionalität rudimentär reingepatched hat… aber will ich bei jedem neuen Release die Library patchen und hoffen, daß der Patch noch geht?

    Hatte mich dann für TCPDF entschieden, weil das auch einen eingebauten HTML-Parser hat, mit dem man bequem Vorlagen bauen kann. Wird bei einem Kunden von mir jetzt für die Erzeugung wirklich großer Pressespiegel eingesetzt. Den TCPDF-Code darf man sich echt nicht angucken, das ist echt grausam und erzeugt Augenkrebs. Aber es funktioniert, hat alle Features, die man je wollen würde, ist schnell, relativ ressourcenschonend und Bugs werden schnell behoben. Da sehe ich über die fehlende Architektur gerne hinweg 🙂

    Reply
  5. Ich bin bis jetzt immer noch nicht von FPDF „losgekommen“. Sei es nun aus Faulheith, etwas neues zu verwenden oder nicht ;-).
    Eigentlich stört mich an FPDF nur, dass es nicht mit utf-8 klarkommt (immer diese utf8_decode’s…).

    Ist eigentlich beispielsweise TCPDF wirklich so viel besser als FPDF?
    Lohnt sich der „Umstieg“ auf TCPDF, oder eine noch andere Klasse?
    Mit Zend ansich werde ich nicht so recht warm, diese ganze „Maschinerie“ drum herum lohnt sich bisher für meine meist kleineren Projekte nicht.

    Reply
  6. @Thomas: Ich weiß nicht, ob TCPDF unter’m Strich „besser“ ist als FPDF – letzteres kam für mich eben wegen der mangelnden UTF-8 Unterstützung nie in Frage. TCPDF kann das von Haus aus.

    Reply
  7. @Thomas: Du musst nicht die komplette Zend Library verwenden.

    Ich habe mein derzeitiges Projekt komplett in Zend Framework umgesetzt, außer für Excel und PDF Export.

    Für PDF Exporte ist TCPDF derzeit noch Zend_Pdf vorzuziehen.

    Reply
  8. Schaut gut aus, die Zend Lib.

    Wir verwenden bislang hauptsächlich wkhtmltopdf [1], was die Webkit Engine nutzt, um aus HTML ein PDF zu generieren. Vorteil: Sämtliche CSS Angaben werden von der Engine gut umgesetzt. Hier gab es bei anderen Libs immer mal Probleme.

    Da TYPO3 schon erwähnt wurde in anderen Kommentaren sei noch hinzugefügt, dass es auch eine TYPO3 Extension [2] gibt, die wkhtmltopdf nutzt.

    [1] http://code.google.com/p/wkhtmltopdf/
    [2] http://typo3.org/documentation/document-library/extension-manuals/webkitpdf/1.1.5/view/1/1/

    Gruß,
    Jochen

    Reply
  9. Hi,

    ich hatte vor ein paar Monaten auch mal im PHP Umfeld nach einer ordentlichen PDF Lösung gesucht. Leider hatte mich nichts so wirklich zufrieden gestellt. Deshalb habe ich mir für solche fälle einen Client/Server Anwendung in Java geschrieben welche die folgenden Komponenten nutzt.

    http://jodreports.sourceforge.net/
    http://www.artofsolving.com/opensource/jodconverter
    http://www.openoffice.org/
    http://www.freemarker.org/

    Das ganze funktioniert so:

    Mann erstellt im Prinzip ein OO-Dokument als Template. In diesem Template kann man dann den Syntax der FreeMarker Template Engine nutzen. Die Daten kommen aus einer XML-Datei welche dann in das Template gerendert werden. Zum Schluss wird aus dem OO-Dokument mit OpenOffice einfach ein PDF generiert.

    Von PHP kann ich einfach per exec den Client aufrufen. Der sendet das Template und die XML Datei an den Server. Der Server erstellt die PDF Datei und sendet sie zurück an den Client. Der Client speichert diese Datei dann im Dateisystem. Jetzt kann der PHP Prozess ganz einfach die gespeicherte Datei weiterverarbeiten.

    Reply
  10. Blöde Frage: wie läuft mittlerweile die Positionierung bzw. wo ist der „0-Punkt“ der Koordinaten? Ich habe irgendwann mal auf Zend_PDF zurückgreifen wollen, da war der 0-Punkt offenbar unten links, statt wie allgemein üblich oben links. Da sollte die ganze Bibliothek aber soon™ umgebaut werden. Hab’s dann wieder mit FPDF gemacht und seither noch keinen Bedarf wieder gehabt.

    Reply
  11. Sehe das genauso wie Markus Wolff. Zend_Pdf ist ziemlich low-level. Also weit entfernt vom üblichen Cell() wie man es aus FPDF und TCPDF kennt. Zend_Pdf ist da für mich einfach nicht brauchbar. FPDF kann kein utf-8 und TCPDF wird regelmäßig (ständig) aktualisiert. Den Code sollte man sie aber wahrlich nicht reinziehen. TCPDF ist durch die Erfahrung der Macher und die Fixes mittlerweile ziemlich robust. Ich habe hierfür einen kleinen Wrapper, der das Handling mit TCPDF etwas an den Stil des ZF angleicht. PDFs werden dabei in etwa erstellt wie ein Formular mit Zend_Form.

    Reply
  12. Ich habe kürzlich vorgefertigte PDF-Formulare über PHP mit Daten befüllt, die der User über ein Web-Formular eingibt. Im PDF gab es also Text-Felder für Name, Adresse usw. und viele viele Ankreuzfelder. Dafür habe ich FPDF genutzt, das Kreuzchen in den Ankreuzfeldern habe ich mit folgenden Code erzeugt:
    $fpdf->Text($xCoordinate, $yCoordinate, ‚X‘);
    Ich musste also für jedes Ankreuzfeld die X- und Y-Coordinaten auf 1/10 eines Bildpunktes (?) genau treffen. Wartbarkeit = 0; wenn ein neues Feld hinzukommen wird hat man sehr viel Arbeit.
    Aber gibt es eine bessere Lösung? Etwa, dass die Felder im PDF eindeutig benannt sind und ich dem PDF nur den Feldname und den Wert mitteilen muss und das PDF dann das Feld selbstständig belegt.

    Reply
  13. Also Leute: wer schonmal Rechnungs-PDFs für Firmen gemaht hat, der wird nie natives Zend-PDF oder FPDF verwenden. Ich hab das damals gemacht und alleine dynamisch dimensionierte Tabellen per Hand zu coden ist der reinste Albtraum. Mich hat das auch sehr gewundert dass man im (recht neuen) Zend Framework wieder alles von hand coden muss *graus*

    Seit dieser Zeit: TCPDF. Da schmeiß ich einfach HTML+CSS rein (Tabellen, Formulare, egal) udn das Ding macht mir schöne PDFs draus. Ohne mich um Spezifikas kümmern zu müssen (man kann aber wenn man will).
    Totale Fire&Forget-Lösung, die von der Einfachheit alles schlägt was ich bisher gesehen habe.

    Reply
  14. Ich schließe mich Stahlhammer an.

    Zend_Pdf hat einfach keine gute Funktionalität um Texte einzubringen.

    Mein klarer Tipp: TCPDF mit HTML to PDF!
    Aus meiner Sicht das absolut mögliche Maximum.

    Reply
  15. Fuer dynamische PDF’s die z.B. keine feste Zeilenanzahl haben oder wenn die letzte Seite immer eine bestimmte Fusszeile haben muss, haben wir immer FOP benutzt. Ist an sich kein PHP Tool. Es generiert aus XML-Daten und einen XSLT-Template ein PDF. FOP wird per Kommandozeile mit den Parametern gefuettert und spuckt das PDF aus. Wenn man das ein damit gemacht hat, moechte man nie wieder per PHP in ein bestehendes PDF schreiben wollen.

    Reply
  16. @Duffman: Naja. Also allein schon die Tatsache, daß man erstmal XML-Dokumente generieren und in’s Dateisystem ablegen muss, verumständlicht u.U. die Sache schon ein wenig. Und XSLT – insbesondere XSL:FO – ist auch eher was für Masochisten, aber das ist sicher Geschmacksfrage.

    Bei meinem Kunden, der mit besagten großen Pressespiegeln, wurde anfangs auch mit FOP experimentiert – das Experiment scheiterte an allen Eckpunkten: Ressourcenverbrauch, Geschwindigkeit und Stabilität. Letztlich mußte sogar der Sourcecode noch gepatched werden, damit das Ding nicht bei bestimmten JPEG-Typen immer abstürzte. Fazit: Die Lösung kam über die Testphase nicht hinaus und ist nie in Produktion gegangen.

    TCPDF ist da deutlich besser – und wenn man mal so richtig finster drauf ist, kann man sich ja einen XSL-Layer oben drüber bauen – ich tue das aber ganz bestimmt nicht 😉

    Disclaimer: Das besagte FOP-Experiment liegt gut 5 Jahre zurück – sicher hat sich auch an der Front was getan.

    Reply
  17. @Markus

    Die XSLTs haben wir auch nicht selbst geschrieben. Da muss ich Dir zustimmen dass das an Koerperverletzung grenzt. Stylevision kam bei uns zum Einsatz.

    Reply
  18. Hallo zusammen. Mit PDF Dateien erzeugen habe ich mich letztes Jahr mehrere Monate beschäftigt. Fazit: wenn nur einseitige und einfache PDF Dateien erzeugt werden sollen und man unbedingt Zend_Pdf verwenden muss, dann reicht das aus. Sollen aber die PDF Dateien mehrseitig sein, dann entpuppt sich das Ganze als eine „Raketen-Technik“. Ja, ich habe es geschafft einen PdfGenerator zu bauen der je nach der Größe des Inhaltes, es selber schafft den Inhalt auf mehrere Seiten gleichmäßig zu verteilen. Soweit so gut. Nun wollte der Kunde dass die PDFs barierefrei sind, mit einen Inhaltsverzeichnis und mit Tags für die TAB-Steuerung. So, hier hören die Möglichkeiten von Zend_Pdf schon auf. Bei diesem Punkt haben wir uns dann letztendlich für PdfLib entschieden. Mehr könnt ihr hier nachlesen: http://krsteski.de/php-tricks-und-tipps/pdf-datei-erzeugen.html

    Reply
  19. FPDF hat gegenüber TCPDF den Nachteil, dass es nicht mit utf8 klarkommt – dafür abern den unschlagbaren Vorteil, kleinere PDFs zu generieren.

    Was die Tabellen-Problematik in FPDF angeht – dafür gibt es nette Klassen, die von FPDF erben und damit keine Probleme haben.

    HTML->PDF ist eine absolute Krücke, weil HTML mit PDF nichts gemeinsam hat!

    Reply
  20. @Markus

    Du kannst den Apache FOP und das XML-Gefrickel umgehen. Der Webservice „http://www.pdfnow.com“ generiert PDFs zuverlässig, ohne, dass man irgendwas auf seinen Server installieren muss. Eine Programmzeile reicht aus.

    Die Templates sind in XML, jedoch können einfach Beispieltemplates angepasst werden. Damit hat man die volle Leistung, muss das Rad aber nicht neu erfinden.

    Reply

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen