I am trying to add footer containing username on the left and page number of total pages on the right
I am using iTextPdf 7 on Java but I am not able to find any useful way to do that
please find below my code
The import :
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
small sample of the code :
PdfWriter pdfWriter = new PdfWriter(path);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.addNewPage();
Document document = new Document(pdfDocument);
Paragraph dateParagraph = new Paragraph(todayDate.toString());
dateParagraph.setTextAlignment(TextAlignment.RIGHT);
document.add(dateParagraph);
document.close();
footer sample :
this is sample for the needed footer
A very basic example that does the job. There are numerous ways of adding footers with page numbers in iText and depending on your context one way might be more suitable than the others. The sample I provide is a good start:
Document document = new Document(pdfDocument, PageSize.A4, false);
for (int i = 0; i < 10; i++) {
if (i != 0) {
document.add(new AreaBreak());
}
document.add(new Paragraph("Hello"));
}
int totalPages = document.getRenderer().getCurrentArea().getPageNumber();
for (int i = 1; i <= totalPages; i++) {
Paragraph footer = createFooter(totalPages);
footer.setFixedPosition(i, 40, 40, 300);
document.add(footer);
}
document.close();
Note that I am using Paragraph as a footer element but you can use Table or anything else really:
private Paragraph createFooter(int totalPages) {
Paragraph p = new Paragraph();
Text currentPage = new Text("");
currentPage.setNextRenderer(new CurrentPageNumberRenderer(currentPage));
p.add("Page ").add(currentPage).add(" of ").add(new Text(String.valueOf(totalPages)));
return p;
}
Here is our custom renderer that will assign page number dynamically:
private static class CurrentPageNumberRenderer extends TextRenderer {
public CurrentPageNumberRenderer(Text textElement) {
super(textElement);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
int currentPageNumber = layoutContext.getArea().getPageNumber();
setText(String.valueOf(currentPageNumber));
return super.layout(layoutContext);
}
#Override
public IRenderer getNextRenderer() {
return new CurrentPageNumberRenderer((Text) modelElement);
}
}
Visual result:
Related
Good Morning,
I've been following the Merge with TOC examples and not having any luck getting the PdfActions to respond. Here is my snippet:
PdfReader finalReader = new PdfReader(viewableStream.toByteArray());
Document finalDoc = new Document(PageSize.LETTER);
PdfCopy finalPdfCopy = new PdfCopy(finalDoc,stream);
PdfCopy.PageStamp finalPdfStamp;
finalDoc.open();
int finalNumPages = finalReader.getNumberOfPages();
for(int finalPageIndex = 1;finalPageIndex <= finalNumPages;finalPageIndex++) {
PdfImportedPage finalImpPage = finalPdfCopy.getImportedPage(finalReader,finalPageIndex);
finalPdfStamp = finalPdfCopy.createPageStamp(finalImpPage);
if (finalPageIndex == tocPage) {
new TOCCustomizer().generateLinks(finalDoc, finalPdfCopy, finalPdfStamp, finalImpPage, vApp.getBookBuildContext(), book);
}
finalPdfStamp.alterContents();
finalPdfCopy.addPage(finalImpPage);
}
finalDoc.close();
finalPdfCopy.close();
stream.flush();
stream.close();
generateLinks method:
public void generateLinks(Document finalDoc,PdfCopy finalPdfCopy,PdfCopy.PageStamp stamp,PdfImportedPage srcPage,BookBuilderContext context, Book book) throws Exception
{
finalDoc.setMargins(0.75f * 72, 0.75f * 72, 0.75f * 72, 0.75f * 72);
finalDoc.add(new Paragraph(" "));
File fontFile = new File(context.getResourcePath(), "ProximaNova-Reg.otf");
BaseFont bfRegular = BaseFont.createFont(
fontFile.getAbsolutePath(),
BaseFont.CP1252,
BaseFont.EMBEDDED
);
Font font1 = new Font(bfRegular,14, Font.NORMAL, Colors.SLATE_GREY);
// create a table for the content
PdfPTable table = new PdfPTable(3);
table.setTotalWidth(7.5f*72);
table.setWidths(new float[]{32f,458f,50f});
int currentPage = 1;
for (int i = 0; i < book.getNumSections(); i++)
{
v.bookmodel.Section s = book.getSection(i);
String itemNbr = s.getItemNbr();
// don't add excluded sections
if (s.isIncluded() && !TOC_EXCLUDE.contains(itemNbr))
{
PdfPCell sectNumCell = new PdfPCell(new Phrase(i+". ",font1));
sectNumCell.setBorder(0);
sectNumCell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
sectNumCell.setPaddingLeft(5);
sectNumCell.setPaddingBottom(10);
sectNumCell.setPaddingTop(15);
table.addCell(sectNumCell);
Chunk sectChunk = new Chunk(s.getSectionName());
sectChunk.setFont(font1);
// sectChunk.setAction(PdfAction.gotoLocalPage(currentPage, new PdfDestination(PdfDestination.FITH), finalPdfCopy));
sectChunk.setAction(new PdfAction(PdfAction.FIRSTPAGE));
Phrase sectPhrase = new Phrase(sectChunk);
PdfPCell sectDescCell = new PdfPCell(sectPhrase);
sectDescCell.setBorder(0);
sectDescCell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
sectDescCell.setPaddingLeft(5);
sectDescCell.setPaddingBottom(10);
sectDescCell.setPaddingTop(15);
table.addCell(sectDescCell);
PdfPCell sectPageCell = new PdfPCell(new Phrase(currentPage+"",font1));
sectPageCell.setBorder(0);
sectPageCell.setHorizontalAlignment(PdfPCell.ALIGN_RIGHT);
sectPageCell.setPaddingLeft(5);
sectPageCell.setPaddingBottom(10);
sectPageCell.setPaddingTop(15);
table.addCell(sectPageCell);
int sectionPages = s.getSectionTotalPages();
currentPage+=sectionPages;
} else if (s.isIncluded() && TOC_SECTIONS.contains(itemNbr)) {
int sectionPages = s.getSectionTotalPages();
currentPage+=sectionPages;
}
}
The document is getting created, but the TOC links will not go back to the first page. I did convert this to use PdfWriter instead of PdfCopy and this worked for the links, but I can't use PdfWriter due to the different original pdf boxing. I think there's something simple that I'm missing, but struggling to see what it is. Any help would be greatly appreciated. I'm currently using version 2.0.7 on this project.
Thanks In Advance,
-Jeff
I am using Apace POI to process some documents and I would like to add a header/footer which would consist of multiple paragraphs, but I would like for them to be displayed on the same line.
This is my attempt so far:
XWPFDocument document = new XWPFDocument();
// adding header and footer
CTP ctp = CTP.Factory.newInstance();
CTR ctr = ctp.addNewR();
// create footer components
CTText footerCopyrightText = ctr.addNewT();
footerCopyrightText.setStringValue("\u00A9" + " My Website - " + Calendar.getInstance().get(Calendar.YEAR));
CTText footerPageText = ctr.addNewT();
footerPageText.setStringValue(document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages() + "");
XWPFParagraph footerCopyrightParagraph = new XWPFParagraph( ctp, document );
footerCopyrightParagraph.setAlignment(ParagraphAlignment.CENTER);
XWPFParagraph footerPageParagraph = new XWPFParagraph(ctp, document);
footerPageParagraph.setAlignment(ParagraphAlignment.RIGHT);
XWPFParagraph[] footerParagraphs = {footerCopyrightParagraph, footerPageParagraph};
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document, sectPr );
headerFooterPolicy.createFooter(STHdrFtr.DEFAULT, footerParagraphs);
However, the end result so far is that I get a single right-aligned text, which consists of the two XWPFParagraphs, concatenated.
I have also checked some other examples here on Stack Overflow (there was one for a Header, but I didn't manage to get it to work).
A basic idea of what I want to achieve is this: http://imgur.com/jrwVO0F
Any ideas on what I am doing wrong?
Thank you,
Add Tabstops and use them
Here's my draft - printing my Name Left, Center and Right on a A4 Document. I have no clue whatsoever as to how those position elements are calculated though... Code to add tabstops is from Java Apache POI Tab Stop word document
import java.awt.Desktop;
import java.io.*;
import java.math.BigInteger;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
public class POIExample {
public static void main(String[] args) {
try {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun tmpRun = paragraph.createRun();
tmpRun.setText("JAN");
tmpRun.addTab();
tmpRun.setText("JAN");
tmpRun.addTab();
tmpRun.setText("JAN");
BigInteger pos1 = BigInteger.valueOf(4500);
setTabStop(paragraph, STTabJc.Enum.forString("center"), pos1);
BigInteger pos2 = BigInteger.valueOf(9000);
setTabStop(paragraph, STTabJc.Enum.forString("right"), pos2);
File f = File.createTempFile("poi", ".docx");
try (FileOutputStream fo = new FileOutputStream(f)) {
document.write(fo);
}
Desktop.getDesktop().open(f);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setTabStop(XWPFParagraph oParagraph, STTabJc.Enum oSTTabJc, BigInteger oPos) {
CTP oCTP = oParagraph.getCTP();
CTPPr oPPr = oCTP.getPPr();
if (oPPr == null) {
oPPr = oCTP.addNewPPr();
}
CTTabs oTabs = oPPr.getTabs();
if (oTabs == null) {
oTabs = oPPr.addNewTabs();
}
CTTabStop oTabStop = oTabs.addNewTab();
oTabStop.setVal(oSTTabJc);
oTabStop.setPos(oPos);
}
}
So, after some tinkering, I finally have a functioning version. Here's hoping it will prove useful to other users as well.
Creating footer object code
// create footer components
XWPFDocument document = new XWPFDocument();
CTP footerCtp = CTP.Factory.newInstance();
CTR footerCtr = footerCtp.addNewR();
XWPFParagraph footerCopyrightParagraph = new XWPFParagraph(footerCtp, document);
document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages();
XWPFRun run = footerCopyrightParagraph.getRun(footerCtr);
run.setText("My Website.com");
run.addTab();
run.setText("\u00A9" + " My Website - " + Calendar.getInstance().get(Calendar.YEAR));
run.addTab();
run.setText("Right Side Text");
setTabStop(footerCtp, STTabJc.Enum.forString("right"), BigInteger.valueOf(9000));
XWPFParagraph[] footerParagraphs = {footerCopyrightParagraph};
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document, sectPr);
headerFooterPolicy.createFooter(STHdrFtr.DEFAULT, footerParagraphs);
SetTabStop method
private static void setTabStop(CTP oCTP, STTabJc.Enum oSTTabJc, BigInteger oPos) {
CTPPr oPPr = oCTP.getPPr();
if (oPPr == null) {
oPPr = oCTP.addNewPPr();
}
CTTabs oTabs = oPPr.getTabs();
if (oTabs == null) {
oTabs = oPPr.addNewTabs();
}
CTTabStop oTabStop = oTabs.addNewTab();
oTabStop.setVal(oSTTabJc);
oTabStop.setPos(oPos);
}
I'm creating a pdf with iText 5 and want to add a footer. I did everything like the book "iText in action" in Chapter 14 says.
There are no errors but the footer doesn't show up.
Can somebody tell me what I'm doing wrong?
My code:
public class PdfBuilder {
private Document document;
public void newDocument(String file) {
document = new Document(PageSize.A4);
writer = PdfWriter.getInstance(document, new FileOutputStream(file));
MyFooter footerEvent = new MyFooter();
writer.setPageEvent(footerEvent);
document.open();
...
document.close();
writer.flush();
writer.close();
}
class MyFooter extends PdfPageEventHelper {
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer(), (document.right() - document.left()) / 2
+ document.leftMargin(), document.top() + 10, 0);
}
private Phrase footer() {
Font ffont = new Font(Font.FontFamily.UNDEFINED, 5, Font.ITALIC);
Phrase p = new Phrase("this is a footer");
return p;
}
}
The problem you report can not be reproduced. I have taken your example and I create the TextFooter example with this event:
class MyFooter extends PdfPageEventHelper {
Font ffont = new Font(Font.FontFamily.UNDEFINED, 5, Font.ITALIC);
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
Phrase header = new Phrase("this is a header", ffont);
Phrase footer = new Phrase("this is a footer", ffont);
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
header,
(document.right() - document.left()) / 2 + document.leftMargin(),
document.top() + 10, 0);
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
footer,
(document.right() - document.left()) / 2 + document.leftMargin(),
document.bottom() - 10, 0);
}
}
Note that I improved the performance by creating the Font and Paragraph instance only once. I also introduced a footer and a header. You claimed you wanted to add a footer, but in reality you added a header.
The top() method gives you the top of the page, so maybe you meant to calculate the y position relative to the bottom() of the page.
There was also an error in your footer() method:
private Phrase footer() {
Font ffont = new Font(Font.FontFamily.UNDEFINED, 5, Font.ITALIC);
Phrase p = new Phrase("this is a footer");
return p;
}
You define a Font named ffont, but you don't use it. I think you meant to write:
private Phrase footer() {
Font ffont = new Font(Font.FontFamily.UNDEFINED, 5, Font.ITALIC);
Phrase p = new Phrase("this is a footer", ffont);
return p;
}
Now when we look at the resulting PDF, we clearly see the text that was added as a header and a footer to each page.
By using showTextAligned method of PdfContentByte We can add footer to our page. Instead of phrase we should pass footer content as string to showTextAligned method as one of the parameter. If you want to format your footer content do before passing it to the method. Below is the sample code.
PdfContentByte cb = writer.getDirectContent();
cb.showTextAligned(Element.ALIGN_CENTER, "this is a footer", (document.right() - document.left()) / 2 + document.leftMargin(), document.bottom() - 10, 0);
Hi When I am generating form using java with itext I want to add form number on top left of the document
above the header.Please let me know the ways to do it.
PdfPTable table = new PdfPTable(3); // 3 columns.
table.setWidthPercentage(100);
PdfPCell cell1 = new PdfPCell(new Paragraph("Cell 1"));
PdfPCell cell2 = new PdfPCell(new Paragraph("Cell 2"));
PdfPCell cell3 = new PdfPCell(new Paragraph("Cell 3"));
cell1.setBorder(0);
cell2.setBorder(0);
cell3.setBorder(0);
table.addCell(cell1);
table.addCell(cell2);
table.addCell(cell3);
How can I set the table alignment to start of the page margin.
Your question is very confusing. You say you are creating a form, but when you say form, you don't seem to be referring to an interactive form, but to an ordinary PDF containing a table.
You say you want to add a number above the header, but you are not telling us what you mean by header. You are assuming that the people reading your question can read your mind.
I guess you want to use a page event to add a String in the top left corner of each page. That would make your question almost a duplicate of itextsharp: How to generate a report with dynamic header in PDF using itextsharp?
You can create a subclass of PdfPageEventHelper like this:
public class Header extends PdfPageEventHelper {
protected Phrase header;
public void setHeader(Phrase header) {
this.header = header;
}
#Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, header, 36, 806, 0);
}
}
You can then use this Header class like this:
public void createPdf(String filename) throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
Header event = new Header();
writer.setPageEvent(event);
// step 3
document.open();
// step 4
List<Integer> factors;
for (int i = 2; i < 301; i++) {
factors = getFactors(i);
if (factors.size() == 1) {
document.add(new Paragraph("This is a prime number!"));
}
for (int factor : factors) {
document.add(new Paragraph("Factor: " + factor));
}
event.setHeader(new Phrase(String.format("THE FACTORS OF %s", i)));
document.newPage();
}
// step 5
document.close();
}
In your case, you wouldn't have:
event.setHeader(new Phrase(String.format("THE FACTORS OF %s", i)));
You'd have something like:
event.setHeader(new Phrase(number));
Where number is the number you want to add at the coordinate x = 36, y = 806.
I am having problem while merging documents of different width using iText.
Below is the code I'm using to merge.
public static void doMerge(List<InputStream> list, OutputStream outputStream) throws Exception {
Rectangle pagesize = new Rectangle(1700f, 20f);
com.itextpdf.text.Document document = new com.itextpdf.text.Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
document.setPageSize(pagesize);
com.itextpdf.text.pdf.PdfContentByte cb = writer.getDirectContent();
for (InputStream in : list){
PdfReader reader = new PdfReader(in);
for (int i = 1; i <= reader.getNumberOfPages(); i++){
document.newPage();
//import the page from source pdf
com.itextpdf.text.pdf.PdfImportedPage page = writer.getImportedPage(reader, i);
//calculate the y for merging it from top
float y = document.getPageSize().getHeight() - page.getHeight();
//add the page to the destination pdf
cb.addTemplate(page, 0, y);
}
reader.close();
in.close();
}
outputStream.flush();
document.close();
outputStream.close();
}
First page of pdf will be of 14 inch of width and 13 inch of height. All the other pages on document will be always smaller than it.
I want to merge all the documents altogether in a single document.
I don't know how to set a width and height of a single merged document.
I think Rectangle pagesize = new Rectangle(1700f, 20f); should do it but it's not working means if change it to Rectangle pagesize = new Rectangle(1700f, 200f);, document has no effect.
Please guide me further.
Using the PdfWriter class to merge documents goes against all the recommendations given in the official documentation, though there are unofficial examples that may have lured you into writing bad code. I hope that you understand that I find these bad examples even more annoying than you do.
Please take a look at Table 6.1 in chapter 6 of my book. It gives you an overview showing when to use which class. In this case, you should use PdfCopy:
String[] files = { MovieLinks1.RESULT, MovieHistory.RESULT };
// step 1
Document document = new Document();
// step 2
PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
PdfReader reader;
int n;
// loop over the documents you want to concatenate
for (int i = 0; i < files.length; i++) {
reader = new PdfReader(files[i]);
// loop over the pages in that document
n = reader.getNumberOfPages();
for (int page = 0; page < n; ) {
copy.addPage(copy.getImportedPage(reader, ++page));
}
copy.freeReader(reader);
reader.close();
}
// step 5
document.close();
If you are using a recent version of iText, you can even use the addDocument() method in which case you don't need to loop over all the pages. You also need to take special care if forms are involved. There are several examples demonstrating the new functionality (dating from after the book was written) in the Sandbox.
with the itext version 5.5 we can merge pdf more easly using the method PdfCopy.addDocument :
package tn.com.sf.za.rd.controller;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
public class ReportMerging {
public static void main(String[] args) throws DocumentException, IOException {
String DOC_ONE_PATH = "D:/s.zaghdoudi/tmp/one.pdf";
String DOC_TWO_PATH = "D:/s.zaghdoudi/tmp/two.pdf";
String DOC_THREE_PATH = "D:/s.zaghdoudi/tmp/three.pdf";
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(DOC_THREE_PATH));
document.open();
PdfReader readerOne = new PdfReader(DOC_ONE_PATH);
PdfReader readerTwo = new PdfReader(DOC_TWO_PATH);
copy.addDocument(readerOne);
copy.addDocument(readerTwo);
document.close();
}
}