iText – append du contenu au fichier PDF existant

Je veux faire ce qui suit avec iText:

(1) parsingr un fichier PDF existant

(2) y append des données, sur la seule page existante du document (comme un horodatage)

(3) écrire le document

Je n’arrive pas à comprendre comment faire avec iText. En pseudo-code, je le ferais:

Document document = reader.read(input); document.add(new Paragraph("my timestamp")); writer.write(document, output); 

Mais pour une raison quelconque, l’API d’iText est si compliquée que je ne peux pas la comprendre. Le PdfReader contient effectivement le modèle de document ou quelque chose (plutôt que de cracher un document), et vous avez besoin d’un PdfWriter pour en lire les pages … hein?

iText a plus d’une façon de le faire. La classe PdfStamper est une option. Mais je trouve que la méthode la plus simple consiste à créer un nouveau document PDF, puis à importer des pages individuelles du document existant dans le nouveau PDF.

 // Create output PDF Document document = new Document(PageSize.A4); PdfWriter writer = PdfWriter.getInstance(document, outputStream); document.open(); PdfContentByte cb = writer.getDirectContent(); // Load existing PDF PdfReader reader = new PdfReader(templateInputStream); PdfImportedPage page = writer.getImportedPage(reader, 1); // Copy first page of existing PDF into output PDF document.newPage(); cb.addTemplate(page, 0, 0); // Add your new data / text here // for example... document.add(new Paragraph("my timestamp")); document.close(); 

Cela va lire dans un PDF à partir de templateInputStream et l’écrire dans outputStream . Ceux-ci peuvent être des stream de fichiers ou des stream de mémoire ou tout ce qui convient à votre application.

Le code de Gutch est proche , mais ça ne fonctionnera que si:

  • Il n’y a pas d’annotations (liens, champs, etc.), pas de structure de document / contenu marqué, pas de signets, pas de script au niveau du document, etc., etc., etc.
  • La taille de la page se trouve être A.4 (probabilités décentes, mais cela ne fonctionnera pas sur tous les PDF que vous rencontrerez)
  • Cela ne vous dérange pas de perdre toutes les métadonnées du document d’origine (producteur, date de création, éventuellement auteur / titre / mots-clés), et peut-être l’ID du document. Vous ne pouvez pas copier la date de création et l’ID de document sauf si vous faites un piratage assez profond sur iText lui-même).

La méthode approuvée consiste à faire l’inverse. Ouvrez le document existant avec un PdfStamper et utilisez le fichier PdfContentByte renvoyé par getOverContent () pour écrire du texte (et tout ce dont vous pourriez avoir besoin) directement sur la page. Aucun deuxième document requirejs.

Et vous pouvez utiliser un ColumnText pour gérer la mise en page et ce pour vous … pas besoin de vous mettre aux pieds avec beginText (), setFontAndSize (), drawText (), drawText () …, endText ().

C’est le scénario le plus compliqué que je puisse imaginer: j’ai un fichier PDF créé avec Ilustrator et modifié avec Acrobat pour avoir AcroFields (AcroForm) que je vais remplir avec des données avec ce code Java, le résultat de ce fichier PDF avec le les données dans les champs sont modifiées en ajoutant un document.

En fait, dans ce cas, je génère dynamicment un arrière-plan qui est ajouté à un fichier PDF qui est également généré dynamicment avec un document contenant une quantité inconnue de données ou de pages.

J’utilise JBoss et ce code est dans un fichier JSP (devrait fonctionner dans n’importe quel serveur Web JSP).

