2010-07-26 4 views
43

Je veux faire ce qui suit avec iText:iText - ajouter du contenu dans un fichier PDF existant

(1) Parse un fichier PDF existant

(2) ajouter des données à elle, sur la seule page existante du document (par exemple un horodatage)

(3) sur le document

Je ne arrive pas à comprendre comment faire cela avec iText. Dans le code pseudo que je ferais ceci:

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

Mais pour une raison quelconque de l'API iText est si décourageante compliqué que je ne peux pas envelopper la tête autour d'elle. Le PdfReader détient réellement le modèle de document ou quelque chose (plutôt que de cracher un document), et vous avez besoin d'un PdfWriter pour lire les pages de celui-ci ... hein?

Répondre

67

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 est de créer un nouveau document PDF puis d'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 lire dans un fichier PDF à partir templateInputStream et l'écrire à outputStream. Ceux-ci peuvent être des flux de fichiers ou des flux de mémoire ou tout ce qui convient à votre application.

+10

Merci pour cela. Si vous ne voulez pas le limiter uniquement à A4, vous pouvez ajouter document.setPageSize (reader.getPageSize (1)); – Dittimon

+0

Lorsque j'ai utilisé cette méthode, le PDF est sorti tout désaligné. Par conséquent, je suis allé avec la réponse de Mark Storer et utilisé PdfStamper. –

+0

Cela fonctionne correctement, mais les pages avec acrofields ne les copient pas dans cb.addTemplate (page, 0,0). Acrofields ne sont pas disponibles dans la sortie pdf – Vicky

40

Code de Gutch est près, mais ça ne fonctionnera bien si:

  • Il n'y a pas d'annotations (liens, champs, etc.), aucune structure de document/Contenu Marqué, aucun signet, aucun document -level script, etc, etc, etc ...
  • La taille de la page se trouve être A.4 (chances décent, mais il ne fonctionnera pas sur un ol 'PDF que vous rencontrez)
  • Il ne faut pas perdre toutes les métadonnées du document original (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 du document, sauf si vous faites un peu de hackery 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 PdfContentByte retourné par getOverContent() pour écrire le texte (et tout ce dont vous pourriez avoir besoin) directement sur la page. Aucun second document nécessaire.

Et vous pouvez utiliser un ColumnText pour gérer la mise en page et tel pour vous ... pas besoin de descendre et sale avec beginText(), setFontAndSize(), drawText(), drawText() ..., endText() .

+0

Tous les excellents points ... c'est un bon moyen de déterminer si la méthode 'PdfStamper' ou la méthode' addTemplate' est meilleure pour votre scénario. Dans mon cas, le 'addTemplate' est nettement meilleur à cause de vos points: je reçois un template source d'un graphiste qui a été généré dans Adobe Illustrator, qui contient beaucoup d'ordures et de métadonnées et qui pèse 1Mo. Si j'utilisais 'PdfStamper', les documents générés seraient de 1 Mo + et porteraient le nom d'un graphiste contractuel; en utilisant 'addDocument', les documents sont de 50 Ko et aucune information personnelle n'est incorporée. – gutch

+0

Wow. C'est un énorme changement de taille. Les métadonnées ne sont pas si grandes ... qu'est-ce qui prend le reste de l'espace ?! –

+0

Je pense que la case "Préserver les capacités d'édition d'Illustrator" a été cochée dans ces gros fichiers PDF, ce qui enregistre toutes les informations d'Adobe Illustrator dans le fichier pour permettre d'autres modifications. C'est un peu comme créer un PDF à partir d'un document et y incorporer le fichier DOC source. – gutch

5

Ceci est le scénario le plus compliqué que je peux 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 Fichier PDF avec les données dans les champs est modifié en ajoutant un document.

En fait, dans ce cas, je génère dynamiquement un arrière-plan qui est ajouté à un PDF qui est également généré dynamiquement avec un document avec 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 allez voir le code PDF sur l'écran. Cela n'arrive 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 résout votre problème. Cela dépend de la quantité de texte que vous voulez ajouter.

// 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(); 
3
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); 
     } 
    } 
} 
Questions connexes