Saturday, November 30, 2013

iTextSharp–Add header/footer to PDF

It’s a common requirement to have header/footer on PDF and it could be achieved using PageEvents in iTextSharp. It depends on the requirement, but in general header may contain:
  • Header Title
  • Header Subtitle
  • Logo
  • Page Number/Datetime
And footer may contain:
  • Page Number
  • Copyright information
Check out below function that creates sample PDF having five pages with header and footer:
private void CreatePDF()
{
    string fileName = string.Empty;

    DateTime fileCreationDatetime = DateTime.Now;

    fileName = string.Format("{0}.pdf", fileCreationDatetime.ToString(@"yyyyMMdd") + "_" + fileCreationDatetime.ToString(@"HHmmss"));

    string pdfPath = Server.MapPath(@"~\PDF\") +   fileName;

    using (FileStream msReport = new FileStream(pdfPath, FileMode.Create))
    {
        //step 1
        using (Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 140f, 10f))
        {
            try
            {
                // step 2
                PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, msReport);
                pdfWriter.PageEvent = new Common.ITextEvents();

                //open the stream 
                pdfDoc.Open();

                for (int i = 0; i < 5; i++)
                {
                    Paragraph para = new Paragraph("Hello world. Checking Header Footer", new Font(Font.FontFamily.HELVETICA, 22));

                    para.Alignment = Element.ALIGN_CENTER;

                    pdfDoc.Add(para);

                    pdfDoc.NewPage();
                }

                pdfDoc.Close();

            }
            catch (Exception ex)
            {
                //handle exception
            }

            finally
            {


            }

        }

    }
}
Below line assigns object of ItextEvent class that extends PdfPageEventHelper, which contains various methods as shown below that you can override to do various thing like add header/footer, watermark etc. In next post we’ll add watermark using similar class that extends PdfPageEventHelper.

pdfpageeventhelper

Check out the ITextEvents class that extends PdfPageEventHelper to add header/footer.

