The HiQPdf Chromium library offers extensive control over headers and footers. You can apply a header and a footer to a PDF document generated from multiple HTML documents. The header and footer HTML templates can contain any valid HTML markup, provided either as a string or via a URL. By using the template variables {page_number} and {total_pages}, you can include page numbering.
A key feature of the HTML to PDF Converter that enables adding an HTML header and footer to a PDF document generated from multiple HTML sources is delayed rendering. This can be enabled using the DelayContentRendering property. It allows the rendering of headers and footers to be postponed until after the individual PDF documents generated from multiple HTML sources are merged into a single document using an instance of the PdfMerge class.
The PdfMerge class provides methods to merge PDF documents from a memory buffer using the PdfMergeAddPdf(Byte, String) method, or from a file using the PdfMergeAddPdf(String, String) method. You can optionally specify a user or owner password if the added PDF document is password protected.
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using HiQPdf.Chromium;
namespace HiQPdf_Chromium_AspNetDemo.Controllers
{
public class PdfHeadersAndFooters_MergeHtmlController : Controller
{
private readonly IWebHostEnvironment m_hostingEnvironment;
public PdfHeadersAndFooters_MergeHtmlController(IWebHostEnvironment hostingEnvironment)
{
m_hostingEnvironment = hostingEnvironment;
}
public IActionResult Index()
{
SetCurrentViewData();
return View();
}
[HttpPost]
public ActionResult MergePdf(IFormCollection collection)
{
// Replace the demo serial number with the serial number received upon purchase
// to run the converter in licensed mode
Licensing.SerialNumber = "YCgJMTAE-BiwJAhIB-EhlWTlBA-UEBRQFBA-U1FOUVJO-WVlZWQ==";
// Create the first HTML to PDF converter instance
HtmlToPdf firstHtmlToPdfConverter = new HtmlToPdf();
// Delay header and footer rendering until the merged PDF is saved
firstHtmlToPdfConverter.Document.PdfHtmlHeader.DelayContentRendering = true;
firstHtmlToPdfConverter.Document.PdfHtmlFooter.DelayContentRendering = true;
// Set header and footer visibility for the first converter
SetHeaderFooterVisibility(firstHtmlToPdfConverter, 0, collection);
// Set common options for the first converter
SetHtmlToPdfConverterOptions(firstHtmlToPdfConverter, collection);
// Convert the first HTML to PDF
byte[] firstPdfBytes = firstHtmlToPdfConverter.ConvertUrlToMemory(collection["textBoxUrl1"]);
// Get header and footer size based on their rendered HTML content
System.Drawing.Size headerSize = firstHtmlToPdfConverter.Document.PdfHtmlHeader.DestinationSize;
System.Drawing.Size footerSize = firstHtmlToPdfConverter.Document.PdfHtmlFooter.DestinationSize;
// Create the PDF merger
PdfMerge pdfMerge = new PdfMerge();
// Set merge options including header and footer dimensions
SetPdfMergeOptions(pdfMerge, headerSize, footerSize, collection);
// Add the first PDF to the merger
int firstPdfPageCount = pdfMerge.AddPdf(firstPdfBytes);
// Prepare the list of additional URLs to convert and merge
List<string> urlsToConvert = new List<string>() {
collection["textBoxUrl2"]
};
foreach (string url in urlsToConvert)
{
// Create a new converter for each HTML source
HtmlToPdf htmlToPdfConverter = new HtmlToPdf();
// Delay header and footer rendering until merge is saved
htmlToPdfConverter.Document.PdfHtmlHeader.DelayContentRendering = true;
htmlToPdfConverter.Document.PdfHtmlFooter.DelayContentRendering = true;
// Calculate current page count to determine visibility logic
int totalPdfPageCount = pdfMerge.PdfMergeInfo.TotalPagesProduced;
// Set header and footer visibility based on current position
SetHeaderFooterVisibility(htmlToPdfConverter, totalPdfPageCount, collection);
// Apply general converter options
SetHtmlToPdfConverterOptions(htmlToPdfConverter, collection);
// Convert the HTML to PDF
byte[] pdfBytes = htmlToPdfConverter.ConvertUrlToMemory(url);
// Add the result to the merger
int pdfPageCount = pdfMerge.AddPdf(pdfBytes);
}
// Merge all PDFs into a single document, applying the header and footer
byte[] mergedPdf = pdfMerge.SaveToMemory();
// Send the resulting PDF to the browser
FileResult fileResult = new FileContentResult(mergedPdf, "application/pdf");
fileResult.FileDownloadName = "Header_Footer_on_PDF_from_Multiple_HTML.pdf";
return fileResult;
}
private void SetHeaderFooterVisibility(HtmlToPdf htmlToPdfConverter, int totalPagesBefore, IFormCollection collection)
{
// Set header visibility
SetHeaderFooterVisibility(htmlToPdfConverter, totalPagesBefore, true, collection);
// Set footer visibility
SetHeaderFooterVisibility(htmlToPdfConverter, totalPagesBefore, false, collection);
}
private void SetHeaderFooterVisibility(HtmlToPdf htmlToPdfConverter, int totalPagesBefore, bool isHeader, IFormCollection collection)
{
PdfHtmlHeaderFooter pdfHtmlTemplate = null;
bool showInFirstPage, showInEvenPages, showInOddPages;
if (isHeader)
{
pdfHtmlTemplate = htmlToPdfConverter.Document.PdfHtmlHeader;
showInFirstPage = collection["showHeaderInFirstPageCheckBox"].Count > 0;
showInOddPages = collection["showHeaderInOddPagesCheckBox"].Count > 0;
showInEvenPages = collection["showHeaderInEvenPagesCheckBox"].Count > 0;
}
else
{
pdfHtmlTemplate = htmlToPdfConverter.Document.PdfHtmlFooter;
showInFirstPage = collection["showFooterInFirstPageCheckBox"].Count > 0;
showInOddPages = collection["showFooterInOddPagesCheckBox"].Count > 0;
showInEvenPages = collection["showFooterInEvenPagesCheckBox"].Count > 0;
}
pdfHtmlTemplate.ShowInFirstPage = showInFirstPage;
pdfHtmlTemplate.ShowInEvenPages = showInEvenPages;
pdfHtmlTemplate.ShowInOddPages = showInOddPages;
if (totalPagesBefore > 0)
{
if (totalPagesBefore % 2 == 1)
{
// First page is even in whole document
pdfHtmlTemplate.ShowInFirstPage = showInEvenPages;
pdfHtmlTemplate.ShowInOddPages = showInEvenPages;
pdfHtmlTemplate.ShowInEvenPages = showInOddPages;
}
else
{
// First page is odd in whole document
pdfHtmlTemplate.ShowInFirstPage = showInOddPages;
pdfHtmlTemplate.ShowInOddPages = showInOddPages;
pdfHtmlTemplate.ShowInEvenPages = showInEvenPages;
}
}
}
private void SetHtmlToPdfConverterOptions(HtmlToPdf htmlToPdfConverter, IFormCollection collection)
{
bool headerEnabled = collection["headerEnabledCheckBox"].Count > 0;
if (headerEnabled)
{
// Set the header HTML from a URL or from an HTML string
bool headerHtmlFromUrl = collection["HeaderHtmlSource"] == "headerUrlRadioButton";
if (headerHtmlFromUrl)
{
string headerUrl = collection["headerUrlTextBox"];
htmlToPdfConverter.Document.PdfHtmlHeader.HtmlSourceUrl = headerUrl;
}
else
{
string headerHtml = collection["headerHtmlTextBox"];
string headerHtmlBaseUrl = collection["headerHtmlBaseUrlTextBox"];
htmlToPdfConverter.Document.PdfHtmlHeader.Html = headerHtml;
htmlToPdfConverter.Document.PdfHtmlHeader.HtmlBaseUrl = headerHtmlBaseUrl;
}
// Enable automatic height adjustment based on header HTML content
bool autoSizeHeaderContentHeight = collection["autoSizeHeaderContentHeightCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlHeader.AutoSizeContentHeight = autoSizeHeaderContentHeight;
// Set minimum and maximum content height when AutoSizeContentHeight is enabled
htmlToPdfConverter.Document.PdfHtmlHeader.MinContentHeight = int.Parse(collection["headerMinContentHeightTextBox"]);
htmlToPdfConverter.Document.PdfHtmlHeader.MaxContentHeight = int.Parse(collection["headerMaxContentHeightTextBox"]);
// Set a fixed header height when AutoResizeHeight is disabled
string headerHeightValueString = collection["headerHeightTextBox"];
if (!string.IsNullOrEmpty(headerHeightValueString))
{
int headerHeight = int.Parse(headerHeightValueString);
htmlToPdfConverter.Document.PdfHtmlHeader.Height = headerHeight;
}
// If AutoResizeHeight and FitHeight are enabled, the content may be scaled down to fit the specified height
bool fitHeaderHeight = collection["fitHeaderHeightCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlHeader.FitHeight = fitHeaderHeight;
// Automatically adjust the top page margin based on the header height
bool autoResizeTopMargin = collection["autoResizeTopMarginCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlHeader.AutoResizePdfMargins = autoResizeTopMargin;
// Reserve space for the header on all pages, regardless of visibility
// If false, print styles are used instead of screen styles
htmlToPdfConverter.Document.PdfHtmlHeader.ReserveSpaceAlways = collection["reserveHeaderSpaceCheckBox"].Count > 0;
// Optimize the header rendering time by providing a hint if the HTML template contains variables such as { page_number} or { total_pages}
htmlToPdfConverter.Document.PdfHtmlHeader.SkipVariablesParsing = collection["skipHeaderVariablesParsingCheckBox"].Count > 0;
// Optionally set additional time to wait for the asynchronous header HTML content before rendering
if (collection["headerWaitBeforeConvertTextBox"][0].Length > 0)
htmlToPdfConverter.Document.PdfHtmlHeader.WaitBeforeConvert = int.Parse(collection["headerWaitBeforeConvertTextBox"]);
}
bool footerEnabled = collection["footerEnabledCheckBox"].Count > 0;
if (footerEnabled)
{
// Set the footer HTML from a URL or from an HTML string
bool footerHtmlFromUrl = collection["FooterHtmlSource"] == "footerUrlRadioButton";
if (footerHtmlFromUrl)
{
string footerUrl = collection["footerUrlTextBox"];
htmlToPdfConverter.Document.PdfHtmlFooter.HtmlSourceUrl = footerUrl;
}
else
{
string footerHtml = collection["footerHtmlTextBox"];
string footerHtmlBaseUrl = collection["footerHtmlBaseUrlTextBox"];
htmlToPdfConverter.Document.PdfHtmlFooter.Html = footerHtml;
htmlToPdfConverter.Document.PdfHtmlFooter.HtmlBaseUrl = footerHtmlBaseUrl;
}
// Enable automatic height adjustment based on footer HTML content
bool autoSizeFooterContentHeight = collection["autoSizeHeaderContentHeightCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlFooter.AutoSizeContentHeight = autoSizeFooterContentHeight;
// Set minimum and maximum content height when AutoSizeContentHeight is enabled
htmlToPdfConverter.Document.PdfHtmlFooter.MinContentHeight = int.Parse(collection["footerMinContentHeightTextBox"]);
htmlToPdfConverter.Document.PdfHtmlFooter.MaxContentHeight = int.Parse(collection["footerMaxContentHeightTextBox"]);
// Set a fixed footer height when AutoResizeHeight is disabled
string footerHeightValueString = collection["footerHeightTextBox"];
if (!string.IsNullOrEmpty(footerHeightValueString))
{
int footerHeight = int.Parse(footerHeightValueString);
htmlToPdfConverter.Document.PdfHtmlFooter.Height = footerHeight;
}
// If AutoResizeHeight and FitHeight are enabled, the content may be scaled down to fit the specified height
bool fitFooterHeight = collection["fitFooterHeightCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlFooter.FitHeight = fitFooterHeight;
// Automatically adjust the bottom page margin based on the footer height
bool autoResizeBottomMargin = collection["autoResizeBottomMarginCheckBox"].Count > 0;
htmlToPdfConverter.Document.PdfHtmlFooter.AutoResizePdfMargins = autoResizeBottomMargin;
// Reserve space for the footer on all pages, regardless of visibility
// If false, print styles are used instead of screen styles
htmlToPdfConverter.Document.PdfHtmlFooter.ReserveSpaceAlways = collection["reserveFooterSpaceCheckBox"].Count > 0;
// Optimize the footer rendering time by providing a hint if the HTML template contains variables such as { page_number} or { total_pages}
htmlToPdfConverter.Document.PdfHtmlFooter.SkipVariablesParsing = collection["skipFooterVariablesParsingCheckBox"].Count > 0;
// Optionally set additional time to wait for the asynchronous footer HTML content before rendering
if (collection["footerWaitBeforeConvertTextBox"][0].Length > 0)
htmlToPdfConverter.Document.PdfHtmlFooter.WaitBeforeConvert = int.Parse(collection["footerWaitBeforeConvertTextBox"]);
}
}
private void SetPdfMergeOptions(PdfMerge pdfMerge, System.Drawing.Size headerSize, System.Drawing.Size footerSize, IFormCollection collection)
{
bool headerEnabled = collection["headerEnabledCheckBox"].Count > 0;
if (headerEnabled)
{
PdfHtmlTemplate pdfHeaderTemplate = null;
// Set the header HTML from a URL or from an HTML string
bool headerHtmlFromUrl = collection["HeaderHtmlSource"] == "headerUrlRadioButton";
if (headerHtmlFromUrl)
{
string headerUrl = collection["headerUrlTextBox"];
pdfHeaderTemplate = pdfMerge.AddHtmlTemplate(0, 0, headerSize.Width, headerSize.Height,
PdfTemplateHorizontalAlign.Left, PdfTemplateVerticalAlign.Top, headerUrl);
}
else
{
string headerHtml = collection["headerHtmlTextBox"];
string headerHtmlBaseUrl = collection["headerHtmlBaseUrlTextBox"];
pdfHeaderTemplate = pdfMerge.AddHtmlTemplate(0, 0, headerSize.Width, headerSize.Height,
PdfTemplateHorizontalAlign.Left, PdfTemplateVerticalAlign.Top, headerHtml, headerHtmlBaseUrl);
}
// Enable automatic height adjustment based on header HTML content
bool autoSizeHeaderContentHeight = collection["autoSizeHeaderContentHeightCheckBox"].Count > 0;
pdfHeaderTemplate.AutoSizeContentHeight = autoSizeHeaderContentHeight;
// Set minimum and maximum content height when AutoSizeContentHeight is enabled
pdfHeaderTemplate.MinContentHeight = int.Parse(collection["headerMinContentHeightTextBox"]);
pdfHeaderTemplate.MaxContentHeight = int.Parse(collection["headerMaxContentHeightTextBox"]);
// Set a fixed header height when AutoResizeHeight is disabled
string headerHeightValueString = collection["headerHeightTextBox"];
if (!string.IsNullOrEmpty(headerHeightValueString))
{
int headerHeight = int.Parse(headerHeightValueString);
pdfHeaderTemplate.Height = headerHeight;
}
// If AutoResizeHeight and FitHeight are enabled, the content may be scaled down to fit the specified height
bool fitHeaderHeight = collection["fitHeaderHeightCheckBox"].Count > 0;
pdfHeaderTemplate.FitHeight = fitHeaderHeight;
// Set header visibility on specific PDF pages: first page, odd-numbered pages and even-numbered pages
pdfHeaderTemplate.ShowInFirstPage = collection["showHeaderInFirstPageCheckBox"].Count > 0;
pdfHeaderTemplate.ShowInOddPages = collection["showHeaderInOddPagesCheckBox"].Count > 0;
pdfHeaderTemplate.ShowInEvenPages = collection["showHeaderInEvenPagesCheckBox"].Count > 0;
// Optimize the header rendering time by providing a hint if the HTML template contains variables such as { page_number} or { total_pages}
pdfHeaderTemplate.SkipVariablesParsing = collection["skipHeaderVariablesParsingCheckBox"].Count > 0;
// Optionally set additional time to wait for the asynchronous header HTML content before rendering
if (collection["headerWaitBeforeConvertTextBox"][0].Length > 0)
pdfHeaderTemplate.WaitBeforeConvert = int.Parse(collection["headerWaitBeforeConvertTextBox"]);
}
bool footerEnabled = collection["footerEnabledCheckBox"].Count > 0;
if (footerEnabled)
{
PdfHtmlTemplate pdfFooterTemplate = null;
// Set the footer HTML from a URL or from an HTML string
bool footerHtmlFromUrl = collection["FooterHtmlSource"] == "footerUrlRadioButton";
if (footerHtmlFromUrl)
{
string footerUrl = collection["footerUrlTextBox"];
pdfFooterTemplate = pdfMerge.AddHtmlTemplate(0, 0, footerSize.Width, footerSize.Height,
PdfTemplateHorizontalAlign.Left, PdfTemplateVerticalAlign.Bottom, footerUrl);
}
else
{
string footerHtml = collection["footerHtmlTextBox"];
string footerHtmlBaseUrl = collection["footerHtmlBaseUrlTextBox"];
pdfFooterTemplate = pdfMerge.AddHtmlTemplate(0, 0, footerSize.Width, footerSize.Height,
PdfTemplateHorizontalAlign.Left, PdfTemplateVerticalAlign.Bottom, footerHtml, footerHtmlBaseUrl);
}
// Enable automatic height adjustment based on footer HTML content
bool autoSizeFooterContentHeight = collection["autoSizeFooterContentHeightCheckBox"].Count > 0;
pdfFooterTemplate.AutoSizeContentHeight = autoSizeFooterContentHeight;
// Set minimum and maximum content height when AutoSizeContentHeight is enabled
pdfFooterTemplate.MinContentHeight = int.Parse(collection["footerMinContentHeightTextBox"]);
pdfFooterTemplate.MaxContentHeight = int.Parse(collection["footerMaxContentHeightTextBox"]);
// Set a fixed footer height when AutoResizeHeight is disabled
string footerHeightValueString = collection["footerHeightTextBox"];
if (!string.IsNullOrEmpty(footerHeightValueString))
{
int footerHeight = int.Parse(footerHeightValueString);
pdfFooterTemplate.Height = footerHeight;
}
// If AutoResizeHeight and FitHeight are enabled, the content may be scaled down to fit the specified height
bool fitFooterHeight = collection["fitFooterHeightCheckBox"].Count > 0;
pdfFooterTemplate.FitHeight = fitFooterHeight;
// Set footer visibility on specific PDF pages: first page, odd-numbered pages and even-numbered pages
pdfFooterTemplate.ShowInFirstPage = collection["showFooterInFirstPageCheckBox"].Count > 0;
pdfFooterTemplate.ShowInOddPages = collection["showFooterInOddPagesCheckBox"].Count > 0;
pdfFooterTemplate.ShowInEvenPages = collection["showFooterInEvenPagesCheckBox"].Count > 0;
// Optimize the footer rendering time by providing a hint if the HTML template contains variables such as { page_number} or { total_pages}
pdfFooterTemplate.SkipVariablesParsing = collection["skipFooterVariablesParsingCheckBox"].Count > 0;
// Optionally set additional time to wait for the asynchronous footer HTML content before rendering
if (collection["footerWaitBeforeConvertTextBox"][0].Length > 0)
pdfFooterTemplate.WaitBeforeConvert = int.Parse(collection["footerWaitBeforeConvertTextBox"]);
}
}
private void SetCurrentViewData()
{
ViewData["ContentRootPath"] = 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();
ViewData["CurrentPageUrl"] = uriBuilder.Uri.AbsoluteUri;
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>Header HTML with Page Numbers</title>
</head>
<body style="font-family: 'Times New Roman'; font-size: 16px">
<table style="width: 100%">
<tr>
<td style=" font-size:18px; font-weight: bold; color: navy">Header HTML with Page Numbers</td>
<td rowspan="2">
<a href="http://www.hiqpdf.com">
<img style="float: right; height: 50px" src="Images/HiQPdfLogo.jpg" />
</a>
</td>
<td rowspan="2" style="width: 5px"></td>
</tr>
<tr>
<td>
<span style="font-size: 16px">Page <span style="color:blue">{page_number}</span> of <span style="color:green">{total_pages}</span> pages</span>
</td>
</tr>
</table>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Footer HTML with Page Numbers</title>
</head>
<body style="font-family: 'Times New Roman'; font-size: 16px">
<table style="width: 100%">
<tr>
<td style=" font-size:18px; font-weight: bold; color: navy">Footer HTML with Page Numbers</td>
<td rowspan="2">
<a href="http://www.hiqpdf.com">
<img style="float: right; height: 50px" src="Images/HiQPdfLogo.jpg" />
</a>
</td>
<td rowspan="2" style="width: 5px"></td>
</tr>
<tr>
<td>
<span style="font-size: 16px">Page <span style="color:blue">{page_number}</span> of <span style="color:green">{total_pages}</span> pages</span>
</td>
</tr>
</table>
</body>
</html>