# PDF Formulare zusammenführen mit iText



## CMartien (4. August 2011)

Hallo zusammen,

ich versuche nun schon einen ganzen Moment etliche PDF Formulare zusammen zu führen die eine ganze Menge an Feldern enthalten. Diese Felder sollen teilweise dynamisch durch Angabe von Informationen aus einem Webformular befüllt werden. Das stell mich vorerst nicht vor ein wirkliches Problem so lange ich setFormFlattening(false) bzw nicht auf true setze.
Ich möchte jedoch die Formularfelder nach der Erzeugung der PDF Datei noch editieren können.

Mein erster Ansatz war:

alle benötigten PDF Formulare zusammenführen und danach stampen.  Dies hatte jedoch zur Folge dass ich nicht mehr auf alle Felder zugreifen konnte da Felder in verschiedenen dokumenten die gleiche Feldbezeichnung haben, was auch so gewollt ist. Nach dem Merge gehen die Feldbezeichnungen verlorenund ich kann nicht mehr alle Felder stampen
jedes PDF Formular erst stampen dann an ein gemeinsames Ergebnispdf anhängen. Die Folge von dieser Variante war, dass die Dokumente zusammengeführt wurden jedoch der Inhalt der Formularfelder wurde nicht mit kopiert.

Ich verwende für die PDF Bearbeitung iText und bin da noch relativ frisch dabei. 

Stampen einer PDF Datei sieht bei mir wie folgt aus:

```
private ByteArrayOutputStream stamp(PdfReader reader, Map paramMap) throws IOException, DocumentException{
		ByteArrayOutputStream pdf = new ByteArrayOutputStream();
		PdfStamper pdfStamper = new PdfStamper(reader, pdf);
		
		AcroFields fields = pdfStamper.getAcroFields();
		Map fieldMap = fields.getFields();
		Iterator it = fieldMap.keySet().iterator();
		
		while (it.hasNext()) {
			String key = (String)it.next();
			
			if (paramMap.containsKey(key)){
				fields.setField(key, paramMap.get(key).toString());
			}
		}
		
		//FormFlattening ausgeschaltet lassen 
        //pdfStamper.setFormFlattening(true);
        pdfStamper.close();
        
        return pdf;
	}
```

Merge von zwei PDF Dateien führe ich wie folgt aus:

```
private void merge(ByteArrayOutputStream pdfOut, PdfReader pdfToMerge) throws IOException, DocumentException{
		PdfReader existingPdf = null;
		
		if (pdfOut != null && pdfOut.size() > 0) { 
			//throws IOException
			existingPdf = new PdfReader(pdfOut.toByteArray());
		}
		
		Document document = null;
		PdfSmartCopy copy = null;
		
		// Erzeugung eins Documents als Basis fuer die Zusammenfuehrung der PDF Dokumente
		if (existingPdf != null) {
			document = new Document(existingPdf.getPageSizeWithRotation(1));
		} else {
			document = new Document(pdfToMerge.getPageSizeWithRotation(1));
		}
		
		//writer erzeugen um in das document zu schreiben
		copy = new PdfSmartCopy(document, pdfOut); // throws DocumentException
		copy.setPdfVersion(PdfWriter.VERSION_1_2);		
		
		document.open();
		
		//existierendes PDF einlesen wenn es nicht leer ist
		if (existingPdf != null) {
			for (int i = 0; i < existingPdf.getNumberOfPages();) {
				// throws DocumentException
				copy.addPage(copy.getImportedPage(existingPdf, ++i));
			}
		}
				
		int pageCountPortrait = pdfToMerge.getNumberOfPages();

		//zusammenfuehren der beiden PDF Dokumente
		for (int i = 0; i < pageCountPortrait;) {
			// throws DocumentException
			copy.addPage(copy.getImportedPage(pdfToMerge, ++i));
		}
		document.close();
	}
```

Ich hoffe es kann mir jemand helfen, sinnvoll PDF Formulare zu mergen und teilweise zu befüllen ohne das man FormFlattening auf true setzen muss.

Danke schonmal vorab!

Viele Grüße,
Christian


----------



## CMartien (30. August 2011)

Leider scheint niemand eine Lösung für mein Problem zu kennen. 

Ich habe mich daher nun für eine zwar unsauber aber eine für mich sinnvolle Lösung entschieden.

Im ersten Schritt werden nun meine PDF Formulare beschrieben und gleichzeitig werden direkt nach dem beschreiben die Felder Umbenannt. Nach dem beschreiben füge ich die Formulare zusammen.

Normal werden die Felder nach dem beschreiben entfernt (pdfStamper.setFormFlattening(true)) jedoch sollen die Felder auch nach dem erstellen der PDF Datei noch beschreibbar bleiben. Daher setze ich das pdfStamper.setFormFlattening(false) wodurch die Felder bestehen bleiben.



