View RSS Feed

richyrich

Using iTextSharp to generate PDF with Header and Footer

Rating: 9 votes, 4.44 average.
by on June 26th, 2010 at 07:03 AM (24926 Views)
This one had me struggling for a while, so I thought I'd post a blog about it to try and help others.

What I was trying to do was create a PDF including header and footer sections to print documents onto a headed paper style.

Using iTextSharp V5.0.2.0 DLL in the bin folder you can create PDFs on the fly. My previous blog explained how to generate a simple PDF. Next I wanted to generate something a bit more complicated.

It seems previous versions of iTextSharp used a different method for producing headers and footers, but the more recent releases use an event handler to allow you to manipulate the document during various stages of it's production.

The first thing to do is create a class that will provide the event handler methods. This inherits the PdfPageEventHelper class from iTextSharp, like so:-
Code:
using System;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace myApp.ns.pages
{
   public class pdfPage : iTextSharp.text.pdf.PdfPageEventHelper
   {
       //I create a font object to use within my footer
      protected Font footer
      {
          get
          {
               // create a basecolor to use for the footer font, if needed.
               BaseColor grey = new BaseColor(128, 128, 128);
               Font font = FontFactory.GetFont("Arial", 9, Font.Normal, grey);
               return font;
          }
      }
       //override the OnStartPage event handler to add our header
       public override void OnStartPage(PdfWriter writer, Document doc)
       {
            //I use a PdfPtable with 1 column to position my header where I want it
            PdfPTable headerTbl = new PdfPTable(1);

            //set the width of the table to be the same as the document
            headerTbl.TotalWidth = doc.PageSize.Width;

            //I use an image logo in the header so I need to get an instance of the image to be able to insert it. I believe this is something you couldn't do with older versions of iTextSharp
            Image logo = Image.GetInstance(HttpContext.Current.Server.MapPath("/images/logo.jpg"));

            //I used a large version of the logo to maintain the quality when the size was reduced. I guess you could reduce the size manually and use a smaller version, but I used iTextSharp to reduce the scale. As you can see, I reduced it down to 7% of original size.
            logo.ScalePercent(7);

            //create instance of a table cell to contain the logo
            PdfPCell cell = new PdfPCell(logo);

            //align the logo to the right of the cell
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;

            //add a bit of padding to bring it away from the right edge
            cell.PaddingRight = 20;

            //remove the border
            cell.border = 0;

            //Add the cell to the table
            headerTbl.AddCell(cell);

            //write the rows out to the PDF output stream. I use the height of the document to position the table. Positioning seems quite strange in iTextSharp and caused me the biggest headache.. It almost seems like it starts from the bottom of the page and works up to the top, so you may ned to play around with this.
            headerTbl.WriteSelectedRows(0,-1, 0, (doc.PageSize.Height-10), writer.DirectContent);
       }

       //override the OnPageEnd event handler to add our footer
       public override void OnEndPage(PdfWriter writer, Document doc)
       {
            //I use a PdfPtable with 2 columns to position my footer where I want it
            PdfPTable footerTbl = new PdfPTable(2);

            //set the width of the table to be the same as the document
            footerTbl.TotalWidth = doc.PageSize.Width;

            //Center the table on the page
            footerTbl.HorizontalAlignment = Element.ALIGN_CENTER;

            //Create a paragraph that contains the footer text
            Paragraph para = new Paragraph("Some footer text", footer);

            //add a carriage return
            para.Add(Environment.NewLine);
            para.Add("Some more footer text");

            //create a cell instance to hold the text
            PdfPCell cell = new PdfPCell(para);

            //set cell border to 0
            cell.Border = 0;

            //add some padding to bring away from the edge
            cell.PaddingLeft = 10;

            //add cell to table
            footerTbl.AddCell(cell);

            //create new instance of Paragraph for 2nd cell text
            para = new Paragraph("Some text for the second cell", footer);

           //create new instance of cell to hold the text
            cell = new PdfPCell(para);

            //align the text to the right of the cell
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            //set border to 0
            cell.Border = 0;

            // add some padding to take away from the edge of the page
            cell.PaddingRight = 10;

            //add the cell to the table
            footerTbl.AddCell(cell);

         //write the rows out to the PDF output stream.
         footerTbl.WriteSelectedRows(0,-1, 0, (doc.BottomMargin + 10),  writer.DirectContent);
       }
   }
}
Then, on your PDF page, you need to add your event handler to the PDF instance. This can be done like this-
Code:
using System;
using System.Web;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

