Montag, 13. April 2015

PDF Inhalte zusammenführen mit Apache PDFBox (merge content)

In einem Kundenprojekt gab es folgende Ausgangssituation:

  • Erzeugung Druckversion Ausgangsrechnung mit Apache FOP
  • Papierdruck der Rechnungen auf Papier mit Kopfbogen, d.h. Firmenlogo und Footer sind bereits auf dem Papier und werden nicht gedruckt.

Mit der Einführung eines digitalen Dokumenten Managements geht die Ausgangsrechnung bei der Erstellung automatisch als PDF aus der Warenwirtschaft in das DMS und wird dort archiviert. Damit entfällt die Ablage einer Papierkopie.

Um zukünftig Ausgangsrechnungen als PDF digital versenden zu können, musste eine Möglichkeit geschaffen werden, die Rechnung als PDF mit hinterlegtem Kopfbogen abzurufen. Die Ablage im DMS soll dann ebenfalls mit Kopfbogen erfolgen.
Dazu wurde von der Werbeagentur ein PDF mit dem Kopfbogen zur Verfügung gestellt.

Im Projekt  wird bereits die Apache PDFBox Bibliothek verwendet, so dass dies erstmal die erste Wahl war.
Nach einigem Kopfzerbrechen habe ich eine einfache Lösung gefunden:

org.apache.pdfbox.util.Overlay

Diese Klasse stellt die entsprechende Funktionalität bereit und kann sogar noch einiges mehr.

Overlay overlay = new Overlay();

overlay.setDefaultOverlayPDF(PDDocument.load(
   new File("/home/peter/kopfbogen.pdf")));

// Quell PDF
overlay.setInputPDF(PDDocument.load(
   new File("/home/peter/quell_dokument.pdf")));

// Zielpfad
overlay.setOutputFile("/home/peter/Downloads/ziel_dokument.pdf");

// Overlay ausfuehren und Output erzeugen
overlay.overlay(new HashMap<Integer, String>());

Im Beispiel wird die Datei kopfbogen.pdf hinter jede Seite des Dokuments quell_dokument.pdf gelegt. Das Resultat wird in ziel_dokument.pdf gespeichert.

Damit wird genau die Anforderung erfüllt und das Ziel-PDF hat das selbe Erscheinungsbild wie die ausgedruckte Rechnung auf Briefpapier.


Die Klasse Overlay bietet noch weitere Möglichkeiten:

  • Unterschiedliche Overlays für gerade und ungerade Seiten (odd/even)
  • Spezielle Overlays für einzelne Seiten. Diese werden in der Map<Integer,String> an die Methode overlay() übergeben. Im Beiepiel wird einfach eine leere Map übergeben.


Für mein Projekt habe ich nun noch das Problem, dass ich das Ziel in einen Stream schreiben muss. Dies unterstützt Overlay erstmal nicht, da der Output nur als Pfad gesetzt werden kann. Im Zweifel muss ich dazu die komplette overlay() Methode überschreiben und entsprechend anpassen.

HINWEIS: Das Beispiel nutzt bereits die PDFBox 2.0. In der 1.8er gestaltet sich das API geringfügig anderes.

Keine Kommentare:

Kommentar veröffentlichen