2010-07-26 51 views
43

existente Quiero hacer lo siguiente con iText:iText - agregar contenido a archivo PDF

(1) analizar un archivo PDF existente

(2) añadir algunos datos en ella, en la página única existente del documento (por ejemplo, una marca de tiempo)

(3) escribir el documento

yo sólo parece que no puede encontrar la manera de hacer esto con iText. En pseudocódigo Me gustaría hacer esto:

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

Pero por alguna razón API de iText es complicado por lo auténtico desafío que no puedo envolver mi cabeza alrededor de ella. El PdfReader realmente contiene el modelo de documento o algo así (en lugar de escupir un documento), y usted necesita un PdfWriter para leer páginas de él ... ¿eh?

Respuesta

67

iText tiene más de una forma de hacerlo. La clase PdfStamper es una opción. Pero creo que el método más fácil es crear un nuevo documento PDF y luego importar páginas individuales desde el documento existente al nuevo 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(); 

Esto permitirá la lectura de un documento PDF con templateInputStream y escribirlo a outputStream. Estos pueden ser flujos de archivos o secuencias de memoria o lo que sea adecuado para su aplicación.

+10

Gracias a este. Si no desea restringirlo solo a A4, puede agregar document.setPageSize (reader.getPageSize (1)); – Dittimon

+0

Cuando usé este método, el PDF salió desalineado. Por lo tanto, fui con la respuesta de Mark Storer y utilicé PdfStamper. –

+0

Esto funciona bien, pero las páginas con acrofields no copian con ellas en cb.addTemplate (página, 0,0). Acrofields no está disponible en la salida pdf – Vicky

40

código de Gutch es cerca, pero sólo funcionará bien si:

  • No hay anotaciones (enlaces, campos, etc.), sin la estructura del documento/contenido marcado, no hay marcadores, ningún documento - nivel de secuencia de comandos, etc, etc, etc ...
  • El tamaño de la página pasa a ser A.4 (probabilidades decentes, pero no funcionará en ningún PDF antiguo que encuentre)
  • Usted don No importa perder todos los metadatos del documento original (productor, fecha de creación, posiblemente autor/título/palabras clave), y tal vez la identificación del documento. Usted no puede copiar la fecha de creación y el ID de documento a menos que haga un poco de hackery bastante profunda en iText sí ​​mismo).

El método aprobado es hacerlo al revés. Abra el documento existente con un PdfStamper, y use el PdfContentByte devuelto de getOverContent() para escribir texto (y cualquier otra cosa que pueda necesitar) directamente en la página. No se necesita un segundo documento.

Y puede usar un Texto de columna para manejar el diseño y cosas así ... no necesita ensuciarse con beginText(), setFontAndSize(), drawText(), drawText() ..., endText() .

+0

Todos los puntos excelentes ... esa es una buena forma de determinar si el método 'PdfStamper' o' addTemplate' es mejor para su escenario. En mi caso, 'addTemplate' es claramente mejor debido a tus puntos: obtengo una plantilla de fuente de un diseñador gráfico que se generó en Adobe Illustrator, tiene un montón de basura y metadatos y pesa 1 MB. Si utilizo 'PdfStamper', los documentos generados serían de 1MB + y tienen el nombre de un diseñador gráfico de contrato; al usar 'addDocument', los documentos son de 50kB y no tienen información personal incrustada. – gutch

+0

Wow. Eso es un gran cambio de tamaño. Los metadatos no son tan grandes ... ¿qué está ocupando el resto del espacio? –

+0

Creo que esos archivos PDF grandes habrían tenido marcada la casilla 'Conservar capacidades de edición de Illustrator', que guarda toda la información de Adobe Illustrator en el archivo para permitir su posterior edición. Es un poco como crear un PDF a partir de un documento e incrustar el archivo DOC de origen en él. – gutch

5

Este es el escenario más complicado que puedo imaginar: tengo un archivo PDF creado con Ilustrator y modificado con Acrobat para tener AcroFields (AcroForm) que voy a completar con datos con este código Java, el resultado de eso El archivo PDF con los datos en los campos se modifica agregando un Documento.

De hecho, en este caso estoy generando dinámicamente un fondo que se agrega a un PDF que también se genera dinámicamente con un documento con una cantidad desconocida de datos o páginas.

estoy usando JBoss y este código se encuentra dentro de un archivo JSP (debería funcionar en cualquier servidor web JSP).

Nota: si utiliza IExplorer debe enviar un formulario HTTP con método POST para poder descargar el archivo. Si no, verá el código PDF en la pantalla. Esto no ocurre en Chrome o 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(); 
%> 

Hay otra solución mucho más simple, y resuelve su problema. Depende de la cantidad de texto que desee agregar.

// 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); 
     } 
    } 
} 
Cuestiones relacionadas