using myApp.ns.pages;

    protected void Page_Load(object sender, EventArgs e)
    {
        //create an instance of a PDF document. You may need to play with the margins to ensure the "look" is right
        Document doc = new Document(PageSize.A4, 42, 53, 70, 46);

        //Change the content type to PDF
        HttpContext.Current.Response.ContentType = "application/pdf";

        //create an instance of your PDFpage class. This is the class we generated above.
        pdfPage page = new pdfPage();

        //create an instance of the PdfWriter and write to the Response.OutputStream. This will stream it directly to the browser
        PdfWriter pdfWriter = PdfWriter.GetInstance(doc, HttpContext.Current.Response.OutputStream);

        //set the PageEvent of the pdfWriter instance to the instance of our PDFPage class
        pdfWriter.PageEvent = page;

        //open the document
        doc.Open();

        //this is just some default text I used. a Paragraph instance is just repeated 100 times
        Paragraph para;
        for (int x = 1; x <= 100; x++)
        {
            para = new Paragraph("This is a paragraph");
            doc.Add(para);
        }

        //close the document
        doc.Close();
    }
That should be it! You will have your header and footer in the correct place on every page.

The things you'll have to play around with are the page margins to ensure they don't overlap the header or footer areas. Using the event handlers, our header and footer tables use absolute positioning to put them in the right place, so you may need to make some adjustments where necessary.

Hope that helps someone.

Submit "Using iTextSharp to generate PDF with Header and Footer" to Digg Submit "Using iTextSharp to generate PDF with Header and Footer" to del.icio.us Submit "Using iTextSharp to generate PDF with Header and Footer" to StumbleUpon Submit "Using iTextSharp to generate PDF with Header and Footer" to Google

Comments

