I have an application that creates a PDF file using Java, Spring and IText.
I want to add a watermark to the pdf.
I have found plenty of examples of adding a watermark to an already saved PDF. I want to add the watermark before the PDF is saved.
I found an example of doing what I want using ITextSharp, however, it is for .NET. I am using the following code in my class that creates the pdf document.
protected void buildPdfDocument(Map model, Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception {
response.setContentType("application/pdf");
ProgramCmd programCmd = (ProgramCmd) request.getSession().getAttribute("programCmd ");
List<Courses> list = programCmd.getCoursesList();
List<Events> eventsList = programCmd.getEventsList();
FONT_SIZE_16_BOLD.setColor(232, 177, 0);
// Print Header
Paragraph paragraph = new Paragraph("Title",FONT_SIZE_16_BOLD);
paragraph.setAlignment(Element.ALIGN_CENTER);
document.add(paragraph);
paragraph = new Paragraph("***This is Not Official***",FONT_SIZE_12_BOLD);
paragraph.setAlignment(Element.ALIGN_CENTER);
document.add(paragraph);
paragraph = new Paragraph("Create Date: " + todaysDate,FONT_SIZE_12_BOLD);
paragraph.setAlignment(Element.ALIGN_CENTER);
document.add(paragraph);
}
Please let me know if you want me to post other code.
Thank you.
The first edition of the book "iText in Action" has an example "WatermarkExample.java" in chapter 14. You can download the source of the example at Manning's website, though of course, I also encourage you to purchase the book!
Thank you for promoting my book, GreyBeardedGeek (deserves an upvote).
Let me elaborate on the matter:
It's not clear if you want to add the watermark while you're creating the document (that's done with page events), or after the document is created (that's done with PdfStamper).
These are examples of both options:
In http://itextpdf.com/examples/iia.php?id=105 we extend PdfPageEventHelper and implement the onEndPage() method. As documented, you shouldn't add anything to the Document class, nor use the onStartPage() method to add content. (More info in iText in Action - Second Edition).
In http://itextpdf.com/examples/iia.php?id=119 we add a background to an existing PDF using PdfStamper and PdfReader. You don't need to have a file on disk to create a PdfReader instance. You can create the file in memory first (e.g. using a ByteArrayOutputStream) and pass the bytes to the PdfReader constructor.
Related
I am using iText7 for pdf signature workflow, i followed the samples provided with i7js-signatures. However my requirement is to take an input pdf file, add sequential signatures to it, and further pass it for signature.
i tried splitting up the process in two steps.
Take input pdf and add sequential signature panel, in the intermediate_output file.
public void createForm() throws IOException {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(FORM),new PdfWriter(TMP));
//PdfDocument pdfDoc = new PdfDocument(new PdfWriter(FORM));
pdfDoc.addNewPage();
Document doc = new Document(pdfDoc);
Table table = new Table(1);
table.addCell("Signer 1: Alice");
table.addCell(createSignatureFieldCell("sig1"));
table.addCell("Signer 2: Bob");
table.addCell(createSignatureFieldCell("sig2"));
table.addCell("Signer 3: Carol");
table.addCell(createSignatureFieldCell("sig3"));
doc.add(table);
doc.close();
}
Take intermediate_output file and sign it.
While running the step two with output of step 1, i am getting com.itextpdf.kernel.PdfException: error.reading.objstm
Exception in thread "main" com.itextpdf.kernel.PdfException: error.reading.objstm
at com.itextpdf.kernel.pdf.PdfReader.readObjectStream(PdfReader.java:508)
at com.itextpdf.kernel.pdf.PdfReader.readObject(PdfReader.java:1014)
at com.itextpdf.kernel.pdf.PdfReader.readObject(PdfReader.java:533)
at com.itextpdf.kernel.pdf.PdfIndirectReference.getRefersTo(PdfIndirectReference.java:128)
at com.itextpdf.kernel.pdf.PdfIndirectReference.getRefersTo(PdfIndirectReference.java:132)
at com.itextpdf.kernel.pdf.PdfArray.get(PdfArray.java:376)
at com.itextpdf.kernel.pdf.PdfArray.get(PdfArray.java:237)
Input pdf:
Intermediate pdf page 1:
Intermediate pdf page 2:
Please guide me in case, i am doing something wrong here.
The underlying iText 7 bug/peculiarity is the same as described in this answer where the table is built across four pages but all the fields turns up on the last page.
As you clarified, though, in a comment, you want the table and the fields on the last page anyways. Thus, all we need to do is move the table to the last page, too.
This actually is quite simple, merely add an appropriate AreaBreak before adding the table:
doc.add(new AreaBreak(AreaBreakType.LAST_PAGE));
doc.add(table);
(AddSignatureField test testAddSignaturesInTable)
You updated your iText version in the context of this question. Meanwhile there have been considerable changes in the table creation code. Thus, you will probably want to also set a width of the signature cell, e.g.
Cell cell = new Cell();
cell.setHeight(50);
cell.setWidth(200);
cell.setNextRenderer(new SignatureFieldCellRenderer(cell, name));
return cell;
(AddSignatureField method createSignatureFieldCell)
In my project, some data sets are needed to be exported in PDF format.
I learned that iText is helpful, and PdfpTable can do the work, but it needs much code to deal with styles. While using PDF template can save time and code for adjusting style, but I can only set certain fields left in the template.
Can you give me some suggestions to show the data sets using commands like foreach? Thanks in advance!
Here are my code using pdfpTable, which has done the work, but the code is a little ugly:
PdfPTable pdfTable = createNewPDFTable();
for (int i = 0; i < dataSet.size(); i++) {
MetaObject metaObject = SystemMetaObject.forObject(dataSet.get(i));
for (String field : fields) {
Phrase phrase = new Phrase(String.valueOf(metaObject.getValue(field) != null ? metaObject.getValue(field) : "")
, PDFUtil.createChineseSong(DEFAULT_CELL_FONT_SIZE));
PdfPCell fieldCell = new PdfPCell(phrase);
fieldCell.setBorder(Rectangle.NO_BORDER);
fieldCell.setFixedHeight(DEFAULT_COLUMN_HEIGHT);
fieldCell.setHorizontalAlignment(Element.ALIGN_CENTER);
fieldCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
pdfTable.addCell(fieldCell);
}
}
Here are some code using pdfp template,which is copied from itext examples, the work is unfinished yet because i haven't find a proper way to show the data set.
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
form.setField("text_1", "Bruno Lowagie");
form.setFieldProperty("text_1", "setfflags", PdfFormField.FF_READ_ONLY, null);
There is an inconsistency in your question. You write: PdfpTable can do the work, but it needs much code to deal with styles. However, in your first code snippet, you don't really create your PDFs the way one would expect. Instead of producing a high volume of finished PDFs, you create use PdfPTable to create a template. I assume you then use that template to create a high volume of finished PDFs.
If you want to use a template and populate it afterwards, you shouldn't create your form using iText. Create it manually, for instance using Open Office or Libre Office. See for instance the example in chapter 6 of my book (section 6.3.5). Create the template with a tool that has a GUI, then fill out that template many times using iText.
This approach has some down-sides: all the content has to fit the fields you define. All fields have a fixed position on a fixed page.
If "applying styles through code" is a problem, you may want to follow the approach described in the ZUGFeRD book. In that book, we create HTML first: Creating HTML invoices.
Once you have the HTML, then convert the HTML to PDF, and use CSS to apply styles: Creating PDF invoices.
This is how we create a ZUGFeRDDocument:
ZugferdDocument pdfDocument = new ZugferdDocument(
new PdfWriter(fos), ZugferdConformanceLevel.ZUGFeRDComfort,
new PdfOutputIntent("Custom", "", "http://www.color.org",
"sRGB IEC61966-2.1", new FileInputStream(INTENT)));
pdfDocument.addFileAttachment(
"ZUGFeRD invoice", dom.toXML(), "ZUGFeRD-invoice.xml",
PdfName.ApplicationXml, new PdfDictionary(), PdfName.Alternative);
pdfDocument.setTagged();
HtmlConverter.convertToPdf(
new ByteArrayInputStream(html), pdfDocument, getProperties());
The getProperties() method looks like this:
public ConverterProperties getProperties() {
if (properties == null) {
properties = new ConverterProperties()
.setBaseUri("resources/zugferd/");
}
return properties;
}
You can find other examples on how to use HTML to PDF here: pdfHTML add-on (read the introduction).
Note that you are using an old version of iText. The examples I shared are using iText 7. There's a huge difference between iText 5 and iText 7.
i try to generate a pdf with itext. First i read in a existing template and stamp the formulars in the method stampFormular(Formular formular, PdfStamper stamper). The stamp method works. But i have a problem, with adding more formulars to the output file.
I want to stamp for each Formular the PDF Template "yellow". So i tried it with, the document.add(), but that doesn't work. So i tried to do this with pdf writer. But that doesn't work to. Any idea how i can stamp the pdf template with the one formular data, make a new page and stamp the same pdf template with the next formular data.
public static File createForm(List<Fomular> formulars) {
Document document = new Document();
File pdf = null;
document.open();
try {
PdfReader pdfTemplate = new PdfReader('YELLOW');
PdfStamper stamper = new PdfStamper(pdfTemplate,
new FileOutputStream("output.pdf"));
PdfWriter writer;
for (Formular f : formulars) {
stamper = stampFormular(f, stamper);
writer = stamper.getWriter();
writer.newPage();
}
stamper.close();
pdfTemplate.close();
pdf = new File("output.pdf");
Desktop.getDesktop().open(pdf);
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
return pdf;
}
A couple of observations:
You can't take the PdfWriter object from a PdfStamper, use newPage() and expect it to work. That's the equivalent of opening the hood of your car and start rewiring tubes that fit without knowing anything about the art of motor maintenance. When you want to add a new page to a stamper, you're supposed to use the insertPage() method as explained in the documentation.
Second observation: you're not telling us if you're flattening the content of the forms. If you do, then it's simple, just use the example mentioned in the documentation and you're all set. In other words: combine PdfStamper with PdfSmartCopy. Especially if you're using the same template over and over again, PdfSmartCopy will give you much better results than PdfCopy for the reason explained in chapter 6.
Suppose that your template needs to remain interactive, then you may have a problem for a reason that is also explained in that chapter: different visualizations of a field with a specific name must always have the same value. For instance: if your template has a field named name, then every occurrence of this field in the document must have the same value. If you don't want this, you need to rename name, for instance to name1, name2, etc...
Concatenation of templates that need to remain interactive used to be done with PdfCopyFields (see documentation). Here, the documentation is somewhat outdated. In the latest version of iText, we now have a method addDocument() in PdfCopy and PdfSmartCopy. This method allows you to add a full document at once, preserving the interactivity.
I am doing some "pro bono" development for a food pantry near where I live. They are inundated with forms and paperwork, and I would like to develop a system that simply reads data from their MySQL server (which I set up for them on a previous project) and feeds data into PDF versions of all the forms they are required to fill out. This will help them out enormously and save them a lot of time, as well as get rid of a lot of human errors that are made when filling out these forms.
Not knowing anything about the internals of PDF files, I can foresee two avenues here:
Harder Way: It is possible to scan a paper document, turn it into a PDF, and then have software that "fills out" the PDF simply by saying "add text except blah to the following (x,y) coordinates..."; or
Easier Way: PDF specification already allows for the construct of "fields" that can be filled out; this way I just write code that says "add text excerpt blah to the field called *address_value*...", etc.
So my first question is: which of the two avenues am I facing? Does PDF have a concept of "fields" or do I need to "fill out" these documents by telling the PDF library the pixel coordinates of where to place data?
Second, I obviously need an open source (and Java) library to do this. iText seems to be a good start but I've heard it can be difficult to work with. Can anyone lend some ideas or general recommendations here? Thanks in advance!
You can easily merge data into PDF's fields using the FDF(Form Data Format) technology.
Adobe provides a library to do that : Acrobat Forms Data Format (FDF) Toolkit
Also Apache PDFBox can be used to do that.
Please take a look at the chapter about interactive forms in the free ebook The Best iText Questions on StackOverflow. It bundles the answers to questions such as:
How to fill out a pdf file programatically?
How can I flatten a XFA PDF Form using iTextSharp?
Checking off pdf checkbox with itextsharp
How to continue field output on a second page?
finding out required fields to fill in pdf file
and so on...
Or you can watch this video where I explain how to use forms for reporting step by step.
See for instance:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader,
new FileOutputStream(dest));
AcroFields fields = stamper.getAcroFields();
fields.setField("name", "CALIFORNIA");
fields.setField("abbr", "CA");
fields.setField("capital", "Sacramento");
fields.setField("city", "Los Angeles");
fields.setField("population", "36,961,664");
fields.setField("surface", "163,707");
fields.setField("timezone1", "PT (UTC-8)");
fields.setField("timezone2", "-");
fields.setField("dst", "YES");
stamper.setFormFlattening(true);
stamper.close();
reader.close();
}
public void fillPDF()
{
try {
PDDocument pDDocument = PDDocument.load(new File("D:/pdf/pdfform.pdf")); // pdfform.pdf is input file
PDAcroForm pDAcroForm = pDDocument.getDocumentCatalog().getAcroForm();
PDField field = pDAcroForm.getField("Given Name Text Box");
field.setValue("firstname");
field = pDAcroForm.getField("Family Name Text Box");
field.setValue("lastname");
field = pDAcroForm.getField("Country Combo Box");
field.setValue("Country");
System.out.println("country combo" );
field = pDAcroForm.getField(" Driving License Check Box");
field = pDAcroForm.getField("Favourite Colour List Box");
System.out.println("country combo"+ field.isRequired());
pDDocument.save("D:/pdf/pdf-java-output.pdf");
pDDocument.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I am using iText 2.1.7 to generate a document from a database. One of the fields I need to add is in XHTML format. I can use the HTMLWorker class to generate the HTML but this is a bit limited.
I convert this to XHTML using the following code:
String url = chapterDesc.getString("description").toString(); // get the HTML string from the database
org.w3c.dom.Document doc = XMLResource.load(new ByteArrayInputStream(url.getBytes())).getDocument();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
renderer.layout();
renderer.createPDF(os);
I want to add this information to the document in memory. Is this possible?
Do I need to use PdfStamper? I believe that this requires the document to be closed? If it is possible I would like to avoid using multiple passes to add these descriptions.
Flying saucer does not work correctly with any version of iText other than 2.0.8. Also since you meantioned creating the pdf in memory are you using JSF, JSP, or servlets? If you are than you can just send your ByteArrayOutputStream as a response on one of these pages using something along the lines of
response.setContentType("application/pdf");
response.setContentLength(os.size());
os.writeTo(response.getOutputStream());
response.flushBuffer();
I know it's been more than two years since you've asked, but I'm facing the same problem. I googled for a solution and apparently there is none anywhere to be found. So I had to develop my own and I thought I might as well share it. Hope it'll be useful to someone.
I tried to use flying saucer as you did, but it didn't work for me. My piece of HTML was just a simple table so I could use iText HTMLWorker to do the parsing.
So first I get a PdfStamper as you suggested.
PdfReader template = new PdfReader(templateFileName);
PdfStamper editablePage = new PdfStamper(template, reportOutStream);
Then I work with the document (fill the fields, insert some images) and after that I need to insert an HTML snippet.
//getting a 'canvas' to add parsed elements
final ColumnText page = new ColumnText(editablePage.getOverContent(pageNumber));
//finding out the page sizefinal
Rectangle pagesize = editablePage.getReader().getPageSize(pageNumber);
//you can define any size here, that will be where your parsed elements will be added
page.setSimpleColumn(0, 0, pagesize.getWidth(), pagesize.getHeight());
If you need simple styling, HTMLWorker can do some
StyleSheet styles = new StyleSheet();
styles.loadStyle("h1", "color", "#008080");
//parsing
List<Element> parsedTags = HTMLWorker.parseToList(new StringReader(htmlSnippet), styles);
for (Element tag : parsedTags)
{
page.addElement(tag);
page.go();
}
These are just some basic ideas of how to do that, hope it helps.