EVO HTML to PDF Converter can be configured to automatically create a table of contents in a PDF document based on H1 to H6 heading tags found in HTML document by simply turning on the PdfDocumentOptionsGenerateTableOfContents option. An object of the PdfDocumentOptions type is exposed by the HtmlToPdfConverterPdfDocumentOptions property. The code below can be used to enable the table of contents generation in the PDF document.
// Create a HTML to PDF converter object with default settings
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();
// Enable or disable the automatic creation of a table of contents in the PDF document based on H1 to H6 HTML tags
htmlToPdfConverter.PdfDocumentOptions.GenerateTableOfContents = true;In the custom mode, you can also mark arbitrary HTML elements as table of contents entries using the data-heading attribute, as described in the section below.
The table of contents container is the equivalent of a block element with the ID 'html-to-pdf-toc'. Inside this block element there is another block element that contains the title followed by an unordered list of table entries, similar to an unordered list element from HTML. Each entry in the table of contents, corresponding to a heading tag from HTML, has a text, a level which determines the entry appearance in table and a target PDF page number. The table of contents style can be controlled by a CSS stylesheet which reflects the internal structure described in this section.
Besides the standard H1 to H6 heading tags, any HTML element can be turned into a table of contents entry by setting the data-heading attribute to a level from 1 to 6, for example data-heading="2". The entry text is taken from the data-heading-text attribute when present, otherwise from the element text. A real heading can be excluded from the table of contents by setting data-heading="false". The custom data-heading attribute is honored only when the custom table of contents mode is used, that is when TableOfContentsOptionsUseBrowserMode is false (the inline table of contents is always created in custom mode).
The HTML below shows how to mark ordinary elements as table of contents entries together with the standard heading tags.
<!DOCTYPE html>
<html>
<head>
<title>Auto Create Table of Contents</title>
<link href="styles/webfonts.css" type="text/css" rel="stylesheet">
</head>
<body style="font-family: Verdana, sans-serif; font-size: 16px">
<br />
<br />
<h1>Contents</h1>
<a href="#Chapter1">Go To Chapter 1</a>
<br />
<a href="#Chapter2">Go To Chapter 2</a>
<br />
<a href="#Chapter3">Go To Chapter 3</a>
<br />
<a href="#CustomTocItems">Go To Custom TOC Items</a>
<br />
<!-- This DIV is the container for inline table of contents.
If it is not explicitly defined, a default one is created
before the HTML content of the converted page -->
<div id="html-to-pdf-toc"></div>
<h2 style="page-break-before: always" id="Chapter1">Chapter 1</h2>
This is the chapter 1 content.
<h2 style="page-break-before: always" id="Chapter2">Chapter 2</h2>
This is the chapter 2 content.
<h2 style="page-break-before: always" id="Chapter3">Chapter 3</h2>
This is the chapter 3 content.
<!-- Custom table of contents items created with the data-heading attribute.
Any element (not only H1-H6) becomes a table of contents entry when it has
a data-heading attribute with a valid level (1 to 6). -->
<h2 style="page-break-before: always" id="CustomTocItems">Custom Table of Contents Example</h2>
These table of contents entries are created from ordinary elements using the data-heading attribute.
<div data-heading="3">Custom TOC Item - Level 3</div>
This entry was added to the table of contents using a custom <div> element with data-heading="3".
<div data-heading="3" data-heading-text="Custom TOC Item With Explicit Title">This visible text is ignored for the table of contents</div>
This entry uses data-heading-text to set the table of contents title independently of the element text.
<h3 data-heading="false">Excluded Heading (data-heading="false")</h3>
This is a real H3 heading, but it is excluded from the table of contents because of data-heading="false".
<p><i>Note: The custom data-heading attribute is enabled only when the custom table of contents mode is used.</i></p>
</body>
</html>The table of contents properties are controlled by the PdfDocumentOptionsTableOfContents property which exposes an object of TableOfContentsOptions type. By setting this object's properties, you can control the table of contents style and the page numbering.
The table of contents title can be set using the TableOfContentsOptionsTitle property. The code below can be used to set the table of contents title.
// Set the table of contents title
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.Title = "Table of Contents";The table of contents style can be controlled using a standard CSS stylesheet defined in the TableOfContentsOptionsStyle property. You can control the global table of contents style, the title style, the style for each entry level and the page numbers style. There is a separate section dedicated to style customization.
The table of contents is normally created at the beginning of the PDF document, but there is also the possibility to generate the table of contents inline in any position within the converted HTML document by setting the TableOfContentsOptionsCreateInline property The code below can be used to create the table of contents inline.
// Set the table of contents title
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.CreateInline = true;The table of contents position in the converted HTML document is given by a DIV element with the ID 'html-to-pdf-toc', defined as below.
<div id="html-to-pdf-toc"></div>If there is no such DIV element defined in the converted HTML document, the converter will automatically create it at the top of the HTML content being converted.
The table of contents can display the target PDF page number at the right side of each table of contents entry.
Enable Page Numbers. Using the property TableOfContentsOptionsShowPageNumbers you can enable or disable the page numbers display in the table of contents. When the page numbers are disabled, you might also optionally need to adjust the table style to no longer show the dotted line between the table entry and the page number.
Page Numbers Offset. Another option to control the page numbering is to use the TableOfContentsOptionsPageNumbersOffset property to adjust the page numbering with a constant positive or negative integer. This property can be useful when merging a PDF containing a table of contents with other PDF documents similar to the 'Merge Multiple HTML to PDF' example from the demo application.
Count TOC and Start Pages. For non-inline table of contents you can also configure whether to include or exclude from the page numbering the PDF pages on which the table of contents is rendered, using the TableOfContentsOptionsCountTocAndStartPages property. This property also includes the PDF pages coming from the PDF documents added before the main HTML content using the PdfDocumentOptionsAddStartPdf(Byte) method of the converter. If you ignore the table of contents and start PDF pages, the page numbers in the table of contents will start from page 1, which refers to the next page after the table of contents. This property does not apply to inline table of contents.
For non-inline table of contents it is also possible to configure the creation mode to be custom or browser with TableOfContentsOptionsUseBrowserMode property.
Custom Mode. This is the default mode and the converter uses a custom algorithm to generate the table of contents entries.
Browser Mode. In this mode the table of contents is generated using the browser capabilities. To enable this mode you can use the code below.
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.UseBrowserMode = true;The table of contents style can be controlled using a standard CSS stylesheet set in the TableOfContentsOptionsStyle property. The converter initializes this property with a default style that you can overwrite with your own CSS stylesheet to control the global table of contents style, the title style, styles for each entry level and the page numbers style. The code below sets the Style property with a style similar to the default style used by converter.
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.Style = """
#html-to-pdf-toc {
font-family: Arial, sans-serif;
margin: 0px;
padding: 10px;
box-sizing: border-box;
background-color: #FFFFFF;
width: 100%;
position: relative;
display : block;
z-index: 100;
opacity: 1;
/* uncomment the lines below to force PDF page breaks before and after inline TOC */
/*page-break-after : always;
page-break-before : always;*/
/* uncomment the line below for RTL table of contents*/
/*direction : rtl;*/
}
/* TOC title style */
#html-to-pdf-toc .toc-title {
font-size: 22px;
font-weight: bold;
margin-bottom: 15px;
color: #444444;
text-align: center;
}
/* Common style for all TOC entries text */
#html-to-pdf-toc li .toc-link {
order: 1;
text-decoration: none;
color: inherit;
padding: 0px;
margin: 0px;
}
/* Level specific style for TOC entries text */
#html-to-pdf-toc li .toc-link-level-1 {
font-weight: bold;
font-size: 18px;
color: #111111;
}
#html-to-pdf-toc li .toc-link-level-2 {
font-weight: bold;
font-size: 16px;
color: #222222;
}
#html-to-pdf-toc li .toc-link-level-3 {
font-weight: bold;
font-size: 14px;
color: #333333;
}
#html-to-pdf-toc li .toc-link-level-4 {
font-weight: normal;
font-size: 12px;
color: #333333;
}
#html-to-pdf-toc li .toc-link-level-5 {
font-weight: normal;
font-size: 11px;
color: #333333;
font-style: italic;
}
#html-to-pdf-toc li .toc-link-level-6 {
font-weight: normal;
font-size: 10px;
color: #333333;
font-style: italic;
}
/* Common style for all page numbers */
#html-to-pdf-toc li .page-link {
order: 3;
font-family: Arial, sans-serif;
font-size: 16px;
font-weight: bold;
font-style: normal;
text-decoration: none;
padding: 0px;
margin: 0px;
color: #111111;
}
/* Style for space between entry text and page number */
#html-to-pdf-toc li::after {
flex-grow: 1;
order: 2;
content: "";
height: 1em;
/* comment the line below to remove the dotted line from TOC */
border-bottom: 2px dotted lightgray;
}
#html-to-pdf-toc ul {
list-style-type: none;
padding: 0px;
}
/* Common style for all TOC entries*/
#html-to-pdf-toc li {
font-size: 14px;
display: flex;
padding: 0px;
margin: 0px;
}
/* Level specific style for TOC entries */
#html-to-pdf-toc ul li.level-1 {
margin-bottom: 10px;
margin-inline-start: 0px;
}
#html-to-pdf-toc ul li.level-2 {
margin-bottom: 8px;
margin-inline-start: 20px;
}
#html-to-pdf-toc ul li.level-3 {
margin-bottom: 6px;
margin-inline-start: 40px;
}
#html-to-pdf-toc ul li.level-4 {
margin-bottom: 4px;
margin-inline-start: 60px;
}
#html-to-pdf-toc ul li.level-5 {
margin-bottom: 2px;
margin-inline-start: 80px;
}
#html-to-pdf-toc ul li.level-6 {
margin-bottom: 2px;
margin-inline-start: 100px;
}
""";The global table style is given by the '#html-to-pdf-toc' selector. You can configure the padding, the background color, the font family, text direction and other properties. For inline table of contents, you can force page breaks in PDF before and after the table of contents by uncommenting the 'page-break-after: always' and 'page-break-before: always' styles
The table of contents style is controlled by the '#html-to-pdf-toc .toc-title' selector.
The '#html-to-pdf-toc li' selector controls the common style of all entries in the table of contents. The style of the entries for various levels can be controlled by using the '#html-to-pdf-toc ul li.level-n' selectors, where n can be an integer from 1 to 6.
The common styles for all text in the table of contents are controlled by the '#html-to-pdf-toc li .toc-link' selector. The text style of the entries for various levels can be controlled by using the '#html-to-pdf-toc li .toc-link-level-n' selectors, where n can be an integer from 1 to 6.
The common style for all page numbers is controlled by the '#html-to-pdf-toc li .page-link' selector. To remove the dotted line between the table entry text and the page number, comment out the 'border-bottom: 2px dotted lightgray' style in '#html-to-pdf-toc li::after' selector.
using System;
using System.IO;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using EvoPdf_Next_AspNetDemo.Models;
using EvoPdf_Next_AspNetDemo.Models.HTML_to_PDF;
// Use EVO PDF Namespace
using EvoPdf.Next;
namespace EvoPdf_Next_AspNetDemo.Controllers.HTML_to_PDF
{
public class Table_of_ContentsController : Controller
{
private readonly IWebHostEnvironment m_hostingEnvironment;
public Table_of_ContentsController(IWebHostEnvironment hostingEnvironment)
{
m_hostingEnvironment = hostingEnvironment;
}
public IActionResult Index()
{
var model = SetViewModel();
return View(model);
}
[HttpPost]
public ActionResult ConvertHtmlToPdf(Table_of_Contents_ViewModel model)
{
if (!ModelState.IsValid)
{
var errorMessage = ModelStateHelper.GetModelErrors(ModelState);
throw new ValidationException(errorMessage);
}
// Set license key received after purchase to use the converter in licensed mode
// Leave it not set to use the library in demo mode
Licensing.LicenseKey = "3FJDU0ZDU0NTQkddQ1NAQl1CQV1KSkpKU0M=";
// Create a HTML to PDF converter object with default settings
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();
// Enable or disable the automatic creation of a table of contents in the PDF document based on H1 to H6 HTML tags
htmlToPdfConverter.PdfDocumentOptions.GenerateTableOfContents = model.GenerateToc;
// Optionally set the table of contents to display inline within the 'html-to-pdf-toc' DIV
// By default, the table of contents is created at the start of the generated PDF document
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.CreateInline = model.InlineToc;
// Optionally enable the usage of browser capabilities when creating the table of contents
// This option is applicable only if the table of contents is not inline and it is false by default
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.UseBrowserMode = model.UseBrowserMode;
// Set if the page numbers from table of contents are displyed
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.ShowPageNumbers = model.ShowPageNumbers;
// Set if the TOC pages are included in the page numbers displayed in the TOC.
// This option is not applicable to the inline table of contents
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.CountTocAndStartPages = model.CountTocPages;
// Set an offset to be applied to all page numbers in the table of contents.
// It can be useful when merging a PDF with a table of contents with other PDF documents
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.PageNumbersOffset = model.PageNumbersOffset;
// Set the table of contents title
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.Title = model.TocTitle;
// Optionally set a custom CSS style for the table of contents
// A default style is applied by the library if this property is not set
htmlToPdfConverter.PdfDocumentOptions.TableOfContents.Style = model.TocStyleTextBox;
// Set HTML Viewer width in pixels which is the equivalent in converter of the browser window width
htmlToPdfConverter.HtmlViewerWidth = model.HtmlViewerWidth;
// Set the initial HTML viewer height in pixels
if (model.HtmlViewerHeight.HasValue)
htmlToPdfConverter.HtmlViewerHeight = model.HtmlViewerHeight.Value;
// Set the HTML content zoom percentage similar to zoom level in a browser
htmlToPdfConverter.HtmlViewerZoom = model.HtmlViewerZoom;
// Automatically resize the PDF page width to match the HtmlViewerWidth property
// The default value is true
htmlToPdfConverter.PdfDocumentOptions.AutoResizePdfPageWidth = model.AutoResizePdfPageWidth;
// Set the PDF page size, which can be a predefined size like A4 or a custom size in points
// The default is A4
// Important Note: The PDF page width is automatically determined from the HTML viewer width
// when the AutoResizePdfPageWidth property is true
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = SelectedPdfPageSize(model.PdfPageSize);
// Set the PDF page orientation to Portrait or Landscape. The default is Portrait
htmlToPdfConverter.PdfDocumentOptions.PdfPageOrientation = SelectedPdfPageOrientation(model.PdfPageOrientation);
// Set the PDF page margins in points. The default is 0
htmlToPdfConverter.PdfDocumentOptions.LeftMargin = model.LeftMargin;
htmlToPdfConverter.PdfDocumentOptions.RightMargin = model.RightMargin;
htmlToPdfConverter.PdfDocumentOptions.TopMargin = model.TopMargin;
htmlToPdfConverter.PdfDocumentOptions.BottomMargin = model.BottomMargin;
// Set the maximum time in seconds to wait for HTML page to be loaded
// Leave it not set for a default 120 seconds maximum wait time
htmlToPdfConverter.NavigationTimeout = model.NavigationTimeout;
// Set an additional delay in seconds to wait for JavaScript or AJAX calls after page load completed
// Set this property to 0 if you don't need to wait for such asynchronous operations to finish
if (model.ConversionDelay.HasValue)
htmlToPdfConverter.ConversionDelay = model.ConversionDelay.Value;
// The buffer to receive the generated PDF document
byte[] outPdfBuffer = null;
if (model.HtmlPageSource == "Url")
{
string url = model.Url;
// Convert the HTML page given by an URL to a PDF document in a memory buffer
outPdfBuffer = htmlToPdfConverter.ConvertUrl(url);
}
else
{
string htmlString = model.HtmlStringTextBox;
string baseUrl = model.BaseUrlTextBox;
// Convert a HTML string with a base URL to a PDF document in a memory buffer
outPdfBuffer = htmlToPdfConverter.ConvertHtml(htmlString, baseUrl);
}
// Send the PDF file to browser
FileResult fileResult = new FileContentResult(outPdfBuffer, "application/pdf");
fileResult.FileDownloadName = "Table_of_Contents.pdf";
return fileResult;
}
private PdfPageSize SelectedPdfPageSize(string selectedValue)
{
switch (selectedValue)
{
case "A0":
return PdfPageSize.A0;
case "A1":
return PdfPageSize.A1;
case "A10":
return PdfPageSize.A10;
case "A2":
return PdfPageSize.A2;
case "A3":
return PdfPageSize.A3;
case "A4":
return PdfPageSize.A4;
case "A5":
return PdfPageSize.A5;
case "A6":
return PdfPageSize.A6;
case "A7":
return PdfPageSize.A7;
case "A8":
return PdfPageSize.A8;
case "A9":
return PdfPageSize.A9;
case "ArchA":
return PdfPageSize.ArchA;
case "ArchB":
return PdfPageSize.ArchB;
case "ArchC":
return PdfPageSize.ArchC;
case "ArchD":
return PdfPageSize.ArchD;
case "ArchE":
return PdfPageSize.ArchE;
case "B0":
return PdfPageSize.B0;
case "B1":
return PdfPageSize.B1;
case "B2":
return PdfPageSize.B2;
case "B3":
return PdfPageSize.B3;
case "B4":
return PdfPageSize.B4;
case "B5":
return PdfPageSize.B5;
case "Flsa":
return PdfPageSize.Flsa;
case "HalfLetter":
return PdfPageSize.HalfLetter;
case "Ledger":
return PdfPageSize.Ledger;
case "Legal":
return PdfPageSize.Legal;
case "Letter":
return PdfPageSize.Letter;
case "Letter11x17":
return PdfPageSize.Letter11x17;
case "Note":
return PdfPageSize.Note;
default:
return PdfPageSize.A4;
}
}
private PdfPageOrientation SelectedPdfPageOrientation(string selectedValue)
{
return selectedValue == "Portrait" ? PdfPageOrientation.Portrait : PdfPageOrientation.Landscape;
}
private Table_of_Contents_ViewModel SetViewModel()
{
var model = new Table_of_Contents_ViewModel();
var contentRootPath = Path.Combine(m_hostingEnvironment.ContentRootPath, "wwwroot");
HttpRequest request = ControllerContext.HttpContext.Request;
UriBuilder uriBuilder = new UriBuilder();
uriBuilder.Scheme = request.Scheme;
uriBuilder.Host = request.Host.Host;
if (request.Host.Port != null)
uriBuilder.Port = (int)request.Host.Port;
uriBuilder.Path = request.PathBase.ToString() + request.Path.ToString();
uriBuilder.Query = request.QueryString.ToString();
string currentPageUrl = uriBuilder.Uri.AbsoluteUri;
string rootUrl = currentPageUrl.Substring(0, currentPageUrl.Length - "Table_of_Contents".Length);
model.HtmlStringTextBox = System.IO.File.ReadAllText(Path.Combine(contentRootPath, "DemoAppFiles/Input/HTML_Files/Table_of_Contents.html"));
model.TocStyleTextBox = System.IO.File.ReadAllText(Path.Combine(contentRootPath, "DemoAppFiles/Input/HTML_Files/TOC_Style.css"));
model.BaseUrlTextBox = rootUrl + "DemoAppFiles/Input/HTML_Files/";
return model;
}
}
}