2010-07-26 50 views
43

hiện tại tôi muốn làm như sau với iText:iText - thêm nội dung vào tập tin PDF

(1) phân tích một tập tin PDF sẵn có

(2) thêm một số dữ liệu vào nó, trên trang duy nhất hiện có của tài liệu (chẳng hạn như một timestamp)

(3) viết ra các tài liệu

tôi chỉ dường như không thể tìm ra cách để làm điều này với iText. Trong mã giả tôi sẽ làm điều này:

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

Nhưng vì một lý do nào đó, API của iText phức tạp đến mức tôi không thể quấn quanh đầu. PdfReader thực sự giữ mô hình tài liệu hoặc một cái gì đó (thay vì khạc ra một tài liệu), và bạn cần một PdfWriter để đọc các trang từ nó ... eh?

Trả lời

67

iText có nhiều cách để thực hiện việc này. Lớp học PdfStamper là một lựa chọn. Nhưng tôi thấy phương pháp đơn giản nhất là tạo một tài liệu PDF mới, sau đó nhập các trang riêng lẻ từ tài liệu hiện có sang PDF mới.

// 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(); 

Điều này sẽ đọc trong PDF từ templateInputStream và ghi ra outputStream. Đây có thể là các luồng tệp hoặc luồng bộ nhớ hoặc bất kỳ điều gì phù hợp với ứng dụng của bạn.

+10

Cảm ơn vì điều này. Nếu bạn không muốn giới hạn nó chỉ với A4, bạn có thể thêm document.setPageSize (reader.getPageSize (1)); – Dittimon

+0

Khi tôi sử dụng phương pháp này, PDF xuất hiện tất cả không đúng giá trị. Vì vậy, tôi đã đi với câu trả lời của Mark Storer và sử dụng PdfStamper. –

+0

Thao tác này hoạt động tốt, nhưng các trang có acrofields không được sao chép với chúng trong cb.addTemplate (trang, 0,0). Acrofields không có sẵn ở đầu ra pdf – Vicky

40

đang Gutch là gần, nhưng nó sẽ chỉ làm việc ngay nếu:

  • Không có chú thích (liên kết, lĩnh vực, vv), không có tài liệu Cấu trúc/Nội dung đánh dấu, không dấu, không có tài liệu tập lệnh -level, v.v., v.v.
  • Kích thước trang sẽ là A.4 (tỷ lệ cược phù hợp, nhưng nó sẽ không hoạt động trên bất kỳ tệp PDF nào bạn gặp phải)
  • Bạn không không nhớ mất tất cả siêu dữ liệu gốc (nhà sản xuất, ngày tạo, có thể tác giả/tiêu đề/từ khóa) và có thể là ID tài liệu. Bạn không thể sao chép ngày tạo và ID tài liệu trừ khi bạn thực hiện một số tin tặc khá sâu trên iText).

Phương pháp được chấp thuận là thực hiện theo cách khác. Mở tài liệu hiện có bằng PdfStamper và sử dụng PdfContentByte được trả về từ hàm getOverContent() để viết văn bản (và bất kỳ thứ gì khác bạn có thể cần) trực tiếp vào trang. Không cần tài liệu thứ hai.

Và bạn có thể sử dụng ColumnText để xử lý bố cục và cho bạn ... không cần phải xuống và bẩn với beginText(), setFontAndSize(), drawText(), drawText() ..., endText() .

+0

Tất cả các điểm xuất sắc ... đó là cách tốt để xác định xem phương thức 'PdfStamper' hoặc' addTemplate' có tốt hơn cho kịch bản của bạn hay không. Trong trường hợp của tôi, 'addTemplate' rõ ràng là tốt hơn vì điểm của bạn: Tôi lấy mẫu nguồn của một nhà thiết kế đồ họa được tạo ra trong Adobe Illustrator, có rất nhiều rác và siêu dữ liệu và nặng khoảng 1MB. Nếu tôi sử dụng 'PdfStamper' các tài liệu được tạo sẽ là 1MB + và có tên của một nhà thiết kế đồ họa hợp đồng trong đó; bằng cách sử dụng 'addDocument' chúng tài liệu là 50kB và không có thông tin cá nhân được nhúng. – gutch

+0

Chà. Đó là một thay đổi kích thước HUGE. Siêu dữ liệu không phải là lớn ... những gì chiếm phần còn lại của không gian ?! –

+0

Tôi nghĩ rằng những tệp PDF lớn này sẽ có hộp 'Bảo tồn Khả năng Chỉnh sửa Illustrator', điều này sẽ lưu tất cả thông tin Adobe Illustrator trong tệp để cho phép chỉnh sửa thêm. Nó giống như việc tạo một tệp PDF từ một tài liệu và nhúng tệp DOC nguồn vào đó. – gutch

5

Đây là kịch bản phức tạp nhất tôi có thể tưởng tượng: Tôi có tệp PDF được tạo bằng Ilustrator và được sửa đổi với Acrobat để có AcroFields (AcroForm) mà tôi sẽ điền dữ liệu với mã Java này, kết quả của Tệp PDF với dữ liệu trong các trường được sửa đổi thêm Tài liệu.

Thực tế trong trường hợp này tôi đang tạo động nền được thêm vào tệp PDF cũng được tạo động với Tài liệu có lượng dữ liệu hoặc trang không xác định.

Tôi đang sử dụng JBoss và mã này nằm trong tệp JSP (nên hoạt động trong bất kỳ máy chủ web JSP nào).

Lưu ý: nếu bạn đang sử dụng trình duyệt IExplorer, bạn phải gửi biểu mẫu HTTP có phương thức POST để có thể tải xuống tệp. Nếu không, bạn sẽ thấy mã PDF trên màn hình. Điều này không xảy ra trong Chrome hoặc 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(); 
%> 

Có một giải pháp đơn giản hơn nhiều và giải quyết vấn đề của bạn. Nó phụ thuộc vào số lượng văn bản bạn muốn thêm vào.

// 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); 
     } 
    } 
} 
Các vấn đề liên quan