Search code examples
c#itext7pdfhtml

IText7 PDFHtml generator with header and footer for C#


I am trying to generating a PDF from predefined HTML content. I managed to generate the content, yet without the required HTML Header, HTML Footer, and Arabic language is not supported as well.

My requirements:

  1. Arabic language support.
  2. The ability to generate more than 10 pages.
  3. The footer may differ from one page to another.

  4. There is a web application that sends a request to a WCF service, and the service returns a byte array containing the PDF.

So, I have been searching for a couple of days for a good tool and I found SelectPdf, it is perfect except that it is NOT free, so the only solution is IText7 PDFHtml. The thing is this library has good documentation for JAVA, and I am really struggling in following the C# examples and converting from JAVA API to C# code. Anyone has done something similar before with c#?


Solution

  • After a long process of searching and trying, I have got it working and achieved the following features:

    1. Image in the header.

    2. Base64 image in the footer, in addition to the ability to write some text in the other side in the footer.

    3. Generating the same footer for all pages except for the last one.
    4. the number of the generated pages was unlimited.
    5. Page numbering.

    All the previous features were free of charge, however, supporting Arabic language needs a license, so I have to pay anyway :)

    Kindly find below my C# code and post your improvements if you have any.

    public class Pdfgenerator
    {
        public const string FONT = "Fonts/NotoNaskhArabic-Regular2.ttf";
        public static string HEADER_TEXT = "<table width=\"100%\" border=\"0\"><tr><td>Header</td><td align=\"right\">Some title</td></tr></table>";
        public static string FOOTER_TEXT = "<table width=\"100%\" border=\"0\"><tr><td>Footer</td><td align=\"right\">Some title</td></tr></table>";
        public MemoryStream createPdf()
        {
            string apPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
            MemoryStream file = new MemoryStream();
            PdfDocument pdfDocument = null;
            PdfDocument pdfDoc = null;
            PdfDocument pdfDocument1 = null;
            try
            {
    
                using (file)
                {
                    PdfFont f = PdfFontFactory.CreateFont(apPath + FONT, PdfEncodings.IDENTITY_H);
                    string header = "pdfHtml Header and footer example using page-events";
                    Header headerHandler = new Header(header);
                    Footer footerHandler = new Footer();
                    ConverterProperties converterProperties = new ConverterProperties();
                    PdfWriter writer1 = new PdfWriter(apPath + "test1.pdf");
                    pdfDocument1 = new PdfDocument(writer1);
                    pdfDocument1.AddEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
                    pdfDocument1.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
                    converterProperties = new ConverterProperties().SetBaseUri(apPath);
    
                    HtmlConverter.ConvertToDocument(File.ReadAllText(apPath + "content.html"), pdfDocument1, converterProperties);
                    footerHandler.lastPage = pdfDocument1.GetLastPage();
    
                    pdfDocument1.Close();
                }
            }
            catch (Exception ex)
            {
    
            }
            finally
            {
                file.Dispose();
            }
    
            return new MemoryStream();
        }
    }
    

    Generating the header:

    class Header : IEventHandler
    {
        private string header;
        private Image image;
        public Header(string header)
        {
            string apPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
            this.header = header;
            image = new Image(ImageDataFactory.Create(apPath + "Images/RANDOM_PHOTO.jpg"));
    
        }
    
        public void HandleEvent(Event @event)
        {
            PdfDocumentEvent docEvent = (PdfDocumentEvent)@event;
            PdfDocument pdf = docEvent.GetDocument();
            PdfPage page = docEvent.GetPage();
            Rectangle pageSize = page.GetPageSize();
    
            Canvas canvas = new Canvas(new PdfCanvas(page), pdf, pageSize);
            canvas.SetFontSize(18);
    
    
            // Write text at position
            canvas.Add(image);
            canvas.Close();
        }
    }
    

    Generating the footer:

    class Footer : IEventHandler
    {
        public PdfPage lastPage = null;
        protected PdfFormXObject placeholder;
        protected float side = 20;
        protected float x = 300;
        protected float y = 25;
        protected float space = 4.5f;
        protected float descent = 3;
    
        public Footer()
        {
            placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
        }
    
        public void HandleEvent(Event @event)
        {
            PdfDocumentEvent docEvent = (PdfDocumentEvent)@event;
            PdfDocument pdf = docEvent.GetDocument();
            PdfPage page = docEvent.GetPage();
            int pageNumber = pdf.GetPageNumber(page);
            Rectangle pageSize = page.GetPageSize();
            // Creates drawing canvas
            PdfCanvas pdfCanvas = new PdfCanvas(page);
            Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
    
            IList<iText.Layout.Element.IElement> elements = HtmlConverter.ConvertToElements("<table border=\"0\"><tr><td><img src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\" alt=\"Italian Trulli\"></td></tr></table>");
            Paragraph p = new Paragraph();
    
            foreach (iText.Layout.Element.IElement e in elements)
            {
                if (e is IBlockElement) {
                    p.Add((IBlockElement)e);
                }
            }
            if (lastPage == docEvent.GetPage()) {
    
            }
            else
            {
                canvas.ShowTextAligned(p, 25, 75, TextAlignment.LEFT);
            }
    
            canvas.Close();
    
            // Create placeholder object to write number of pages
            pdfCanvas.AddXObject(placeholder, x + space, y - descent);
            pdfCanvas.Release();
        }
    
        public void writeTotal(PdfDocument pdf)
        {
            Canvas canvas = new Canvas(placeholder, pdf);
            canvas.ShowTextAligned(pdf.GetNumberOfPages().ToString(),
                    0, descent, TextAlignment.LEFT);
            canvas.Close();
        }
    }
    

    I was trying to get a stream as an output, so if you want that as well you can use the following in your main service:

    public byte[] GetData()
        {
            MemoryStream stream = new Pdfgenerator().createPdf();
            byte[] arr = stream.ToArray();
            return stream.ToArray();
        }