Page 1 of 2 1 2 LastLast
  1. EKAREEM -
    EKAREEM's Avatar
    Hi
    Thanks for the good article.

    I tried it using VS2008 but I got a compilation error on the first code piece:

    Error: Method must return a type
    Raised for the method: OnPageEnd
    Could you please help?
    Thanks.
    EK
    • |
    • permalink
  2. EKAREEM -
    EKAREEM's Avatar
    Hi,
    In fact it would be nice if I could download you code and try with it.

    Thanks.
    EK
    • |
    • permalink
  3. richyrich -
    richyrich's Avatar
    Hi

    Really sorry about that. The declaration of the method should be:-
    Code:
    public override void OnStartPage(PdfWriter writer, Document doc)
    
    I have amended the original code to show this.

    I will see about uploading a zip with the file contents.

    If this doesn't solve your issue, please post back.

    Thanks for pointing out the problem..
    • |
    • permalink
  4. AndreH -
    AndreH's Avatar
    Hi

    Thanks for this post. It really helps!

    Just two things I noticed...
    1. The OnPageEnd() should be OnEndPage() : iTextSharp.dll version 5.0.4.0
    2. para.add() takes only one parameter.
    I.e. not para.Add("Some more footer text", footer);
    but para.Add("Some more footer text"); ?

    Thanks!
    AH
    • |
    • permalink
  5. richyrich -
    richyrich's Avatar
    Thanks for pointing that out. I have amended the code to show.

    That'll teach me to adapt my own code into a "simpler" example for posting without testing it fully. Also had problems copying and pasting which meant I had to type the code in...Not that I'm making excuses...
    • |
    • permalink
  6. newera -
    newera's Avatar
    Hi
    Thanks for this valuable code because I am using it in one of my projects. However I am having an issue. I am using this code for some invoices I am printing. However when the invoice has a lot of products the products are overlapping the footer and I need to find a way that this does not happen. Actually I solved it but it's not the way I would like.

    What I am currently doing is that I gave an option to the user that if the items overlap the footer he basically selects an option to print the footer content in a table which is printed after the last invoice item and not in the page footer.

    Thanks
    • |
    • permalink
  7. richyrich -
    richyrich's Avatar
    Quote Originally Posted by newera
    Hi
    Thanks for this valuable code because I am using it in one of my projects. However I am having an issue. I am using this code for some invoices I am printing. However when the invoice has a lot of products the products are overlapping the footer and I need to find a way that this does not happen. Actually I solved it but it's not the way I would like.

    What I am currently doing is that I gave an option to the user that if the items overlap the footer he basically selects an option to print the footer content in a table which is printed after the last invoice item and not in the page footer.

    Thanks
    Hi

    In this case, I would probably play around with the bottom margin of the page, to ensure the footer isn't written over. I think if you play around with the document declaration, I think that should do it.
    Code:
    Document doc = new Document(PageSize.A4, 42, 53, 70, 46);
    
    The last parameter is the bottom margin. It goes page size, left margin, right margin, top margin and bottom margin.

    Let me know if this doesn't work and I'll have a look at an example.

    Hope that helps.
    • |
    • permalink
  8. newera -
    newera's Avatar
    The thing is that if you change the document declaration the footer also moves up. So the footer is relative to the page size so if you decrease the page size the footer is also affected.
    • |
    • permalink
  9. richyrich -
    richyrich's Avatar
    Quote Originally Posted by newera
    The thing is that if you change the document declaration the footer also moves up. So the footer is relative to the page size so if you decrease the page size the footer is also affected.
    I believe you can then alter the position of the footer by adjusting this line:-
    Code:
    footerTbl.WriteSelectedRows(0,-1, 0, (doc.BottomMargin + 10),  writer.DirectContent);
    
    I'm afraid it's been a while since I did anything with iTextSharp. I think it should be possible to adjust the positioning and margins so that your page data doesn't over write your footer.

    I seem to remember it was a bit of a fiddle and a fair amount of trial and error to get it right. I think I mentioned in one of my iTextSharp blogs that I never quite got my head round how the positioning of it worked...

    The footer and header seem to use absolute positioning, so they will appear where ever you tell them to on the page. The footer uses the document bottom margin to position it on the page, so if you make a change to the bottom margin, I guess you'd also have to adjust the positioning of the footer.

    Hope that helps.
    • |
    • permalink
  10. newera -
    newera's Avatar
    I solved the thing. Thanks for your help. It actually needs a lot of trial and error and you need to have some test data to work with but it seems ok now.

    I now had to modify the margin and the bottom margin and it worked. Actually it was much better the way it worked before version 5.0 where there was a property called HeaderFooter.

    Thanks again for your input.
    • |
    • permalink
  11. richyrich -
    richyrich's Avatar
    Quote Originally Posted by newera
    I solved the thing. Thanks for your help. It actually needs a lot of trial and error and you need to have some test data to work with but it seems ok now.

    I now had to modify the margin and the bottom margin and it worked. Actually it was much better the way it worked before version 5.0 where there was a property called HeaderFooter.

    Thanks again for your input.
    No problem. Glad you got it working.

    Yes, it does take a lot of trial and error to get it right. I think in my original blog I just did a loop that repeated the same text 200 odd times so it goes on to 2 pages.
    • |
    • permalink
  12. naturecallings -
    naturecallings's Avatar
    This works like a charm, and this the the alternate for all those who are using newer version i.e. +5.0.0.0
    header and footer support is removed from the latest versions.
    So this have helped me and I recommend to use this further...
    Moreover I have been succeed to add Image in Header of the PDF page, So if required I can post it here.
    Thanks you and keep up the good work!!
    Updated February 9th, 2011 at 06:02 AM by naturecallings (Forgot to thanks the author!!)
    • |
    • permalink
  13. Mark Khor -
    Mark Khor's Avatar
    can you please point out how to show different header and footer on 1st page? I've been seeking about it but non of the resolution solve the issue due to many version of iTextSharp released.

    Thanks in advance

    Mark Khor
    Updated March 22nd, 2011 at 07:16 AM by richyrich (Removed link)
    • |
    • permalink
  14. richyrich -
    richyrich's Avatar
    Quote Originally Posted by Mark Khor
    can you please point out how to show different header and footer on 1st page? I've been seeking about it but non of the resolution solve the issue due to many version of iTextSharp released.

    Thanks in advance

    Mark Khor
    I've not tried anything like this, but I would have thought using a conditional inside the OnStartPage and OnEndPage handlers like this should work:-
    Code:
           public override void OnStartPage(PdfWriter writer, Document doc)
           {
                if(doc.PageNumber==1)
                {
                   // this is the first page so show a different header
                }else{
                  // this is not the first page so show the normal header
                }
           }
           public override void OnEndPage(PdfWriter writer, Document doc)
           {
                if(doc.PageNumber==1)
                {
                   // this is the first page so show a different footer
                }else{
                  // this is not the first page so show the normal footer
                }
           }
    
    Hope that helps.
    Updated June 6th, 2011 at 08:25 AM by richyrich
    • |
    • permalink
  15. kinggopal -
    kinggopal's Avatar
    Dear Friends,

    I would like to Thank Richyrich for the code. It worked fine for me. However, I have 1 issue. I am inserting a image in the header. As I populate the data by adding the tables to pdf file, when it come to next page, the tables' contents are overlapping the Header image.

    I kindly request you to hep to resolve this issue.
    • |
    • permalink
  16. richyrich -
    richyrich's Avatar
    Quote Originally Posted by kinggopal
    Dear Friends,

    I would like to Thank Richyrich for the code. It worked fine for me. However, I have 1 issue. I am inserting a image in the header. As I populate the data by adding the tables to pdf file, when it come to next page, the tables' contents are overlapping the Header image.

    I kindly request you to hep to resolve this issue.
    You will need to adjust the document top margin and header position to ensure it doesn't get overwritten. If you see my comment replies here and here this explains how to adjust the footer for a similar scenario. You will just need to alter the top margin and the header section instead.

    Hope that helps. If not, please post back.
    • |
    • permalink
  17. kinggopal -
    kinggopal's Avatar
    Quote Originally Posted by richyrich
    You will need to adjust the document top margin and header position to ensure it doesn't get overwritten. If you see my comment replies here and here this explains how to adjust the footer for a similar scenario. You will just need to alter the top margin and the header section instead.

    Hope that helps. If not, please post back.
    I m not using absolute positioning in my code. I used
    Document doc= new Document(PageSize.A4).
    • |
    • permalink
  18. richyrich -
    richyrich's Avatar
    OK. You will need to declare the Document with this overloaded constructor:-
    Code:
    Document doc = new Document(PageSize.A4, 42, 53, 70, 46);
    
    You will need to adjust the four end figures based on your own document and header image. Those are just an example.

    This allows you to set the top margin value which is where the header will go. Basically, you set the margins of the document (telling it where your main text will sit) and then your header (if required) and footer (if required) are positioned to sit inside these margins.

    It takes a fair amount of trial and error to get it to sit right.
    Updated July 27th, 2011 at 10:18 AM by richyrich
    • |
    • permalink
  19. kinggopal -
    kinggopal's Avatar
    Quote Originally Posted by richyrich
    OK. You will need to declare the Document with this overloaded constructor:-
    Code:
    Document doc = new Document(PageSize.A4, 42, 53, 70, 46);
    
    You will need to adjust the four end figures based on your own document and header image. Those are just an example.

    This allows you to set the top margin value which is where the header will go. Basically, you set the margins of the document (telling it where your main text will sit) and then your header (if required) and footer (if required) are positioned to sit inside these margins.
    Can u share me ur gtalk ID?
    • |
    • permalink
  20. richyrich -
    richyrich's Avatar
    Quote Originally Posted by kinggopal
    Can u share me ur gtalk ID?
    No I can't I'm afraid. Sorry. We all provide help in our spare time and so I wouldn't want to give out personal details.

    Which bit are you unsure about? Feel free to post a thread on our forum if you want more detailed help.
    • |
    • permalink
Page 1 of 2 1 2 LastLast

SEO by vBSEO