Sample code · C#
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using SelectPdf.Universal; namespace SelectPdf.Samples.Pages { public class StyledTableOfContentsModel : PageModel { // The defaults reproduce the look of selectpdf.com: cream page, dark ink, amber page numbers, // a serif display face for the title and the top level, a sans face below it. public class LevelRow { public string Font { get; set; } public float Size { get; set; } public bool Bold { get; set; } public string Color { get; set; } public float Indent { get; set; } public float SpacingBefore { get; set; } } [BindProperty] public string TxtUrl { get; set; } = "https://selectpdf.com/"; [BindProperty] public string DdlMode { get; set; } = "GeneratePages"; [BindProperty] public string TxtHeadings { get; set; } = "h1, h2, h3"; [BindProperty] public bool ChkBookmarks { get; set; } = true; [BindProperty] public int TxtMargin { get; set; } = 0; // common to both modes [BindProperty] public string TxtTitle { get; set; } = "Contents"; [BindProperty] public string DdlLeader { get; set; } = "Dots"; [BindProperty] public string TxtLeaderColor { get; set; } = "#c7beb1"; [BindProperty] public float TxtLeaderGap { get; set; } = 6; [BindProperty] public string TxtPageNumberColor { get; set; } = "#d97706"; [BindProperty] public int TxtMaxLevel { get; set; } = 0; [BindProperty] public bool ChkNumberEntries { get; set; } = false; // the table written into the page [BindProperty] public string DdlPlacement { get; set; } = "Start"; [BindProperty] public string TxtPlaceholder { get; set; } = ""; [BindProperty] public bool ChkPageBreak { get; set; } = true; [BindProperty] public bool ChkDefaultCss { get; set; } = true; [BindProperty] public string TxtCss { get; set; } = DefaultCss; // the generated pages [BindProperty] public string DdlPosition { get; set; } = "Start"; [BindProperty] public string TxtPageBackColor { get; set; } = "#fff8ec"; [BindProperty] public string TxtTitleFont { get; set; } = "Liberation Serif"; [BindProperty] public float TxtTitleSize { get; set; } = 34; [BindProperty] public bool ChkTitleBold { get; set; } = true; [BindProperty] public string TxtTitleColor { get; set; } = "#1f140a"; [BindProperty] public string DdlTitleAlign { get; set; } = "Left"; [BindProperty] public float TxtTitleSpacingBefore { get; set; } = 64; [BindProperty] public float TxtTitleSpacingAfter { get; set; } = 22; [BindProperty] public string TxtNumberFont { get; set; } = "Liberation Sans"; [BindProperty] public float TxtNumberSize { get; set; } = 10; [BindProperty] public bool ChkNumberBold { get; set; } = true; [BindProperty] public float TxtNumberInset { get; set; } = 56; [BindProperty] public LevelRow[] Levels { get; set; } = { new LevelRow { Font = "Liberation Serif", Size = 16, Bold = true, Color = "#1f140a", Indent = 56, SpacingBefore = 14 }, new LevelRow { Font = "Liberation Sans", Size = 11, Bold = true, Color = "#1f140a", Indent = 72, SpacingBefore = 6 }, new LevelRow { Font = "Liberation Sans", Size = 10, Bold = false, Color = "#6b6257", Indent = 88, SpacingBefore = 3 }, }; public const string DefaultCss = "nav.selectpdf-toc { background: #fff8ec; color: #1f140a; font-family: Georgia, serif;\n" + " max-width: 860px; margin: 0 auto; padding: 72px 32px 40px; box-sizing: border-box; }\n" + "nav.selectpdf-toc .selectpdf-toc-title { font-size: 52px; font-weight: 600;\n" + " letter-spacing: -0.02em; line-height: 1.05; margin: 0 0 28px; padding-bottom: 20px;\n" + " border-bottom: 1px solid #c7beb1; }\n" + "nav.selectpdf-toc li { margin: 12px 0; font-size: 17px; font-family: Arial, sans-serif; }\n" + "nav.selectpdf-toc ol ol { padding-left: 22px; }\n" + "nav.selectpdf-toc li.selectpdf-toc-level-1 > a { font-family: Georgia, serif;\n" + " font-size: 24px; font-weight: 600; }\n" + "nav.selectpdf-toc li.selectpdf-toc-level-2 > a { font-weight: 600; }\n" + "nav.selectpdf-toc li.selectpdf-toc-level-3 > a { color: #6b6257; font-size: 15px; }"; public List<SelectListItem> Modes { get; } = new List<SelectListItem> { new SelectListItem { Value = "GeneratePages", Text = "Generate table of contents pages" }, new SelectListItem { Value = "InsertHtml", Text = "Write a table of contents into the page" }, }; public List<SelectListItem> Leaders { get; } = Items("Dots", "Dashes", "Line", "None"); public List<SelectListItem> Placements { get; } = Items("Start", "End", "Placeholder"); public List<SelectListItem> Positions { get; } = Items("Start", "AfterFirstPage", "End"); public List<SelectListItem> Aligns { get; } = Items("Left", "Center", "Right"); public void OnGet() { } public IActionResult OnPost() { PdfTableOfContentsMode mode = SampleForm.ParseEnum(DdlMode, PdfTableOfContentsMode.GeneratePages); string[] headings = (TxtHeadings ?? "") .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()).Where(s => s.Length > 0).ToArray(); // instantiate a html to pdf converter object HtmlToPdf converter = new HtmlToPdf(); converter.Options.NavigationTimeout = Startup.NavigationTimeout; converter.Options.MarginTop = TxtMargin; converter.Options.MarginRight = TxtMargin; converter.Options.MarginBottom = TxtMargin; converter.Options.MarginLeft = TxtMargin; // bookmarks for the same headings, nested by level, shown when the document is opened if (ChkBookmarks) { converter.Options.PdfBookmarkOptions.CssSelectors = headings; converter.Options.PdfBookmarkOptions.HierarchicalBookmarks = true; converter.Options.ViewerPreferences.PageMode = PdfViewerPageMode.UseOutlines; } // the table of contents: one entry per heading the selectors match PdfTableOfContentsOptions toc = converter.Options.TableOfContents; toc.Mode = mode; toc.HeadingSelectors = headings; toc.Title = string.IsNullOrWhiteSpace(TxtTitle) ? null : TxtTitle; toc.Leader = SampleForm.ParseEnum(DdlLeader, PdfTableOfContentsLeader.Dots); toc.LeaderColor = Color(TxtLeaderColor); toc.LeaderGap = TxtLeaderGap; toc.PageNumberColor = Color(TxtPageNumberColor); toc.MaxLevel = TxtMaxLevel; toc.NumberEntries = ChkNumberEntries; if (mode == PdfTableOfContentsMode.InsertHtml) { // the table is written into the page as html and styled with css toc.HtmlPlacement = SampleForm.ParseEnum(DdlPlacement, PdfTableOfContentsHtmlPlacement.Start); toc.PlaceholderSelector = TxtPlaceholder; toc.PageBreak = ChkPageBreak; toc.IncludeDefaultCss = ChkDefaultCss; converter.Options.CustomCSS = TxtCss; } else { // the table is drawn on pages of its own toc.PagePosition = SampleForm.ParseEnum(DdlPosition, PdfTableOfContentsPagePosition.Start); toc.PageBackColor = Color(TxtPageBackColor); toc.TitleFont = Font(TxtTitleFont, TxtTitleSize, ChkTitleBold); toc.TitleColor = Color(TxtTitleColor); toc.TitleAlign = SampleForm.ParseEnum(DdlTitleAlign, PdfTextHorizontalAlign.Left); toc.TitleSpacingBefore = TxtTitleSpacingBefore; toc.TitleSpacingAfter = TxtTitleSpacingAfter; toc.PageNumberFont = Font(TxtNumberFont, TxtNumberSize, ChkNumberBold); toc.PageNumberRightInset = TxtNumberInset; toc.LevelStyles = Levels.Select(level => new PdfTableOfContentsLevelStyle { Font = Font(level.Font, level.Size, level.Bold), Color = Color(level.Color), Indent = level.Indent, SpacingBefore = level.SpacingBefore, }).ToArray(); } // create a new pdf document converting an url PdfDocument doc = converter.ConvertUrl(TxtUrl); // save pdf document byte[] pdf = doc.Save(); // close pdf document doc.Close(); // return resulted pdf document FileResult fileResult = new FileContentResult(pdf, "application/pdf"); fileResult.FileDownloadName = "Document.pdf"; return fileResult; } // a font installed on the server (Liberation Sans, Serif and Mono are always available) private static PdfFont Font(string family, float size, bool bold) { return PdfFont.CreateFromSystemFont(family, size, bold ? PdfFontStyle.Bold : PdfFontStyle.Regular); } // "#rrggbb" from a color input private static PdfColor Color(string hex) { if (string.IsNullOrWhiteSpace(hex)) return PdfColor.Empty; hex = hex.Trim().TrimStart('#'); int rgb = int.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture); return new PdfColor((byte)(rgb >> 16), (byte)(rgb >> 8), (byte)rgb); } private static List<SelectListItem> Items(params string[] values) { return values.Select(v => new SelectListItem { Value = v, Text = v }).ToList(); } } }