65.9K
CodeProject is changing. Read more.
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5 votes)

Apr 24, 2015

CPOL
viewsIcon

33565

downloadIcon

866

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). 

Prepare Your HTML Content

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

<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:

using iTextSharp;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
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:

/// <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.

/// <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.

/// <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:

/// <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