public class ITextEvents : PdfPageEventHelper
    {

        // This is the contentbyte object of the writer
        PdfContentByte cb;

        // we will put the final number of pages in a template
        PdfTemplate headerTemplate, footerTemplate;

        // this is the BaseFont we are going to use for the header / footer
        BaseFont bf = null;

        // This keeps track of the creation time
        DateTime PrintTime = DateTime.Now;


        #region Fields
        private string _header;
        #endregion

        #region Properties
        public string Header
        {
            get { return _header; }
            set { _header = value; }
        }
        #endregion


        public override void OnOpenDocument(PdfWriter writer, Document document)
        {
            try
            {
                PrintTime = DateTime.Now;
                bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                cb = writer.DirectContent;
                headerTemplate = cb.CreateTemplate(100, 100);
                footerTemplate = cb.CreateTemplate(50, 50);
            }
            catch (DocumentException de)
            {
                //handle exception here
            }
            catch (System.IO.IOException ioe)
            {
                //handle exception here
            }
        }

        public override void OnEndPage(iTextSharp.text.pdf.PdfWriter writer, iTextSharp.text.Document document)
        {
            base.OnEndPage(writer, document);

            iTextSharp.text.Font baseFontNormal = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 12f, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLACK);

            iTextSharp.text.Font baseFontBig = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 12f, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK);

            Phrase p1Header = new Phrase("Sample Header Here", baseFontNormal);

            //Create PdfTable object
            PdfPTable pdfTab = new PdfPTable(3);

            //We will have to create separate cells to include image logo and 2 separate strings
            //Row 1
            PdfPCell pdfCell1 = new PdfPCell();
            PdfPCell pdfCell2 = new PdfPCell(p1Header);
            PdfPCell pdfCell3 = new PdfPCell();
            String text = "Page " + writer.PageNumber + " of ";


            //Add paging to header
            {
                cb.BeginText();
                cb.SetFontAndSize(bf, 12);
                cb.SetTextMatrix(document.PageSize.GetRight(200), document.PageSize.GetTop(45));
                cb.ShowText(text);
                cb.EndText();
                float len = bf.GetWidthPoint(text, 12);
                //Adds "12" in Page 1 of 12
                cb.AddTemplate(headerTemplate, document.PageSize.GetRight(200) + len, document.PageSize.GetTop(45));
            }
            //Add paging to footer
            {
                cb.BeginText();
                cb.SetFontAndSize(bf, 12);
                cb.SetTextMatrix(document.PageSize.GetRight(180), document.PageSize.GetBottom(30));
                cb.ShowText(text);
                cb.EndText();
                float len = bf.GetWidthPoint(text, 12);
                cb.AddTemplate(footerTemplate, document.PageSize.GetRight(180) + len, document.PageSize.GetBottom(30));
            }
            //Row 2
            PdfPCell pdfCell4 = new PdfPCell(new Phrase("Sub Header Description", baseFontNormal));
            //Row 3


            PdfPCell pdfCell5 = new PdfPCell(new Phrase("Date:" + PrintTime.ToShortDateString(), baseFontBig));
            PdfPCell pdfCell6 = new PdfPCell();
            PdfPCell pdfCell7 = new PdfPCell(new Phrase("TIME:" + string.Format("{0:t}", DateTime.Now), baseFontBig));


            //set the alignment of all three cells and set border to 0
            pdfCell1.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell2.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell3.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell4.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell5.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell6.HorizontalAlignment = Element.ALIGN_CENTER;
            pdfCell7.HorizontalAlignment = Element.ALIGN_CENTER;


            pdfCell2.VerticalAlignment = Element.ALIGN_BOTTOM;
            pdfCell3.VerticalAlignment = Element.ALIGN_MIDDLE;
            pdfCell4.VerticalAlignment = Element.ALIGN_TOP;
            pdfCell5.VerticalAlignment = Element.ALIGN_MIDDLE;
            pdfCell6.VerticalAlignment = Element.ALIGN_MIDDLE;
            pdfCell7.VerticalAlignment = Element.ALIGN_MIDDLE;


            pdfCell4.Colspan = 3;



            pdfCell1.Border = 0;
            pdfCell2.Border = 0;
            pdfCell3.Border = 0;
            pdfCell4.Border = 0;
            pdfCell5.Border = 0;
            pdfCell6.Border = 0;
            pdfCell7.Border = 0;


            //add all three cells into PdfTable
            pdfTab.AddCell(pdfCell1);
            pdfTab.AddCell(pdfCell2);
            pdfTab.AddCell(pdfCell3);
            pdfTab.AddCell(pdfCell4);
            pdfTab.AddCell(pdfCell5);
            pdfTab.AddCell(pdfCell6);
            pdfTab.AddCell(pdfCell7);

            pdfTab.TotalWidth = document.PageSize.Width - 80f;
            pdfTab.WidthPercentage = 70;
            


            //call WriteSelectedRows of PdfTable. This writes rows from PdfWriter in PdfTable
            //first param is start row. -1 indicates there is no end row and all the rows to be included to write
            //Third and fourth param is x and y position to start writing
            pdfTab.WriteSelectedRows(0, -1, 40, document.PageSize.Height - 30, writer.DirectContent);
            
            //Move the pointer and draw line to separate header section from rest of page
            cb.MoveTo(40, document.PageSize.Height - 100);
            cb.LineTo(document.PageSize.Width - 40, document.PageSize.Height - 100);
            cb.Stroke();

            //Move the pointer and draw line to separate footer section from rest of page
            cb.MoveTo(40, document.PageSize.GetBottom(50));
            cb.LineTo(document.PageSize.Width - 40, document.PageSize.GetBottom(50));
            cb.Stroke();
        }

        public override void OnCloseDocument(PdfWriter writer, Document document)
        {
            base.OnCloseDocument(writer, document);

            headerTemplate.BeginText();
            headerTemplate.SetFontAndSize(bf, 12);
            headerTemplate.SetTextMatrix(0, 0);
            headerTemplate.ShowText((writer.PageNumber - 1).ToString());
            headerTemplate.EndText();

            footerTemplate.BeginText();
            footerTemplate.SetFontAndSize(bf, 12);
            footerTemplate.SetTextMatrix(0, 0);
            footerTemplate.ShowText((writer.PageNumber - 1).ToString());
            footerTemplate.EndText();


        }
    }