Remarque: si vous utilisez IExplorer, vous devez soumettre un formulaire HTTP avec la méthode POST pour pouvoir télécharger le fichier. Sinon, vous verrez le code PDF à l’écran. Cela ne se produit pas dans Chrome ou Firefox.

 <%@ page import="java.io.*, com.lowagie.text.*, com.lowagie.text.pdf.*" %><% response.setContentType("application/download"); response.setHeader("Content-disposition","attachment;filename=listaPrecios.pdf" ); // -------- FIRST THE PDF WITH THE INFO ---------- String str = ""; // lots of words for(int i = 0; i < 800; i++) str += "Hello" + i + " "; // the document Document doc = new Document( PageSize.A4, 25, 25, 200, 70 ); ByteArrayOutputStream streamDoc = new ByteArrayOutputStream(); PdfWriter.getInstance( doc, streamDoc ); // lets start filling with info doc.open(); doc.add(new Paragraph(str)); doc.close(); // the beauty of this is the PDF will have all the pages it needs PdfReader frente = new PdfReader(streamDoc.toByteArray()); PdfStamper stamperDoc = new PdfStamper( frente, response.getOutputStream()); // -------- THE BACKGROUND PDF FILE ------- // in JBoss the file has to be in webinf/classes to be readed this way PdfReader fondo = new PdfReader("listaPrecios.pdf"); ByteArrayOutputStream streamFondo = new ByteArrayOutputStream(); PdfStamper stamperFondo = new PdfStamper( fondo, streamFondo); // the acroform AcroFields form = stamperFondo.getAcroFields(); // the fields form.setField("nombre","Avicultura"); form.setField("descripcion","Esto describe para que sirve la lista "); stamperFondo.setFormFlattening(true); stamperFondo.close(); // our background is ready PdfReader fondoEstampado = new PdfReader( streamFondo.toByteArray() ); // ---- ADDING THE BACKGROUND TO EACH DATA PAGE --------- PdfImportedPage pagina = stamperDoc.getImportedPage(fondoEstampado,1); int n = frente.getNumberOfPages(); PdfContentByte background; for (int i = 1; i <= n; i++) { background = stamperDoc.getUnderContent(i); background.addTemplate(pagina, 0, 0); } // after this everithing will be written in response.getOutputStream() stamperDoc.close(); %> 

