Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Create PDF With Bookmark and TOC from HTML with iTextSharp-LGPL.4.1.6

0.00/5 (No votes)
24 Apr 2015 1  
How to export HTML to PDF with Bookmart and TOC using iTextSharp-LGPL.4.1.6

Introduction

This tip shows how to export HTML to PDF with Bookmark and TOC using iTextSharp. Technology includes ASP.NET MVC, iTextSharp 4.1.6 (LGPL/MPL). 

Image 1

Prepare Your HTML Content

Create new view has name PDFContent.cshtml with your content. Here is a sample:

HTML
<h2>Introduction</h2>
<p>This article shows how to create a load more button to your Kendo Grid 
without using default paging control. Technology includes ASP.NET MVC, 
jQuery and Kendo Grid Controls. I also used SQL Server Database Northwind for this sample.</p>
<br/>

<h2>Background</h2>
<p>With Kendo Grid you can&nbsp;easily configure the grid to display data and perform sorting, 
paging and grouping operations via its built-in settings. Now, I will show you how to add a 
load more button without using paging control. This article will apply for 
both server and client paging of Kendo Grid.</p>
<br />

<h2>Setting up Environment</h2>
<p>Please follow steps instruction 
<a href="http://docs.telerik.com/kendo-ui/aspnet-mvc/introduction">here 
</a>to setup environment.</p>

...

Using the Code

Step 1 - Add iTextSharp References and Create Your New Action for Controller

This action will export PDF on your Controller, as follows:

C#
using iTextSharp;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
C#
public ActionResult Index()
{
    string htmlContent = RenderRazorViewToString("~/Views/Shared/PDFContent.cshtml");

    return File(GenerateHtmlToPDFDocument(htmlContent), "application/pdf");
}
With the PDFContent.cshtml we've just created above.

Step 2 - Render Razor View to String

We need to create a function RenderRazorViewToString to get the content in PDFContent.cshtml, as follows:

C#
/// <summary>
/// Render View to String
/// </summary>
/// <param name="viewName"></param>
/// <returns></returns>
public string RenderRazorViewToString(string viewName)
{
    using (var sw = new StringWriter())
    {
        var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);
        return sw.GetStringBuilder().ToString();
    }
}

Step 3 - Create Bookmark From Your HTML Content

This function will split all H2 tags in your HTML content and create section for them.

C#
/// <summary>
/// Create chapter content from html
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public Chapter CreateChapterContent(string html)
{
    // Declare a font to used for the bookmarks
    iTextSharp.text.Font bookmarkFont = iTextSharp.text.FontFactory.GetFont
    (iTextSharp.text.FontFactory.HELVETICA, 16, iTextSharp.text.Font.NORMAL, new Color(255, 153, 0));

    Chapter chapter = new Chapter(new Paragraph(""), 0);
    chapter.NumberDepth = 0;

    // Create css for some tag
    StyleSheet styles = new StyleSheet();

    styles.LoadTagStyle("h2", HtmlTags.HORIZONTALALIGN, "center");
    styles.LoadTagStyle("h2", HtmlTags.COLOR, "#F90");
    styles.LoadTagStyle("pre", "size", "10pt");

    // Split H2 Html Tag
    string pattern = @"<\s*h2[^>]*>(.*?)<\s*/h2\s*>";
    string[] result = Regex.Split(html, pattern);

    // Create section title & content
    int sectionIndex = 0;
    foreach (var item in result)
    {
        if (string.IsNullOrEmpty(item)) continue;

        if (sectionIndex % 2 == 0)
        {
            chapter.AddSection(20f, new Paragraph(item, bookmarkFont), 0);
        }
        else
        {
            foreach (IElement element in HTMLWorker.ParseToList(new StringReader(item), styles))
            {
                chapter.Add(element);
            }
        }

        sectionIndex++;
    }

    chapter.BookmarkTitle = "Demo for Load More Button in Kendo UI Grid";
    return chapter;
}

Step 4 - Generate PDF Document

