IText - добавление содержимого в существующий файл PDF
Я хочу сделать следующее с iText:
(1) проанализировать существующий файл PDF
(2) добавить к нему некоторые данные на существующей отдельной странице документа (например, метку времени)
(3) запишите документ
Я просто не могу понять, как это сделать с iText. В псевдокоде я бы сделал следующее:
Document document = reader.read(input);
document.add(new Paragraph("my timestamp"));
writer.write(document, output);
Но по какой-то причине iText API настолько сложна, что я не могу обернуть вокруг себя. PdfReader фактически держит модель документа или что-то (вместо того, чтобы выплескивать документ), и вам нужен PdfWriter для чтения страниц из него... eh?
Ответы
Ответ 1
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
. Это могут быть потоки файлов или потоки памяти или все, что подходит вашему приложению.
Ответ 2
Код Gutch близок, но он будет работать только в том случае, если:
- Нет аннотаций (ссылок, полей и т.д.), нет структуры документа/помеченного содержимого, никаких закладок, уровня документа script и т.д. и т.д. и т.д.
- Размер страницы - это A.4 (приличные коэффициенты, но это не сработает ни на одном OL файле, с которым вы столкнулись)
- Вы не против потерять все оригинальные метаданные документа (продюсер, дата создания, возможно автор/название/ключевые слова) и, возможно, идентификатор документа. Вы не можете скопировать дату создания и идентификатор документа, если вы не сделаете довольно глубокий хакер на самом iText).
Утвержденный метод заключается в том, чтобы сделать это наоборот. Откройте существующий документ с помощью PdfStamper и используйте возвращаемый PdfContentByte из getOverContent() для записи текста (и всего, что вам может понадобиться) непосредственно на страницу. Не требуется второй документ.
И вы можете использовать ColumnText для обработки макета и т.д. для вас... нет необходимости спускаться и грязно с beginText(), setFontAndSize(), drawText(), drawText()..., endText().
Ответ 3
Это самый сложный сценарий, который я могу себе представить: у меня есть файл 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();
Ответ 4
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\\ 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);
}
}
}