Click here to Skip to main content
15,867,568 members
Articles / Web Development / HTML
Tip/Trick

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
24 Apr 2015CPOL 32.2K   856   8   3
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Success Software Services
Vietnam Vietnam
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionAwesome Pin
.dan.g.23-Jun-20 0:56
professional.dan.g.23-Jun-20 0:56 
Questionobsolete Pin
pixeltrace9-Sep-17 20:30
pixeltrace9-Sep-17 20:30 
GeneralLicense. Pin
Valery Possoz24-Apr-15 9:22
professionalValery Possoz24-Apr-15 9:22 
It's an interesting article and you rightfully mention iTextSharp-LGPL.4.1.6 in the title of your article. This is really important!

Be aware that since July 2009 iTextSharp uses the AGPL license. (version 5+)

If you were to use the technique described in this article and do not want to go open-source make sure to use version 4.1.6 and nothing else.
Also version 4 is not supported anymore and there are quite a few bugs in it.

Valery.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.