First, we need to generate chapter content from Step 3 to PDF Document.

C#
/// <summary>
/// Generate PDF from HTML
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public byte[] GenerateHtmlToPDFDocument(string html)
{
    MemoryStream workStream = new MemoryStream();
    Document pdfDoc = new Document(PageSize.A4);
    PdfWriter.GetInstance(pdfDoc, workStream).CloseStream = false;
    HTMLWorker parser = new HTMLWorker(pdfDoc);

    // Get chapter content
    Chapter chapter = CreateChapterContent(html);

    pdfDoc.Open();

    // Add chapter content to PDF
    pdfDoc.Add(chapter);

    pdfDoc.Close();

    byte[] byteInfo = workStream.ToArray();
    workStream.Write(byteInfo, 0, byteInfo.Length);
    workStream.Position = 0;

    // Generate TOC for existing content
    return GeneratePDFTOCContent(byteInfo, html);
}

And then, we will generate TOC for your PDF, as follows:

C#
/// <summary>
/// Generate PDF To Content
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public byte[] GeneratePDFTOCContent(byte[] content, string html)
{
    var reader = new PdfReader(content);
    StringBuilder sb = new StringBuilder();

    // Title of PDF
    sb.Append("<h2><strong style='text-align:center'>
    Demo for Load More Button in Kendo UI Grid</strong></h2><br>");

    // Begin to create TOC
    sb.Append("<table>");
    sb.Append(string.Format("<tr><td width='80%'><strong>
    {0}</strong></td><td align='right' width='10%'>
    <strong>{1}</strong></td></tr>", "Section", 
    "Page"));
    using (MemoryStream ms = new MemoryStream())
    {
        // XML document generated by iText 
        SimpleBookmark.ExportToXML(SimpleBookmark.GetBookmark(reader), ms, "UTF-8", false);

        // rewind to create xmlreader
        ms.Position = 0;
        using (XmlReader xr = XmlReader.Create(ms))
        {
            xr.MoveToContent();
            string page = null;
            string text = null;

            string format = @"<tr><td width='80%'>{0}</td>
            <td align='right' width='10%'>{1}</td></tr>";
                    
            // extract page number from 'Page' attribute 
            Regex re = new Regex(@"^\d+");
            while (xr.Read())
            {
                if (xr.NodeType == XmlNodeType.Element && 
                xr.Name == "Title" && xr.IsStartElement())
                {
                    page = re.Match(xr.GetAttribute("Page")).Captures[0].Value;
                    xr.Read();

                    if (xr.NodeType == XmlNodeType.Text)
                    {
                        text = xr.Value.Trim();
                        int pageSection = int.Parse(page) + 1;
                        sb.Append(String.Format(format, text, pageSection.ToString()));
                    }
                }
            }
        }
    }

    sb.Append("</table>");

    MemoryStream workStream = new MemoryStream();
    var document = new Document(reader.GetPageSizeWithRotation(1));
    var writer = PdfWriter.GetInstance(document, workStream);
    writer.CloseStream = false;

    document.Open();
    document.NewPage();

    // Add TOC
    StyleSheet styles = new StyleSheet();
    styles.LoadTagStyle("h2", HtmlTags.HORIZONTALALIGN, "center");
    styles.LoadTagStyle("h2", HtmlTags.COLOR, "#F90");

    foreach (IElement element in HTMLWorker.ParseToList(new StringReader(sb.ToString()), styles))
    {
        document.Add(element);
    }

    // Append your chapter content again
    Chapter chapter = CreateChapterContent(html);
    document.Add(chapter);

    document.Close();
    writer.Close();

    byte[] byteInfo = workStream.ToArray();
    workStream.Write(byteInfo, 0, byteInfo.Length);
    workStream.Position = 0;

    return byteInfo;
}

References

  1. iTextSharp - Links and Bookmarks
  2. Creating HTML Table of Contents from PDF Bookmarks
  3. Render a razor view to string
  4. Demo for Load More Button in Kendo UI Grid

History

  • 24th April, 2015 - Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here