Il existe une autre solution beaucoup plus simple et qui résout votre problème. Cela dépend de la quantité de texte que vous souhaitez append.

 // read the file PdfReader fondo = new PdfReader("listaPrecios.pdf"); PdfStamper stamper = new PdfStamper( fondo, response.getOutputStream()); PdfContentByte content = stamper.getOverContent(1); // add text ColumnText ct = new ColumnText( content ); // this are the coordinates where you want to add text // if the text does not fit inside it will be cropped ct.setSimpleColumn(50,500,500,50); ct.setText(new Phrase(str, titulo1)); ct.go(); 
 Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("E:/TextFieldForm.pdf")); document.open(); PdfPTable table = new PdfPTable(2); table.getDefaultCell().setPadding(5f); // Code 1 table.setHorizontalAlignment(Element.ALIGN_LEFT); PdfPCell cell; // Code 2, add name TextField table.addCell("Name"); TextField nameField = new TextField(writer, new Rectangle(0,0,200,10), "nameField"); nameField.setBackgroundColor(Color.WHITE); nameField.setBorderColor(Color.BLACK); nameField.setBorderWidth(1); nameField.setBorderStyle(PdfBorderDictionary.STYLE_SOLID); nameField.setText(""); nameField.setAlignment(Element.ALIGN_LEFT); nameField.setOptions(TextField.REQUIRED); cell = new PdfPCell(); cell.setMinimumHeight(10); cell.setCellEvent(new FieldCell(nameField.getTextField(), 200, writer)); table.addCell(cell); // force upper case javascript writer.addJavaScript( "var nameField = this.getField('nameField');" + "nameField.setAction('Keystroke'," + "'forceUpperCase()');" + "" + "function forceUpperCase(){" + "if(!event.willCommit)event.change = " + "event.change.toUpperCase();" + "}"); // Code 3, add empty row table.addCell(""); table.addCell(""); // Code 4, add age TextField table.addCell("Age"); TextField ageComb = new TextField(writer, new Rectangle(0, 0, 30, 10), "ageField"); ageComb.setBorderColor(Color.BLACK); ageComb.setBorderWidth(1); ageComb.setBorderStyle(PdfBorderDictionary.STYLE_SOLID); ageComb.setText("12"); ageComb.setAlignment(Element.ALIGN_RIGHT); ageComb.setMaxCharacterLength(2); ageComb.setOptions(TextField.COMB | TextField.DO_NOT_SCROLL); cell = new PdfPCell(); cell.setMinimumHeight(10); cell.setCellEvent(new FieldCell(ageComb.getTextField(), 30, writer)); table.addCell(cell); // validate age javascript writer.addJavaScript( "var ageField = this.getField('ageField');" + "ageField.setAction('Validate','checkAge()');" + "function checkAge(){" + "if(event.value < 12){" + "app.alert('Warning! Applicant\\'s age can not" + " be younger than 12.');" + "event.value = 12;" + "}}"); // add empty row table.addCell(""); table.addCell(""); // Code 5, add age TextField table.addCell("Comment"); TextField comment = new TextField(writer, new Rectangle(0, 0,200, 100), "commentField"); comment.setBorderColor(Color.BLACK); comment.setBorderWidth(1); comment.setBorderStyle(PdfBorderDictionary.STYLE_SOLID); comment.setText(""); comment.setOptions(TextField.MULTILINE | TextField.DO_NOT_SCROLL); cell = new PdfPCell(); cell.setMinimumHeight(100); cell.setCellEvent(new FieldCell(comment.getTextField(), 200, writer)); table.addCell(cell); // check comment characters length javascript writer.addJavaScript( "var commentField = " + "this.getField('commentField');" + "commentField" + ".setAction('Keystroke','checkLength()');" + "function checkLength(){" + "if(!event.willCommit && " + "event.value.length > 100){" + "app.alert('Warning! Comment can not " + "be more than 100 characters.');" + "event.change = '';" + "}}"); // add empty row table.addCell(""); table.addCell(""); // Code 6, add submit button PushbuttonField submitBtn = new PushbuttonField(writer, new Rectangle(0, 0, 35, 15),"submitPOST"); submitBtn.setBackgroundColor(Color.GRAY); submitBtn. setBorderStyle(PdfBorderDictionary.STYLE_BEVELED); submitBtn.setText("POST"); submitBtn.setOptions(PushbuttonField. VISIBLE_BUT_DOES_NOT_PRINT); PdfFormField submitField = submitBtn.getField(); submitField.setAction(PdfAction .createSubmitForm("",null, PdfAction.SUBMIT_HTML_FORMAT)); cell = new PdfPCell(); cell.setMinimumHeight(15); cell.setCellEvent(new FieldCell(submitField, 35, writer)); table.addCell(cell); // Code 7, add reset button PushbuttonField resetBtn = new PushbuttonField(writer, new Rectangle(0, 0, 35, 15), "reset"); resetBtn.setBackgroundColor(Color.GRAY); resetBtn.setBorderStyle( PdfBorderDictionary.STYLE_BEVELED); resetBtn.setText("RESET"); resetBtn .setOptions( PushbuttonField.VISIBLE_BUT_DOES_NOT_PRINT); PdfFormField resetField = resetBtn.getField(); resetField.setAction(PdfAction.createResetForm(null, 0)); cell = new PdfPCell(); cell.setMinimumHeight(15); cell.setCellEvent(new FieldCell(resetField, 35, writer)); table.addCell(cell); document.add(table); document.close(); } class FieldCell implements PdfPCellEvent{ PdfFormField formField; PdfWriter writer; int width; public FieldCell(PdfFormField formField, int width, PdfWriter writer){ this.formField = formField; this.width = width; this.writer = writer; } public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvas){ try{ // delete cell border PdfContentByte cb = canvas[PdfPTable .LINECANVAS]; cb.reset(); formField.setWidget( new Rectangle(rect.left(), rect.bottom(), rect.left()+width, rect.top()), PdfAnnotation .HIGHLIGHT_NONE); writer.addAnnotation(formField); }catch(Exception e){ System.out.println(e); } } }