2010-07-26 4 views
43

Я хочу сделать следующее с IText:IText - добавить содержимое в существующий PDF файл

(1) разобрать существующий файл PDF

(2) добавить в него данные, на имеющемся одной странице документа (например, метки времени)

(3) выписывают документ

Я просто не могу понять, как сделать это с IText. В псевдокоде я хотел бы сделать это:

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

Но по какой-то причине API IText настолько угрожающе осложняется тем, что я не могу обернуть мою голову вокруг него. PdfReader фактически держит модель документа или что-то (а не выплескивает документ), и вам нужен PdfWriter для чтения страниц из него ... а?

ответ

67

В iText есть несколько способов сделать это. Класс PdfStamper является одним из вариантов. Но я считаю, что самый простой способ - создать новый PDF-документ, а затем импортировать отдельные страницы из существующего документа в новый 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(); 

Это будет читать в PDF из templateInputStream и записать его в outputStream. Это могут быть потоки файлов или потоки памяти или все, что подходит вашему приложению.

+10

Спасибо за это. Если вы не хотите ограничивать его только A4, вы можете добавить document.setPageSize (reader.getPageSize (1)); – Dittimon

+0

Когда я использовал этот метод, PDF вышел наружу. Поэтому я пошел с ответом Марка Сторьера и использовал PdfStamper. –

+0

Это работает отлично, но страницы с acrofields не копируются с ними в cb.addTemplate (страница, 0,0). Acrofields недоступны в выпуске pdf – Vicky

40

код Gutch является близко, но он будет работать только правильно, если:

  • Там нет аннотации (ссылок, полей и т.д.), нет Структуры документа/Выраженного Содержимого, не закладок, нет документа -level скрипт и т. д. и т. д. и т. д.
  • Размер страницы - A.4 (приличные коэффициенты, но это не сработает ни на одном ол-файле, с которым вы случайно сталкиваетесь)
  • Не теряйте все оригинальные метаданные документа (продюсер, дата создания, возможно автор/название/ключевые слова) и, возможно, идентификатор документа. Вы не можете скопировать дату создания и doc ID, если вы не сделаете довольно глубокий хакер на самом iText).

Утвержденный метод заключается в том, чтобы сделать это наоборот. Откройте существующий документ с помощью PdfStamper и используйте возвращаемый PdfContentByte из getOverContent() для записи текста (и всего, что вам может понадобиться) непосредственно на страницу. Второй документ не требуется.

И вы можете использовать ColumnText для обработки макета и для вас ... нет необходимости спускаться и грязно с beginText(), setFontAndSize(), drawText(), drawText() ..., endText() ,

+0

Все отличные моменты ... это хороший способ определить, лучше ли метод 'PdfStamper' или' addTemplate' для вашего сценария. В моем случае «addTemplate» явно лучше из-за ваших очков: я получаю исходный шаблон графического дизайнера, который был сгенерирован в Adobe Illustrator, имеет множество нежелательных и метаданных и весит 1 МБ. Если бы я использовал 'PdfStamper', сгенерированные документы были бы 1MB + и имели бы имя графического дизайнера контракта в них; используя «addDocument», они имеют размер 50 КБ и не имеют встроенной личной информации. – gutch

+0

Ничего себе. Это ОГРОМНОЕ изменение размера. Метаданные не такие большие ... что занимает остальная часть пространства ?! –

+0

Я думаю, что у этих больших PDF-файлов был установлен флажок «Сохранять возможности Illustrator Illustrator», который сохраняет всю информацию Adobe Illustrator в файле, чтобы разрешить дальнейшее редактирование. Это похоже на создание PDF-документа из документа и включение в него исходного DOC-файла. – gutch

5

Это самый сложный сценарий, который я могу себе представить: у меня есть файл PDF, созданный с помощью Ilustrator и модифицированный Acrobat, чтобы иметь AcroFields (AcroForm), который я собираюсь заполнить данными с помощью этого Java-кода, в результате чего Файл PDF с данными в полях изменяется с добавлением документа.

Фактически в этом случае я динамически генерирую фон, который добавляется в PDF, который также динамически генерируется с Документом с неизвестным количеством данных или страниц.

Я использую JBoss, и этот код находится в JSP-файле (должен работать на любом веб-сервере JSP).

Примечание: если вы используете IExplorer, вы должны отправить HTTP-форму с методом POST, чтобы иметь возможность загрузить файл. Если нет, вы увидите код PDF на экране. Этого не происходит в Chrome или 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(); 
%> 

Существует еще одно решение намного проще и решает вашу проблему. Это зависит от количества текста, который вы хотите добавить.

// 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); 
     } 
    } 
} 
Смежные вопросы