As you can see that above class has Header property that you might want to use if you want your header title to be assigned dynamic. Add as many properties as you want, to display dynamic values in your header/footer.

It will generate sample PDF that will look like below:

SamplePDF

I hope it helps!

26 comments:

Danish Merchant said...

how to get total number of pages dynamically on OnEndPage

Danish Merchant said...

how to get Total number of pages in pdf on OnEndPage dynamically

Nilesh Thakker said...

What do you want to do by having "Total no of pages" in OnEndPage?

It seems there's no way you can have count of total no of pages in OnEndPage event except knowing beforehand how many pages will be there. You can have it OnEndPage event by declaring global variable in PageEvent Class and assign it value from your code.

I hope it makes sense!

Manoj Verma said...

Thankx bro.Its really help me.

please continue blogging.

Joël-Marie KREILOS said...

Hi.
Thanks for your great post.
I'm new to iText and looked over the net quite a while before finding your post.

Just one question :
I've implemented your solution which woks fine, but added instead of a dummy Paragraph a big PDFPTable of Data, which is splitted on 5 pages

How can I set the position and size of the table to fit between the 2 horizontal separation lines of the header and the footer ?


Actually it looks like :

tableDatatableData HEADER tableData
tableDatatableDatatableDatatableData
__________________________________
tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
__________________________________
tableDatatableData FOOTER
tableDatatableDatatableDatatableData


Instead of

HEADER
________________________

tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
tableDatatableDatatableDatatableData
__________________________
FOOTER

Nilesh Thakker said...

@Joel

If you follow the article completely, you'll have the output as you want. Then just replace it with your data.

IWantToLearn said...

do you or anyone have a vb.net version of this? please I need it badly

Sesha Giri said...

the type or name space for common is missing

i have added like new system.config

new Common.ITextEvents();

Aman Thakur said...

@sesha giri: Common is another folder which author has created in his solution and added the Interface ITextEvents class inheriting the PdfPageEventHelper. You can either create a Folder in your solution and place the class there in that folder. OR you can create the class in your namespace only.....It's your choice....

@IWantToLearn: If you really want to learn, then at-least convert this code to VB.NET yourself. It's not a big deal. :P :)

Gourav Chowdhury said...

how to add different footer in last page of pdf...
All pages should have same footer only last page should have some other footer...
Or all pages should have same footer but last page should have no footer... how to achieve any one of these two..

Unknown said...

code converter
c# to VB
http://converter.telerik.com/

Deathly said...

THANKS!!!!! :D!

Kiran said...

How do I pass a value to the Header Property and use it as a dynamic header data

Nilesh Thakker said...

@Kiran

I hope you've gone through current article. If not, please go through it and refer below link:

http://nilthakkar.blogspot.in/2015/08/itextsharp-add-dynamic-header.html

I hope it helps!

Mani kandan said...

Server.MapPath(@"~\PDF\") + fileName;

In this line "Server" not exists in current context what can i do??

buyi wen said...
This comment has been removed by a blog administrator.
AdeleB said...

PDF to image SDK for .NET project - how to change pdf to jpeg image in c#.net

sabata.mereeotlhe said...

Brilliant stuff

Nilesh Thakker said...

Thanks @Sabata

Grant Mchingula said...
This comment has been removed by the author.
Grant Mchingula said...

Great work , Nilesh. THis has been helpful. How do you restrict the header to first page oly?

vijay said...

How to add the three column table in the bottom of the table with the page no in the middle of the cell and other custom footer text in other cells.

Zuhair Ali said...

I'm using ASP.NET Repeater and want to show the sub header description dynamically and the data of the repeater dynamically. How to do this?

Maruti Pathare said...

How to call methods of ITextEvents class?

Thakur said...

Than you so much it help me a lot

Tuna Flakes said...

When i run this code, there is an error.
Object reference not set to an instance.
The error points on cb and template.