I am working with the iText library to do some PDF manipulation in Java, but I am trying to do something in which the iText API is starting to overwhelm me. I really just need a quick tutorial, or some pseudo-code, but here is what I am trying to accomplish:
User selects a series of check boxes, indicating which PDFs he or she wishes to print.
Based on user input, grab 1 - x PDF template files. Each page has a series of AcroFields which need to be filled out.
One such page requires drawing some custom graphics on the PDF, i.e. accessing the PdfContentByte object and manipulating that to insert images and rectangles.
If it possible, I would like to avoid writing temporary PDFs to disk. The previous programmer did this, and it has been messy to deal with that. I'd much prefer to grab the template file, manipulate it in memory and serve it directly to the browser.
I seem to have all the pieces, but I can't quite put it all together. Point #4 is what's been really tripping me up.
TIA.
So, here is the answer I was finally able to come up with:
//Open an input stream to the PDF template
InputStream is = getInputStreamToEachFile();
//Declare a document object, as well as a PdfCopy for
//copying in each PdfFile we open in memory and edit.
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, outputStreamToBrowser);
//Be sure to open the document or it will throw an exception!
doc.open();
//Since the PdfStamper class wants to output everything to an
//output stream you can declare a ByteArrayOutputStream object
//and direct it there, since we need to tack on more PDFs and
//can't just output to the response's output stream directly.
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(new PdfReader(is), byteStream);
//Pseduocode - set form fields - just check out
//the documentation for AcroFields in the API
//this part is easy.
...
//if form has custom graphics declare a PdfContentByte array
//the 1 argument in the getUnderContent refers to the page number
PdfContentByte cb = stamper.getUnderContent(1);
//pseduocode - do custom graphics. This can be a lot of different things,
//so check the documentation
...
//Wrap things up - set the dyanamic form fields to read only
//and call the stamper's close function to close the streams
stamper.setFormFlatterning(true);
stamper.close()
//Finally, declare a new PdfReader, reading the stamper's byte array stream
//which was declared in memory.
PdfReader outReader = new PdfReader(byteStream.toByteArray());
//Use this function call to add each page that you need. Repeat this process
//for as many PDFs as are being stitched together.
copy.addPage(copy.getImportedPage(outReader,1));
//Finally, tell the browser you are done generating the file, and output it.
//If there are a lot of pages being generated this way, I guess you could use the flush
//function instead, and then call close when they are all done.
copy.close();
Thanks go out to this tutorial which I eventually found on my own:
http://itextpdf.com/examples/iia.php?id=127
Related
I want to populate interactive pdf form with the xml using itext:
//build the xmlString, convert it to InputStream
AcroFields fields = pdfStamper.getAcrofields();
XfaForm form = fields.getXfa();
form.fillXfaForm(xmlStream);
The fields getting populated, however the resulting *.pdf is now not editable in the Adobe Reader. That is the document property has "Filling of form fields: Now Allowed" now. So, I was digging around for a solution and read somewhere (I believe the itext in action book), that the itext does, indeed, break the usage rights. After, I tried the solutions described here:
http://itextpdf.com/examples/iia.php?id=166
That is, remove usage rights completely or create stamper in the append mode, e.g.,
reader.removeUsageRights();
or
PdfStamper stamper = PdfStamper(reader, new FileOutputStream(dest), '\0', true)
The pdf is now editable. However, the PDF form I am populating has a drop-down menu - if a particular option in that drop-down is selected, the pdf form activates one of its own text field. This does not work anymore - the drop-down is selected, but the text field it supposed to activate remains inactivate and blank.
I've read that the usage rights are part of the pdf own encryption, I was wondering if it is possible to get that encryption and set it into into a populated copy of the pdf form?
Thank you
I am trying to set a list of images in a PDF document using iText with Java, i could just insert some of them in the first page but i don't know how to jump to the next pages in order to put the rest of my pictures
for(int i = 0; i < 25; i++) {
Image myImg = Image.getInstance("/home/code/img"+i+".png");
imgPaper.setAbsolutePosition(50, 728-(y*58));
document.add(myImg);
y++;
}
The OP clarified his question in a comment
i have already another pages, i just want how to jump to themĀ
You seem to be creating a new document using a PdfWriter. That class is designed to create a pdf one page after the other. As soon as you start a new page, all former ones are written to file.
Thus, in this process you cannot jump to arbitrary pages. You have to add all information for a page while it is the current one.
If, after creating a multi page document, you need to manipulate the content of its pages, first close the document (finishing it), read it into a PdfReader, and apply a PdfStamper which allows you to manipulate arbitrary pages of an existing PDF.
Alternatively, especially if your images constitute something like a water mark or header/footer Logos, consider using page events in your pdf creation process with the PdfWriter.
try to add a new line to your document
document.add( Chunk.NEWLINE );
link for info:
How to insert blank lines in PDF?
I have a problem with iText and flatten form fields in pdfs.
I submit a pdf with form fields created in Acrobat to my java method. On a website i have created a form to fill the form fields in the pdf. The form fields are filled correctly, but as soon as i flatten the document the text is moved to a little different position. The biggest difference is seen in multiline form fields. There the text is at the border of the field in the upper left. In Acrobat and before flattening the text has a padding to the top.
Here is my java code to call the methods of iText:
PdfReader template = new PdfReader(templ);
XfdfReader xfdfReader = new XfdfReader(xfdf);
OutputStream outputStream = new FileOutputStream(output);
PdfStamper stamper = new PdfStamper(template, outputStream, '\0');
AcroFields form = stamper.getAcroFields();
Set<String> fields = form.getFields().keySet();
form.setFields(xfdfReader);
stamper.setFreeTextFlattening(true);
stamper.setFormFlattening(true);
stamper.close();
template.close();
Anyone has an idea why the text is moving when i flatten the pdf? How can I avoid this?
I allready tried different versions from iText. From version 4.X to 5.X. The difference appears in all versions.
Although i tried to move the form fields in the code of iText, but then the whole field is moving and the difference of the position is much bigger and not predictable.
In my project the text must be at the exact same position as in Acrobat, so i must find a workaround for this misbehavior. I hope somebody can help me.
Thanks for your help in advance.
The position of the baseline of a field in a PDF file has been changed over the years. You'll even see differences depending on the version of Acrobat you are using.
There is no solution for your problem unless you know the exact offset. If you do, you can use the setExtraMargin() method to change the offset of all fields when flattening the document.
We created this method to deal with specific forms that have a baseline that is different from what is to be expected. Which values you choose can be different for different forms.
I want to add a piece of text to every page of a PDF file. This answer in SO works fine. But, the text is added to the top of the page. I would like to add my text to the bottom of each page. How do I do this?
Here is the relevant part of the code.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
document.newPage();
pageOfCurrentReaderPDF++;
currentPageNumber++;
page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
document.add(new Paragraph("My Text here")); //As per the SO answer
}
pageOfCurrentReaderPDF = 0;
}
The code is part of a function which accepts a folder, reads the PDF files in it and merges them into one single file. So, I would like to add the text in the above loop itself, instead of iterating the file once again.
If you want to automatically add content to every page, you need a page event.
This is explained in chapter 5 of my book" iText in Action - Second Edition".
If you don't own a copy of the book, you can consult the examples here.
You can also find solutions by looking for the keyword Header / Footer.
The example you're referring to doesn't look correct at first sight. Sure, you can use "two passes", one to create the content, and another to add headers or footers, but the suggested solution is different from the recommended solution: http://itextpdf.com/examples/iia.php?id=118
You are copying the mistake in your question: why on earth would you import the document you've just created into a new document, thus throwing away all possible interactivity you've added to that document? It just doesn't make sense. It's unbelievable that this answer received that many up-votes. I'm the original developer of iText and I'm not at all happy with that answer!
In your case, there may be no need to create the document in memory first and to add the footer afterwards. Just take a look at http://itextpdf.com/examples/iia.php?id=104
You need to create a PdfPageEvent implementation (for instance using PdfPageEventHelper) and you need to implement the onEndPage() method.
Documented caveats:
Do not use onStartPage() to add content,
Do not add anything to the Document object passed to the page event,
Unless you specified a different page size, the lower-left corner has the coordinate x = 0; y = 0. You need to take that into account when adding the footer. The y-value for the footer is lower than the y-value for the header.
For more info: consult my book.
Have a look at chapter 6 of iText in Action, 2nd edition, especially at subsection 6.4.1: Concatenating and splitting PDF documents.
Listing 6.22, ConcatenateStamp.java, shows you how you should create a PDF from copies of pages (in your case: all pages) of multiple other PDFs; the sample additionally adds a new "Page X of Y" footer; this demonstrates how you can add content at given positions on the pages while merging the source files.
Perhaps this may be of assistance here... I suspect you want to do something like the following:
cb.addTemplate(page, 0, 0);
document.add(new Paragraph("My Text here"));
document.setFooter(new HeaderFooter("Footnote goes here"));
}
pageOfCurrentReaderPDF = 0;
I have a requirement to insert Content into the middle of the page in a PDF.
The Content may be a Dynamic Table or an Image.
My Concept was to first split the PDF into 2 parts, then get the new Content that is to be added and append by replacing a place holder field.
the Splitting is called Tiling as per IText and here is an example for the same.
http://itextpdf.com/examples/iia.php?id=116
The Code above has 2 drawbacks:
1. It splits the page into 16 parts. but that is part of the example. Still i cant figure out a way to split the file into 2 parts only.
2. secondly the split page is converted to a complete page thus disturbing its proportions.
The Rearranging code is the another problem.
The remaining Content should be re-ordered in append mode. but till yet i have only found codes to add complete new pages rather than just the content.
I have found a code that appends the PDF content by replacing a placeholder:
float[] fieldPosition= pdfTemplate.getAcroFields().getFieldPositions("tableField");
PdfPTable table = buildTable();
PdfContentByte cb = stamper.getOverContent(1);
table.writeSelectedRows(0, -1, fieldPosition[1],fieldPosition[4],cb);
Please help me to solve this requirement.
PDF is a presentation format, not an edition format. In other words, it is not designed to allow content insertion, with the original content reflowing gracefully. As a consequence, no tool (at least, none that I know of, and surely not iText) will enable you to achieve what you were given as a requirement.
My advice :
refuse the assignment since it's not feasible, or
get your hands on the original document, insert the desired extra content, and then convert to PDF.