```
private ByteArrayOutputStream stamp(PdfReader reader, Map valueMap, String suffix) throws IOException, DocumentException{
		ByteArrayOutputStream pdf = new ByteArrayOutputStream();
		PdfStamper pdfStamper = new PdfStamper(reader, pdf);
		
		AcroFields fields = pdfStamper.getAcroFields();
		
		Set<String> keys = new HashSet<String>(fields.getFields().keySet());
        for (String key : keys) {
			if (valueMap.containsKey(key)) {
				fields.setField(key, valueMap.get(key).toString());
			}
			fields.renameField(key, String.format("%s_%s", key, suffix));
		}
		
        pdfStamper.setFormFlattening(false);
		pdfStamper.close();
        
        return pdf;
	}
```

Dies hat zur Folge, dass beim Mergen kein Konflikt mehr entstehen kann sobald zwei Feldnamen aus zwei Formularen den gleichen Namen haben. Die Umbenennung der Feldnamen bewirkt jedoch dass im endgültigen Dokument nicht mehr alle Felder mit dem vorher gleichen Namen zusammen geändert werden wenn nachträglich nochmal der Inhalt angepasst wird da ein Feldname person.name der in mehreren Formularen vorkommt nach dem Stampen nun das Format person.name_<suffix> trägt.

Beispiel:


Formular_1:
Feld 1 - person.name
Feld 2 - person.vorname
suffix für Formular 1 z.B. F1​
Formular_2:
Feld 1 - person.name
Feld 2 - person.vorname
suffix für Formular 2 z.B. F2​
Diese beiden Felder haben nach dem Stampen nun die Namen:

Ergebnis PDF:
Feld 1 - person.name_F1
Feld 2 - person.vorname_F1
Feld 3 - person.name_F2
Feld 4 - person.vorname_F2​
Ändert man nun im Ergebnis PDF den Namen im Feld 1 muss man diesen auch in Feld 4 nochmal anpassen da diese beiden Felder mit dem gleichen Inhalt keinen Bezug mehr zu einander haben. 

Da ich in meinen Formularen viele solcher Felder habe die jedoch in vielen verschiedenen Formularen enthalten enthalten sind besteht ein relativ großer Aufwand wenn nach der Erzeugung des Ergebnis Formulars noch anpassungen stattfinden da diese Felder keinen Bezug mehr zu einander haben.

Eventuell hat ja noch jemand eine bessere Lösung und möchte sie mir mitteilen. 

Viele Grüße,
Christian


----------



## SE (30. August 2011)

Was mich eher wundert ist die Tatsache das du ein PDF , was eigentlich ein read-only Datenformat ist nachträglich editieren willst.
Normalerweise erzeugt man dann aus den noch vorhandenen Rohdaten eine korrigierte Version und makiert die alte als ungültig.


----------



## CMartien (30. August 2011)

Hmmm... na dann will ich mal ein paar kleine Geheimnisse lüften. 

Formular (von denen ich in meiner Anfrage gesprochen habe)

Wikipedia definiert ein Formular wie folgt:
Ein Formular (siehe auch Vordruck) ist ein standardisiertes Mittel zur Erfassung, Ansicht und Aufbereitung von Daten. Formulare sind Vervielfältigungen, die durch Eintragungen zu ergänzen sind und der Bearbeitung häufig auftretender, gleichartiger Geschäftsfälle dienen und können entweder in Papier- oder elektronischer Form (z. B. Webformular) vorliegen. Formulare haben oft arbeitsvorbereitende Funktion.
http://de.wikipedia.org/wiki/Formular​
PDF Formularprozesse

Wikipedia sagt zu PDF:
...
Formularprozesse

PDF-Dokumente können für Formularprozesse neben Text und grafischen Elementen interaktive Formularelemente enthalten. Komplette Formulare lassen sich somit in einem PDF-Dokument bündeln; die im Dokument erfassten Daten können über verschiedene Wege zum Herausgeber des Formulars zurückgesendet werden.


Drucken und ausfüllen: Das per Hand ausgefüllte Formular kann auf herkömmlichen Wegen per Post oder Fax versendet werden.
    Ausfüllen und Drucken: Das elektronisch ausgefüllte Dokument kann ausgedruckt und auf herkömmlichen Wegen versendet werden.
    Ausfüllen und über eine HTTP-Verbindung senden: Das elektronisch ausgefüllte Formular kann elektronisch über den Webbrowser oder aus Adobe Acrobat heraus versendet werden.
    Ausfüllen und das elektronisch ausgefüllte Formular per E-Mail versenden.
...
http://de.wikipedia.org/wiki/PDF​
Nun, bezogen auf gerade die Definition der Formularprozesse, möchte ich Formulare zusammen fügen und diese befüllen. Die Befüllung der Formularfelder findet erst bei der Formularzusammenstellung statt jedoch soll es auch nach der Formularzusammenstellung noch möglich sein die Formularfelder zu bearbeiten. 

Es geht bei meiner Problemstellung also nicht darum die Texte des Formulars zu editieren sondern nur den Inhalt der Formularfelder!

Ich erstelle auch keine PDF Formulare neu, sondern ermittle anhand von Eingaben in einem Webformular eine Auswahl von PDF Formularvorlagen, beschreibe die Felder, füge diese zusammen und gebe das Ergebnisformular beschrieben aus. Es existieren daher auch keine Formularrohdaten aus denen man ein neues PDF Formular erzeugen kann!

Arbeiten mit Templates bzw Vorlagen ist was feines. 

Viele Grüße,
Christian


----------

