<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Florentin Badea</title>
    <description>The latest articles on DEV Community by Florentin Badea (@florentin_badea).</description>
    <link>https://dev.to/florentin_badea</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3948041%2Fb69049a6-b977-4157-9634-d3fab9658a92.jpg</url>
      <title>DEV Community: Florentin Badea</title>
      <link>https://dev.to/florentin_badea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/florentin_badea"/>
    <language>en</language>
    <item>
      <title>SelectPdf in 2026: A Cross-Platform .NET PDF Library for Windows, Linux and macOS</title>
      <dc:creator>Florentin Badea</dc:creator>
      <pubDate>Fri, 16 Oct 2026 08:01:57 +0000</pubDate>
      <link>https://dev.to/florentin_badea/selectpdf-in-2026-a-cross-platform-net-pdf-library-for-windows-linux-and-macos-4da0</link>
      <guid>https://dev.to/florentin_badea/selectpdf-in-2026-a-cross-platform-net-pdf-library-for-windows-linux-and-macos-4da0</guid>
      <description>&lt;p&gt;I'm the founder of SelectPdf. For most of its twelve years, our .NET PDF library ran on Windows only. If you needed HTML to PDF on Linux or macOS, we pointed you to our REST API. Articles written before October 2026 describe it that way, and for the library of that time they were right.&lt;/p&gt;

&lt;p&gt;In October 2026 that changed. Version 26.4 introduced SelectPdf.Universal, a new edition of the library that runs locally on Windows, Linux and macOS. Version 26.5, released ten days later, added a remote engine that also takes it to Alpine Linux and Kubernetes. This article walks through what the library looks like now, with code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it runs
&lt;/h2&gt;

&lt;p&gt;SelectPdf.Universal runs on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows x64 and x86&lt;/li&gt;
&lt;li&gt;Linux x64 and ARM64&lt;/li&gt;
&lt;li&gt;macOS on Apple Silicon&lt;/li&gt;
&lt;li&gt;Docker containers, and through the remote engine, Alpine Linux and Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It targets .NET 8, .NET 10 and .NET Standard 2.0, so it works on everything from .NET Framework 4.6.1 to the current .NET releases. We have verified it on Azure App Service, Azure Functions, AWS Lambda and Google Cloud Run.&lt;/p&gt;

&lt;p&gt;Installing takes one package for the platform you deploy to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package SelectPdf.Universal.Linux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The others are SelectPdf.Universal.Windows, SelectPdf.Universal.Linux.Arm64 and SelectPdf.Universal.MacOS. Each one installs the library together with the rendering engine for its platform. A build that targets several platforms references SelectPdf.Universal plus one &lt;code&gt;SelectPdf.Universal.Native.&amp;lt;rid&amp;gt;&lt;/code&gt; package per runtime instead.&lt;/p&gt;

&lt;p&gt;On Linux, the engine package brings the libraries Chromium needs, so a Docker image needs no apt-get step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:10.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-f&lt;/span&gt; net10.0 &lt;span class="nt"&gt;-o&lt;/span&gt; /out

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/runtime:10.0-noble&lt;/span&gt;
&lt;span class="c"&gt;# no apt-get: the Chromium closure ships in SelectPdf.Universal.Native.linux-x64&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /out ./&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "/app/PdfSample.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native packages need glibc 2.30 or later (Debian 11+, Ubuntu 20.04+, RHEL 9+). For musl-based images such as Alpine, there is the remote engine, below.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML to PDF
&lt;/h2&gt;

&lt;p&gt;The API is the one SelectPdf users already know, in a new namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// A4 portrait with 20 mm margins (margins are in points: 20 mm = 57 pt)&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Portrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;57&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;57&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;57&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;57&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// a web page, by URL&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webpage.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rendering engine is Chromium, so flexbox, grid, web fonts and current JavaScript render the way they do in the browser. There is one engine, so there is no engine to choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async, with cancellation
&lt;/h2&gt;

&lt;p&gt;The library has a Task-based API: &lt;code&gt;ConvertUrlAsync&lt;/code&gt; and &lt;code&gt;ConvertHtmlStringAsync&lt;/code&gt; on the HTML converter, async methods on the HTML to image converter, and &lt;code&gt;AddAsync&lt;/code&gt; for HTML placed into an existing document. Each takes a &lt;code&gt;CancellationToken&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// in a web app or service: await the conversion, and give up after 30 seconds&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrlAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// the PDF as bytes, for a response or a database&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Up to eight conversions run in parallel by default, and the rest queue in arrival order. Version 26.5 made parallel conversions much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  New in 26.4: beyond HTML to PDF
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Word to PDF.&lt;/strong&gt; docx, doc, rtf, txt, WordML, HTML and Markdown files convert directly, on every platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;WordToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WordToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageSetup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WordPageSetup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// each page keeps its Word size&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bookmarks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WordBookmarks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// the PDF outline comes from the headings&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.docx"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Redaction.&lt;/strong&gt; Text, images and form fields are removed from the file, not just covered. You can redact by area, by exact text or by regular expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text.RegularExpressions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;redactor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfRedactionManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"statement.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRedaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"\d{4}-\d{4}-\d{4}-\d{4}"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// card numbers&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OverlayText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"REDACTED"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Redact&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"statement-redacted.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;redactor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Signature validation&lt;/strong&gt;, with trust and revocation checks, next to signing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standards.&lt;/strong&gt; Accessible PDF/UA-1 and PDF/UA-2 output, on new, converted and loaded documents; PDF/A-4, 4e and 4f archiving; and ZUGFeRD / Factur-X electronic invoices. New documents are encrypted with AES-256 by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  New in 26.5: the remote engine
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw8swm3hzc8mfur4gjz1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw8swm3hzc8mfur4gjz1c.png" alt="SelectPdf 26.5 cover: C# code that sets RenderingEngine.ChromiumRemote, with tables of contents, fillable forms from HTML and hardware-key signing" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The library can hand its conversions to an engine running in a container on another machine. Set the rendering engine and point the library at the engine's address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// convert in the SelectPdf engine container instead of on this machine&lt;/span&gt;
&lt;span class="n"&gt;GlobalProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChromiumRemote&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;GlobalProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EngineEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://selectpdf-engine:8080"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTML to PDF, HTML to image, PDF to text and PDF to image then run in the engine container, and the application needs no native package at all. That is what brings SelectPdf to Alpine Linux and other musl-based systems. The engine image is published for linux/amd64 and linux/arm64 as &lt;code&gt;ghcr.io/selectpdf/engine&lt;/code&gt;, with a Helm chart, and the documentation has tested setups for Docker Compose, Kubernetes, Azure Container Apps, Amazon ECS and Google Cloud Run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also new in 26.5
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tables of contents with page numbers&lt;/strong&gt;, built while the HTML converts. The library can add leaders and page numbers to a table of contents the page already has, write one into the page from its headings, or insert separate table of contents pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableOfContents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTableOfContentsMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GeneratePages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TableOfContents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HeadingSelectors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"h1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"h2"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fillable PDF forms from HTML forms.&lt;/strong&gt; With &lt;code&gt;converter.Options.CreateFormFields = true&lt;/code&gt;, the text inputs, check boxes, radio buttons, drop-down lists and text areas of the page become PDF form fields, with their values, labels and options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing with keys the library never sees.&lt;/strong&gt; PKCS#11 tokens, smart cards and HSMs, the certificate store, or a remote signing service, with long-term validation (PAdES B-LT) and SHA-384 or SHA-512:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the key stays on the token; the library sends it the digest to sign&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfPkcs11Signer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"path/to/pkcs11-library"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"token label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"key label"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDigitalSignatureElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DigestAlgorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfSignatureDigest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SHA384&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableLtv&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// embed the revocation data (PAdES B-LT)&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signed.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;More archiving levels:&lt;/strong&gt; PDF/A-1a, PDF/A-2a and PDF/A-2u. &lt;strong&gt;Smaller files&lt;/strong&gt; from pages with large photos, and &lt;strong&gt;text search&lt;/strong&gt; in Chinese, Japanese, Korean, Hindi, Thai and Arabic.&lt;/p&gt;

&lt;h2&gt;
  
  
  For projects still on wkhtmltopdf
&lt;/h2&gt;

&lt;p&gt;wkhtmltopdf is no longer maintained. Four new open-source packages, SelectPdf.Compat.DinkToPdf and SelectPdf.Compat.WkHtmlToPdfDotNet, each with a .Licensed version, keep the API of the DinkToPdf and Haukcode.WkHtmlToPdfDotNet wrappers. Existing converter code builds as it is and renders with Chromium. They are MIT licensed, &lt;a href="https://github.com/selectpdf/selectpdf-compat-wkhtmltopdf" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The free Community Edition
&lt;/h2&gt;

&lt;p&gt;SelectPdf.HtmlToPdf.Universal is free, with no watermark, and converts HTML to PDF on the same platforms, up to 5 pages per document. It has the same one-package installs (SelectPdf.HtmlToPdf.Windows, .Linux, .Linux.Arm64 and .MacOS) and supports the remote engine. Your code can check whether the page limit cut a document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConversionResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageCountBeforeLimit&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConversionResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"the 5-page limit cut this document"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The classic library
&lt;/h2&gt;

&lt;p&gt;The classic SelectPdf library for Windows is still maintained and receives selected updates; it is version 26.5 too. It remains the choice for .NET Framework 2.0 and later, and for projects that use the WebKit or Blink engines.&lt;/p&gt;

&lt;p&gt;Moving an existing project to SelectPdf.Universal is mostly mechanical: new packages, a new namespace, and SelectPdf's own drawing types in place of System.Drawing. 82% of the classic library's public types and members carry over unchanged apart from the namespace, and the migration guide lists every change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing
&lt;/h2&gt;

&lt;p&gt;One perpetual license per developer, from $499, covers both SelectPdf.Universal and the classic Windows library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://selectpdf.com/pdf-library-cross-platform/" rel="noopener noreferrer"&gt;SelectPdf.Universal overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selectpdf.com/pdf-library/html/Release-Notes-v26-4.htm" rel="noopener noreferrer"&gt;Release notes 26.4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selectpdf.com/pdf-library/html/Release-Notes-v26-5.htm" rel="noopener noreferrer"&gt;Release notes 26.5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selectpdf.com/pdf-library/html/Remote-Engine.htm" rel="noopener noreferrer"&gt;Remote engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://selectpdf.com/how-to/" rel="noopener noreferrer"&gt;How-to guides&lt;/a&gt;, with complete C# programs compiled and run on Windows and Linux&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selectpdf.com/community-edition/" rel="noopener noreferrer"&gt;Community Edition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have a question about running SelectPdf on your platform, ask in the comments. I read them all.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>pdf</category>
      <category>docker</category>
    </item>
    <item>
      <title>HTML to PDF in a .NET Docker container, with no apt-get</title>
      <dc:creator>Florentin Badea</dc:creator>
      <pubDate>Mon, 05 Oct 2026 13:29:13 +0000</pubDate>
      <link>https://dev.to/florentin_badea/html-to-pdf-in-a-net-docker-container-with-no-apt-get-3fkb</link>
      <guid>https://dev.to/florentin_badea/html-to-pdf-in-a-net-docker-container-with-no-apt-get-3fkb</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I work on SelectPdf, the library used in this article. It's a commercial library with a free Community Edition; both are covered at the end.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've ever generated PDFs from HTML in a Linux container, you probably know the drill: a headless browser needs a long list of shared libraries, so the Dockerfile grows an &lt;code&gt;apt-get install&lt;/code&gt; line with twenty-odd packages, then fonts, then sometimes &lt;code&gt;--no-sandbox&lt;/code&gt; or a bigger &lt;code&gt;--shm-size&lt;/code&gt;. Every base-image update is a chance for that list to break.&lt;/p&gt;

&lt;p&gt;This article builds a small ASP.NET Core service that converts web pages and HTML to PDF in a stock .NET runtime container, with none of that. It uses &lt;strong&gt;SelectPdf.Universal&lt;/strong&gt;, which renders with Chromium and ships the engine, with everything it needs, inside a NuGet package.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;p&gt;A minimal API with two endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /pdf?url=…&lt;/code&gt; returns any web page as a PDF&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /pdf&lt;/code&gt; with an HTML body returns that HTML as a PDF&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. The project
&lt;/h2&gt;

&lt;p&gt;Create a web project and add two packages: the library, and the native engine for the platform the container runs on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new web &lt;span class="nt"&gt;-n&lt;/span&gt; PdfService
&lt;span class="nb"&gt;cd &lt;/span&gt;PdfService
dotnet add package SelectPdf.Universal
dotnet add package SelectPdf.Universal.Native.linux-x64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native package is the part that makes the container story simple: it carries the complete Chromium shared-library closure, including the modules Chromium loads at run time for HTTPS. &lt;code&gt;dotnet publish&lt;/code&gt; copies it into the output, so the image needs nothing else.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The code
&lt;/h2&gt;

&lt;p&gt;Replace &lt;code&gt;Program.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// GET /pdf?url=https://example.com  -&amp;gt;  the page as a PDF download&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrlAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"page.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// POST /pdf with an HTML body  -&amp;gt;  that HTML as a PDF&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StreamReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ReadToEndAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"document.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The async methods take a &lt;code&gt;CancellationToken&lt;/code&gt;, so a client that disconnects cancels its conversion. &lt;code&gt;doc.Save()&lt;/code&gt; with no arguments returns the PDF as a byte array; &lt;code&gt;doc.Save("file.pdf")&lt;/code&gt; writes it to disk instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Dockerfile
&lt;/h2&gt;

&lt;p&gt;A standard multi-stage build. Note what's &lt;strong&gt;not&lt;/strong&gt; in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:10.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish PdfService.csproj &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; /app

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:10.0&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app .&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; ASPNETCORE_URLS=http://+:8080&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; app&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "PdfService.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;apt-get&lt;/code&gt;, no fonts step, no Xvfb. The engine renders headless, so there's no display server. It also runs as the image's built-in non-root &lt;code&gt;app&lt;/code&gt; user: when the app is published on Linux, as it is inside this build, the native package makes the engine files readable and executable for every user.&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;.dockerignore&lt;/code&gt; so local build output stays out of the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/
obj/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Build and run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; pdfservice &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 pdfservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A plain &lt;code&gt;docker run&lt;/code&gt;: no &lt;code&gt;--no-sandbox&lt;/code&gt;, no added capabilities, no privileged mode, no GPU and no &lt;code&gt;--shm-size&lt;/code&gt;. Docker's default 64 MB of shared memory is enough.&lt;/p&gt;

&lt;p&gt;Try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; page.pdf &lt;span class="s2"&gt;"http://localhost:8080/pdf?url=https://example.com"&lt;/span&gt;

curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: text/html"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;h1&amp;gt;Hello from Docker&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-o&lt;/span&gt; hello.pdf http://localhost:8080/pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Fonts for every language
&lt;/h2&gt;

&lt;p&gt;Base images ship with no fonts at all. The library carries the Liberation fonts, so Latin, Greek and Cyrillic text renders correctly out of the box. For anything else (Chinese, Japanese, Korean, Arabic, Hebrew, Hindi, Thai and more, plus color emoji), add one package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package SelectPdf.Universal.Fonts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It copies the Noto fonts into your publish output at build time, so nothing gets installed in the image. With it referenced, this renders correctly in the same container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: text/html; charset=utf-8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p&amp;gt;中文 日本語 العربية 😀&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-o&lt;/span&gt; languages.pdf http://localhost:8080/pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. ARM64, and building on a Mac
&lt;/h2&gt;

&lt;p&gt;For ARM64 containers (AWS Graviton, Ampere, or Docker on an Apple Silicon Mac), reference &lt;code&gt;SelectPdf.Universal.Native.linux-arm64&lt;/code&gt; instead of &lt;code&gt;linux-x64&lt;/code&gt;. Nothing else changes: the &lt;code&gt;mcr.microsoft.com/dotnet&lt;/code&gt; tags are multi-architecture, so the same &lt;code&gt;FROM&lt;/code&gt; lines pick the right image.&lt;/p&gt;

&lt;p&gt;One thing that catches people on a Mac: Docker Desktop runs &lt;strong&gt;Linux&lt;/strong&gt; containers, so the image needs &lt;code&gt;linux-arm64&lt;/code&gt;, not &lt;code&gt;osx-arm64&lt;/code&gt;. The macOS package is for apps running natively on macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What works, and what doesn't
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Base images.&lt;/strong&gt; Any glibc-based .NET image. The engines need glibc 2.30 or newer, which covers Ubuntu 20.04+, Debian 11+ and RHEL 9+. Verified end to end, with a real HTTPS page and no packages installed: Debian 12, Ubuntu 22.04, Ubuntu 24.04, and Amazon Linux 2023 through a self-contained publish.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not supported: Alpine.&lt;/strong&gt; The native engines need glibc, and Alpine uses musl. Stay on the default Debian or Ubuntu based tags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources.&lt;/strong&gt; Chromium-based rendering likes CPU and memory. Plan for at least 1 core and 2 GB of RAM per container, and 2+ cores if you convert a lot under load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows containers&lt;/strong&gt; work too, on Windows Server Core, but they need a step to install the core Windows fonts. If Windows isn't a requirement, Linux containers are smaller and simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SelectPdf.Universal&lt;/strong&gt; is commercial. Without a license the output carries a trial watermark; with one, set &lt;code&gt;GlobalProperties.LicenseKey&lt;/code&gt; at startup. Licenses are perpetual and per developer, from $499, and one license covers both SelectPdf.Universal and the classic Windows library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SelectPdf.HtmlToPdf.Universal&lt;/strong&gt; is the free Community Edition: HTML to PDF only, free for commercial use, no watermark, up to 5 pages per document. The code in this article runs unchanged with it: reference &lt;code&gt;SelectPdf.HtmlToPdf.Universal&lt;/code&gt; instead of &lt;code&gt;SelectPdf.Universal&lt;/code&gt;, keep the same native package, and longer documents stop at five pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The whole container story comes down to two &lt;code&gt;dotnet add package&lt;/code&gt; lines and an ordinary Dockerfile. The documentation has more: a Docker deployment guide with Windows containers and batch jobs, and step-by-step pages for Azure Container Apps, AWS Lambda and Google Cloud Run.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-platform library: &lt;a href="https://selectpdf.com/pdf-library-cross-platform/" rel="noopener noreferrer"&gt;https://selectpdf.com/pdf-library-cross-platform/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Launch post (what's new in 26.4): &lt;a href="https://selectpdf.com/selectpdf-universal-our-new-flagship-net-pdf-library-on-linux-macos-and-docker/" rel="noopener noreferrer"&gt;https://selectpdf.com/selectpdf-universal-our-new-flagship-net-pdf-library-on-linux-macos-and-docker/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it and hit something this article doesn't cover, let me know in the comments.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>docker</category>
      <category>csharp</category>
      <category>pdf</category>
    </item>
    <item>
      <title>HTML to PDF in C#: The Complete Guide</title>
      <dc:creator>Florentin Badea</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:39:39 +0000</pubDate>
      <link>https://dev.to/florentin_badea/html-to-pdf-in-c-the-complete-guide-4b4p</link>
      <guid>https://dev.to/florentin_badea/html-to-pdf-in-c-the-complete-guide-4b4p</guid>
      <description>&lt;p&gt;This is a complete, hands-on guide to converting HTML to PDF in C# with the &lt;a href="https://selectpdf.com/pdf-library-for-net/" rel="noopener noreferrer"&gt;SelectPdf library for .NET&lt;/a&gt;. It works up from a three-line conversion to a production-ready workflow: every one of the 19 code steps is a full, compiling example taken straight from this project and rendered with the Chromium engine, so the code you copy is code that actually runs. Along the way you will build a real invoice from a data model, render complex CSS and paginating tables, control layout, handle dynamic and authenticated pages, secure and archive your output, integrate with ASP.NET Core, and finish with notes on running in production and troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Add the SelectPdf packages, then build and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Select.Pdf.NetCore
dotnet add package Select.Pdf.NetCore.Chromium.Windows
dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the project writes each result PDF to &lt;code&gt;output/&lt;/code&gt; and the preview images shown below into &lt;code&gt;images/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 1 - Getting started&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert an HTML string to PDF&lt;/li&gt;
&lt;li&gt;Convert a URL to PDF&lt;/li&gt;
&lt;li&gt;Convert a local HTML file to PDF&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 2 - Build a real document&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build an invoice from a template&lt;/li&gt;
&lt;li&gt;Render complex HTML that paginates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 3 - Control the page layout&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set page size, orientation and margins&lt;/li&gt;
&lt;li&gt;Add headers and footers with page numbers&lt;/li&gt;
&lt;li&gt;Use HTML for headers and footers&lt;/li&gt;
&lt;li&gt;Generate bookmarks from HTML headings&lt;/li&gt;
&lt;li&gt;Produce a single-page PDF&lt;/li&gt;
&lt;li&gt;Add a watermark to every page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 4 - Dynamic and remote content&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wait for JavaScript-rendered content&lt;/li&gt;
&lt;li&gt;Inject custom CSS and run a script&lt;/li&gt;
&lt;li&gt;Control the browser viewport width&lt;/li&gt;
&lt;li&gt;Send HTTP headers and cookies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 5 - Secure, archive, integrate&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the document properties&lt;/li&gt;
&lt;li&gt;Password-protect and restrict permissions&lt;/li&gt;
&lt;li&gt;Create an archivable PDF/A-3 document&lt;/li&gt;
&lt;li&gt;Generate a PDF in ASP.NET Core&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 6 - Run it in production&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Running in production&lt;/li&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;FAQ&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frequently asked questions&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 1 - Getting started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Convert an HTML string to PDF
&lt;/h3&gt;

&lt;p&gt;The simplest conversion: render a raw HTML string into a PDF document in a few lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create the HTML to PDF converter and select the Chromium (CEF) engine.&lt;/span&gt;
&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Convert a raw HTML string into a PDF document.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello, SelectPdf!&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;This PDF was generated from an HTML string in C#.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Save the document to disk, then release the native resources.&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flprgpwgvx9tycdh7m0j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flprgpwgvx9tycdh7m0j5.png" alt="Convert an HTML string to PDF" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convert a URL to PDF
&lt;/h3&gt;

&lt;p&gt;Point the converter at any public web address and capture the rendered page as a PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Convert a live web page to a PDF document.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9a9874y17oxw8h79wpj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9a9874y17oxw8h79wpj3.png" alt="Convert a URL to PDF" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Convert a local HTML file to PDF
&lt;/h3&gt;

&lt;p&gt;Render an HTML file from disk - together with its local CSS and images - into a PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ConvertUrl also accepts a local file path; relative CSS and images&lt;/span&gt;
&lt;span class="c1"&gt;// referenced by the file are resolved automatically.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnlgmgyffhjmv9qywtin4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnlgmgyffhjmv9qywtin4.png" alt="Convert a local HTML file to PDF" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2 - Build a real document
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4. Build an invoice from a template
&lt;/h3&gt;

&lt;p&gt;Turn a C# data model into a styled, real-world invoice: branded header, a line-item table, VAT totals and a page-numbered footer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1) Your data - normally from a database or an order.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LineItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SelectPdf Developer License"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Qty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UnitPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;499m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LineItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Priority Support (1 year)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;Qty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UnitPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;199m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LineItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"On-site training (per day)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;Qty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UnitPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;900m&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 2) Render the data into an HTML template (see BuildInvoiceHtml in the source).&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INV-1042"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3) Convert to PDF, adding a footer with page numbers.&lt;/span&gt;
&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayFooter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;28&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;PdfTextSection&lt;/span&gt; &lt;span class="n"&gt;pageNo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Invoice INV-1042 - page {page_number} of {total_pages}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Arial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;pageNo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTextHorizontalAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageNo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjaor90b3617sc0e3guza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjaor90b3617sc0e3guza.png" alt="Build an invoice from a template" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Render complex HTML that paginates
&lt;/h3&gt;

&lt;p&gt;Prove the engine handles modern CSS - grid layout and a live web font - plus a long table whose header repeats on every page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Give the web font a moment to download before the page is captured.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinPageLoadTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The report uses CSS grid, a Google web font, and a 30-row table.&lt;/span&gt;
&lt;span class="c1"&gt;// The table header repeats on every page (thead { display: table-header-group })&lt;/span&gt;
&lt;span class="c1"&gt;// and rows are kept whole (page-break-inside: avoid) - all controlled from CSS.&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;BuildReportHtml&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjzv0ytpz5cbe1ovmfqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjzv0ytpz5cbe1ovmfqc.png" alt="Render complex HTML that paginates" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3 - Control the page layout
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6. Set page size, orientation and margins
&lt;/h3&gt;

&lt;p&gt;Control the physical page: choose A4, switch to landscape, and set the page margins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Page setup (margins are expressed in points; 72 points = 1 inch).&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Landscape&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;A4 Landscape&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;This page uses a custom size, orientation and half-inch margins.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyspdue0ru9ae0s7r1lpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyspdue0ru9ae0s7r1lpp.png" alt="Set page size, orientation and margins" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Add headers and footers with page numbers
&lt;/h3&gt;

&lt;p&gt;Draw a repeating header on every page and a footer that shows "Page X of Y".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Enable and populate the header.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayHeader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;PdfTextSection&lt;/span&gt; &lt;span class="n"&gt;headerText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SelectPdf Tutorial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Arial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FontStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bold&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;headerText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTextHorizontalAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Enable and populate the footer with page numbering tokens.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayFooter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;PdfTextSection&lt;/span&gt; &lt;span class="n"&gt;footerText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Page {page_number} of {total_pages}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Arial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;footerText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTextHorizontalAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;footerText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjjm7f272c6c7fcrjlz7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjjm7f272c6c7fcrjlz7m.png" alt="Add headers and footers with page numbers" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Use HTML for headers and footers
&lt;/h3&gt;

&lt;p&gt;Build a fully styled header or footer from an HTML fragment instead of plain text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Render the header from an HTML fragment so it can be fully styled with CSS.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayHeader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfHtmlSection&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfHtmlSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;div style='font-family:Arial;color:#b45309;font-size:18px;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"border-bottom:2px solid #b45309;padding:6px 0;'&amp;gt;Acme Corporation&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoFitHeight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HtmlToPdfPageFitMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoFit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Report body&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;The header above is rendered from HTML.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhv6olyhq5qflau0o9xke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhv6olyhq5qflau0o9xke.png" alt="Use HTML for headers and footers" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Generate bookmarks from HTML headings
&lt;/h3&gt;

&lt;p&gt;Turn the document's headings into a clickable PDF bookmarks (outline) tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Build PDF bookmarks from the elements matching these CSS selectors.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfBookmarkOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CssSelectors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"h1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"h2"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Open the document with the bookmarks (outline) panel visible.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewerPreferences&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfViewerPageMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseOutlines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Chapter 1&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Introduction.&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h2&amp;gt;Section 1.1&amp;lt;/h2&amp;gt;&amp;lt;p&amp;gt;Details.&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Chapter 2&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;More content.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh3l9rajspdzwf5xmz11o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh3l9rajspdzwf5xmz11o.png" alt="Generate bookmarks from HTML headings" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Produce a single-page PDF
&lt;/h3&gt;

&lt;p&gt;Fit the whole document onto one continuous page with no page breaks - handy for receipts and tickets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Produce one continuous page sized to the content, instead of paginating.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateSinglePagePdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Single-page output&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;Section one.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Section two.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Section three.&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;All content stays on a single, taller page with no page breaks.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjx1lryf4a00pkwdytsmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjx1lryf4a00pkwdytsmg.png" alt="Produce a single-page PDF" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Add a watermark to every page
&lt;/h3&gt;

&lt;p&gt;Stamp a semi-transparent text watermark - such as CONFIDENTIAL or DRAFT - behind the content of every page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Draft report&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Every page of this document carries a watermark.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Draw a large, light "CONFIDENTIAL" behind the content of every page,&lt;/span&gt;
&lt;span class="c1"&gt;// using a background template that repeats on all pages.&lt;/span&gt;
&lt;span class="n"&gt;PdfFont&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfStandardFont&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;RectangleF&lt;/span&gt; &lt;span class="n"&gt;pageRect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;ClientRectangle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;PdfTemplate&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageRect&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfTextElement&lt;/span&gt; &lt;span class="n"&gt;watermark&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageRect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageRect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CONFIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;watermark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromArgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;210&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;watermark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTextHorizontalAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watermark&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frb3l0wd0pqc8rnbs8sgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frb3l0wd0pqc8rnbs8sgm.png" alt="Add a watermark to every page" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4 - Dynamic and remote content
&lt;/h2&gt;

&lt;h3&gt;
  
  
  12. Wait for JavaScript-rendered content
&lt;/h3&gt;

&lt;p&gt;Give client-side scripts time to run so dynamic content is captured instead of a half-loaded page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Give client-side scripts time to run before the page is captured (seconds).&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinPageLoadTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Dynamic content&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p id='status'&amp;gt;Loading...&amp;lt;/p&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;script&amp;gt;setTimeout(function(){"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"document.getElementById('status').innerHTML = 'Loaded by JavaScript!';"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"}, 800);&amp;lt;/script&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29wudz89gscu4jrxce3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29wudz89gscu4jrxce3m.png" alt="Wait for JavaScript-rendered content" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Inject custom CSS and run a script
&lt;/h3&gt;

&lt;p&gt;Restyle the page with your own CSS and execute JavaScript after load, without touching the source HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Inject additional CSS into the page before rendering.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomCSS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="s"&gt;"body { font-family: Arial; background: #fef3c7; }"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"h1 { color: #b45309; }"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Run JavaScript after the page has loaded (Chromium/Blink only).&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostLoadingScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="s"&gt;"document.body.insertAdjacentHTML('beforeend', '&amp;lt;p&amp;gt;Added by script.&amp;lt;/p&amp;gt;');"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Custom styled page&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;The amber background and heading color come from injected CSS.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dom9y0r3r0igeh6h4gj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4dom9y0r3r0igeh6h4gj.png" alt="Inject custom CSS and run a script" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Control the browser viewport width
&lt;/h3&gt;

&lt;p&gt;Set the virtual browser width the HTML is laid out at, then shrink oversized layouts to fit the PDF page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Lay the HTML out at a fixed 1200px browser width...&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebPageWidth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebPageFixedSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...then shrink it so the wide layout fits the PDF page width.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoFitWidth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HtmlToPdfPageFitMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShrinkOnly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;div style='width:1200px;background:#e0f2fe;padding:24px'&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Wide layout&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;Rendered at a 1200px viewport, then shrunk to fit the page.&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz2a66xlgtgikkogg3e75.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz2a66xlgtgikkogg3e75.png" alt="Control the browser viewport width" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  15. Send HTTP headers and cookies
&lt;/h3&gt;

&lt;p&gt;Attach custom request headers and cookies to reach authenticated or localized pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Attach custom request headers (e.g. language, bearer token) and cookies.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Accept-Language"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpCookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"session"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"demo-cookie-value"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.selectpdf.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuarkw11t32zg1icayf4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuarkw11t32zg1icayf4p.png" alt="Send HTTP headers and cookies" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5 - Secure, archive, integrate
&lt;/h2&gt;

&lt;h3&gt;
  
  
  16. Set the document properties
&lt;/h3&gt;

&lt;p&gt;Fill in the PDF title, author, subject and keywords shown in the viewer and used by search indexes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Quarterly Report&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Prepared for Acme Corporation.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// These appear in the viewer's "Document Properties" dialog and in search indexes.&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DocumentInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Quarterly Report"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DocumentInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SelectPdf"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DocumentInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Q3 financial results"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DocumentInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Keywords&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"report, quarterly, finance"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DocumentInformation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreationDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffwvv4li2gf2rl3vbhlrs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffwvv4li2gf2rl3vbhlrs.png" alt="Set the document properties" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  17. Password-protect and restrict permissions
&lt;/h3&gt;

&lt;p&gt;Encrypt the PDF with an owner password and disable copying and editing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Encrypt with an owner password and restrict what readers may do.&lt;/span&gt;
&lt;span class="c1"&gt;// (Set UserPassword as well to also require a password just to open the file.)&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerPassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"owner-secret"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanPrint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanCopyContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanEditContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Confidential&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Copying and editing are disabled on this document.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2m171an3gvvkgatjmpk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2m171an3gvvkgatjmpk4.png" alt="Password-protect and restrict permissions" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  18. Create an archivable PDF/A-3 document
&lt;/h3&gt;

&lt;p&gt;Emit a PDF/A-3B file suitable for long-term archiving and compliance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// PDF/A (and tagged/accessible) output requires the Chromium engine.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Emit a PDF/A-3B document suitable for long-term archiving.&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfStandard&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfStandard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfA3B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Archivable document&amp;lt;/h1&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;p&amp;gt;Saved as PDF/A-3B for long-term archiving and compliance.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F66juk1eseotfulsawi7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F66juk1eseotfulsawi7h.png" alt="Create an archivable PDF/A-3 document" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  19. Generate a PDF in ASP.NET Core
&lt;/h3&gt;

&lt;p&gt;Build the PDF in a controller action and stream it straight to the browser as a downloadable file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In an ASP.NET Core app, generate the PDF inside a controller action and stream it back.&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/invoice/{id:int}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;HtmlToPdf&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Chromium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;$"&amp;lt;h1&amp;gt;Invoice #&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Thank you for your order.&amp;lt;/p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Save straight to a byte array - no temp file needed.&lt;/span&gt;
        &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Return it as a downloadable file (omit the file name to show it inline).&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"invoice-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18oia6d0dlcg2a6qhshv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18oia6d0dlcg2a6qhshv.png" alt="Generate a PDF in ASP.NET Core" width="800" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 6 - Run it in production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  20. Running in production
&lt;/h3&gt;

&lt;p&gt;SelectPdf runs entirely in-process and is Windows-only (x86 and x64) - there is no Linux or macOS build, and the host needs full trust. Factor that into your hosting choice before you commit.&lt;/p&gt;

&lt;p&gt;A converter instance is not thread-safe: create one HtmlToPdf per conversion rather than sharing one across threads, and cap parallelism with your own queue or semaphore - the library has no built-in concurrency limit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt; - ship Select.Pdf.dll together with Select.Html.dep and Select.Tools.dep; for the Chromium engine also deploy its runtime folder (the Chromium.Windows package copies it on build).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process bitness&lt;/strong&gt; - match the package to the process or you get a BadImageFormatException. Under IIS, Enable 32-Bit Applications = True runs x86, False runs x64.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt; - on 64-bit servers use the x64 package - it can allocate far more memory for image-heavy pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts&lt;/strong&gt; - the default navigation timeout is 60 seconds; raise Options.MaxPageLoadTime for slow pages and use MinPageLoadTime to wait for late assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Licensing&lt;/strong&gt; - set GlobalProperties.LicenseKey once at startup, before any conversion; the trial watermarks every page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Untrusted HTML&lt;/strong&gt; - disable scripts (Options.JavaScriptEnabled = false) and local file access (Options.DenyLocalFileAccess = true) when converting input you do not control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure&lt;/strong&gt; - App Service needs the Chromium engine (v26.2+, Basic plan or above); Virtual Machines and Cloud Services have no restrictions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  21. Troubleshooting
&lt;/h3&gt;

&lt;p&gt;A handful of problems come up again and again - here is the quick fix for each.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blank page, or images and CSS missing from an HTML string&lt;/strong&gt; - pass a base URL: ConvertHtmlString(html, baseUrl) so relative URLs resolve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic content missing&lt;/strong&gt; - the page needs more time or a signal - set Options.MinPageLoadTime, or use WindowStatus / PostLoadingScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BadImageFormatException&lt;/strong&gt; - the x86 or x64 package does not match the process bitness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Could not find Select.Html.dep&lt;/strong&gt; - copy Select.Html.dep and Select.Tools.dep next to Select.Pdf.dll.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation timeout&lt;/strong&gt; - the page is slower than 60s, the URL is not resolvable from the server, or a proxy is required - raise MaxPageLoadTime or set Options.ProxyOptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An image splits across two pages&lt;/strong&gt; - set Options.KeepImagesTogether = true, or style the img with page-break-inside: avoid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OutOfMemoryException&lt;/strong&gt; - an image-heavy page - use the x64 package and optimize the images.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  22. Frequently asked questions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is SelectPdf free?&lt;/strong&gt; - The &lt;a href="https://selectpdf.com/community-edition/" rel="noopener noreferrer"&gt;Community Edition&lt;/a&gt; (Select.HtmlToPdf) is free for HTML to PDF with a 5-page cap. This tutorial uses the commercial &lt;a href="https://selectpdf.com/pdf-library-for-net/" rel="noopener noreferrer"&gt;Select.Pdf library&lt;/a&gt; - a paid license with the full feature set and no page limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does it run on Linux, macOS or in Docker?&lt;/strong&gt; - No. The library is Windows-only (x86 and x64). To generate PDFs from Linux, host it on Windows or use the &lt;a href="https://selectpdf.com/html-to-pdf-api/" rel="noopener noreferrer"&gt;SelectPdf online HTML-to-PDF REST API&lt;/a&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which rendering engine should I use?&lt;/strong&gt; - Chromium (used throughout this tutorial) for modern HTML5, CSS3 and web fonts. WebKit is the embedded default with nothing extra to deploy; Blink is an alternative Chromium-based engine. Chromium and Blink each need their companion NuGet package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do I remove the trial watermark?&lt;/strong&gt; - Set GlobalProperties.LicenseKey once at application startup, before any conversion. See &lt;a href="https://selectpdf.com/pricing/" rel="noopener noreferrer"&gt;.NET library pricing&lt;/a&gt; for license options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can it convert a page that requires login?&lt;/strong&gt; - Yes - send authentication cookies or headers (see Send HTTP headers and cookies), or post form data with HttpPostParameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is there a limit on the number of pages?&lt;/strong&gt; - Not in the commercial library. The 5-page cap applies only to the free &lt;a href="https://selectpdf.com/community-edition/" rel="noopener noreferrer"&gt;Community Edition&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can I convert charts or content drawn by JavaScript?&lt;/strong&gt; - Yes, with the Chromium engine. Give scripts time to run with Options.MinPageLoadTime, or wait for a signal via WindowStatus (see Wait for JavaScript-rendered content).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is the converter thread-safe?&lt;/strong&gt; - Use one HtmlToPdf instance per conversion and throttle concurrency yourself; see Running in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That is the full arc of HTML to PDF with SelectPdf - from a three-line string conversion to a real invoice, complex paginating layouts, security, archival compliance, ASP.NET Core integration and production hardening. Because the same Chromium engine powers every example, what you preview in the browser is what lands in the PDF. Start with a &lt;a href="https://selectpdf.com/downloads/" rel="noopener noreferrer"&gt;free trial&lt;/a&gt;, browse the &lt;a href="https://selectpdf.com/pdf-library/" rel="noopener noreferrer"&gt;full API reference&lt;/a&gt;, or try the &lt;a href="https://selectpdf.com/demo/" rel="noopener noreferrer"&gt;live C# demo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pdf</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>htmltopdf</category>
    </item>
    <item>
      <title>wkhtmltopdf is archived. A straight .NET migration guide (Windows, Linux, Docker and Azure)</title>
      <dc:creator>Florentin Badea</dc:creator>
      <pubDate>Sun, 05 Jul 2026 06:53:30 +0000</pubDate>
      <link>https://dev.to/florentin_badea/wkhtmltopdf-is-archived-a-straight-net-migration-guide-azure-windows-and-the-linux-caveat-2lc6</link>
      <guid>https://dev.to/florentin_badea/wkhtmltopdf-is-archived-a-straight-net-migration-guide-azure-windows-and-the-linux-caveat-2lc6</guid>
      <description>&lt;p&gt;&lt;em&gt;Updated October 2026 for SelectPdf 26.4: the library now runs on Linux, in Docker and on macOS on Apple Silicon as well, through the new SelectPdf.Universal packages. The Linux sections below are rewritten accordingly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your .NET app still calls &lt;code&gt;DinkToPdf&lt;/code&gt;, &lt;code&gt;NReco.PdfGenerator&lt;/code&gt;, &lt;code&gt;Rotativa&lt;/code&gt;, or &lt;code&gt;WkHtmlToXSharp&lt;/code&gt; in production, you're shipping a wrapper around a binary that hasn't had a security patch in years — and one of its open holes is a &lt;strong&gt;CVSS 9.8&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;wkhtmltopdf's repository has been &lt;strong&gt;frozen and read-only since January 2023&lt;/strong&gt;, and the whole project org was archived by mid-2024. Development has stopped; nobody is accepting patches. The underlying QtWebKit engine forked from upstream around 2012 — no modern Flexbox, no Grid, no modern JavaScript, no ICU updates. And &lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2022-35583" rel="noopener noreferrer"&gt;&lt;strong&gt;CVE-2022-35583&lt;/strong&gt;&lt;/a&gt; — an SSRF that lets an attacker reach your internal network by injecting an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; pointing at an internal IP — sits at &lt;strong&gt;CVSS 9.8, unpatched, and permanently so.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your app takes any user-influenced HTML and turns it into a PDF behind a public endpoint, that's not a "someday" cleanup. This post is the migration I'd actually run.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work on &lt;a href="https://selectpdf.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;SelectPdf&lt;/strong&gt;&lt;/a&gt;, a .NET PDF library, and the code below is SelectPdf because that's what I can vouch for line by line. I'll be honest about where it fits and where it doesn't. The broader point stands no matter what you pick: &lt;strong&gt;stop wrapping the dead binary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  First: Windows, Linux or Docker?
&lt;/h2&gt;

&lt;p&gt;I'm putting this at the top because it decides which packages you install, and nothing annoys an engineer more than finding it in paragraph 30. The good news: since version 26.4 there is a SelectPdf library for each case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux, Docker, macOS on Apple Silicon — or any new project on modern .NET&lt;/strong&gt; — use &lt;strong&gt;SelectPdf.Universal&lt;/strong&gt;, the new flagship edition. It runs on Windows (x64, x86), Linux (x64, ARM64) and macOS on Apple Silicon, targets .NET 8 and .NET 10 plus .NET Standard 2.0, and renders with Chromium. You reference the library plus one native package per runtime you deploy to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An existing Windows or .NET Framework app&lt;/strong&gt; (IIS, a VM, Windows App Service) — the classic &lt;strong&gt;SelectPdf&lt;/strong&gt; library is a direct NuGet reference with one API call, supports .NET Framework 2.0 and later, and keeps its four rendering engines. It is still maintained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not on .NET, or you want nothing to deploy at all&lt;/strong&gt; — SelectPdf's &lt;strong&gt;&lt;a href="https://selectpdf.com/html-to-pdf-api/" rel="noopener noreferrer"&gt;Online REST API&lt;/a&gt;&lt;/strong&gt;: your app POSTs HTML and gets back PDF bytes over HTTPS, from any OS and any language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Linux is where wkhtmltopdf hurts most today (newer glibc/libssl combos crash it, and it's no one's job to fix), so it's worth being specific. The &lt;code&gt;SelectPdf.Universal.Native.linux-x64&lt;/code&gt; and &lt;code&gt;linux-arm64&lt;/code&gt; packages carry the shared libraries Chromium needs, so a stock .NET runtime image converts pages with no &lt;code&gt;apt-get&lt;/code&gt; step, no X server and no special &lt;code&gt;docker run&lt;/code&gt; flags. That was verified with real HTTPS conversions on Debian 12, Ubuntu 22.04, Ubuntu 24.04 and Amazon Linux 2023. Latin, Greek and Cyrillic text prints with the fonts built into the library; for other scripts (Arabic, Chinese, Japanese, Korean, Hindi, Thai and more) add the optional &lt;code&gt;SelectPdf.Universal.Fonts&lt;/code&gt; package — also just a NuGet reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Why not just use Playwright or PuppeteerSharp?"
&lt;/h2&gt;

&lt;p&gt;Fair question, and for some teams that's the right call — they're free, cross-platform, and render with real Chromium. Here's the honest trade:&lt;/p&gt;

&lt;p&gt;With Playwright/PuppeteerSharp &lt;strong&gt;you operate the browser yourself.&lt;/strong&gt; You run a provisioning step (&lt;code&gt;playwright install&lt;/code&gt;, or bundling the binaries) and version-manage Chromium; you own the headless browser's lifecycle (zombie processes are real under load); you write your own concurrency throttling; and you write and maintain the automation script. On Linux you also chase down the font and shared-library packages so text doesn't render as boxes. On Windows App Service specifically, a raw headless browser tends to fight the sandbox too — a similar restriction to the Win32k/GDI wall that bites wkhtmltopdf (more on that below).&lt;/p&gt;

&lt;p&gt;Now the honest part, about what is &lt;em&gt;not&lt;/em&gt; a difference: SelectPdf also ships a bundled Chromium (CEF) runtime of broadly similar size — so the disk/image footprint is roughly a wash. Chromium is Chromium. What differs is &lt;strong&gt;who provisions and babysits it.&lt;/strong&gt; SelectPdf ships the matched runtime as a NuGet package that the build copies into your output automatically (no separate install step, no version drift), manages the browser for you, and caps parallelism through one built-in setting (&lt;code&gt;MaximumConcurrentConversions&lt;/code&gt;) — all behind a single call that returns the PDF. On Linux the native package already carries the shared libraries, so there is nothing to &lt;code&gt;apt-get&lt;/code&gt;. The engine is also built to run inside the App Service sandbox where a raw headless browser struggles. You don't write automation, and you don't provision a browser fleet.&lt;/p&gt;

&lt;p&gt;And there's a &lt;strong&gt;scope&lt;/strong&gt; difference that outlasts the migration: Playwright and Puppeteer &lt;em&gt;only print HTML to PDF.&lt;/em&gt; The moment your requirements grow past "render this page" — merge the invoice with a cover sheet, stamp a watermark, fill an AcroForm, digitally sign it, encrypt it, or extract the text back out for search — you're bolting on a &lt;em&gt;second&lt;/em&gt; PDF library (PdfSharp, iText, QuestPDF) and gluing two toolchains together. SelectPdf's &lt;strong&gt;commercial&lt;/strong&gt; library does the rendering &lt;em&gt;and&lt;/em&gt; that post-processing in one dependency: create PDFs from scratch, merge/split, stamp, fill and flatten forms, sign, encrypt, extract text and images, and emit tagged PDF/UA or PDF/A for accessibility and archival. (The free Community Edition is HTML→PDF only — these extras are the paid library.) If rendering HTML is genuinely all you'll ever do, that breadth doesn't matter and Puppeteer is fine. If you can feel a "can you also…" ticket coming, one library beats two.&lt;/p&gt;

&lt;p&gt;If your team is happy operating headless Chrome directly and never needs more than print-to-PDF, Puppeteer is a perfectly defensible choice. Pick with eyes open.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(One more note on the "is it even alive?" question, since wkhtmltopdf just taught everyone to ask it: SelectPdf shipped **v26.4 in October 2026&lt;/em&gt;* — the release that added SelectPdf.Universal for Linux, Docker and macOS on Apple Silicon — and the packages sit at &lt;strong&gt;23M+ NuGet downloads&lt;/strong&gt;. Actively maintained, with a paid tier where a human answers.)*&lt;/p&gt;




&lt;h2&gt;
  
  
  What "archived" actually means for your stack
&lt;/h2&gt;

&lt;p&gt;Most teams know wkhtmltopdf is "old" but haven't priced in the archive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No more CVE patches. Ever.&lt;/strong&gt; CVE-2022-35583 is filed, triaged, and will never be fixed upstream. Any SSRF reported after the repo froze lands in a read-only tracker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QtWebKit is frozen near 2012.&lt;/strong&gt; CSS Grid, container queries, modern JS, modern font features — anything your designers shipped in the last decade renders unreliably or not at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The .NET wrappers fix none of this.&lt;/strong&gt; &lt;code&gt;DinkToPdf&lt;/code&gt;, &lt;code&gt;NReco.PdfGenerator&lt;/code&gt;, &lt;code&gt;Rotativa.AspNetCore&lt;/code&gt;, &lt;code&gt;WkHtmlToXSharp&lt;/code&gt; all P/Invoke into the same &lt;code&gt;libwkhtmltox&lt;/code&gt; native binary. If wkhtmltopdf isn't patched, neither are they. (DinkToPdf itself hasn't shipped a release since 2017.)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The migration, in code
&lt;/h2&gt;

&lt;p&gt;Here's a typical DinkToPdf setup — note the injected &lt;code&gt;IConverter&lt;/code&gt;, which DinkToPdf &lt;em&gt;requires&lt;/em&gt; as a singleton because the native lib can't be loaded repeatedly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Old: DinkToPdf&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;DinkToPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;DinkToPdf.Contracts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IConverter&lt;/span&gt; &lt;span class="n"&gt;_converter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;InvoiceController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConverter&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;RenderInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HtmlToPdfDocument&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;GlobalSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PaperKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Orientation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Orientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Portrait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Margins&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MarginSettings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Top&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;Objects&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ObjectSettings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;HtmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"invoice-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same endpoint with SelectPdf.Universal — the same code runs on Windows, Linux and macOS on Apple Silicon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// New: SelectPdf.Universal&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SelectPdf.Universal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice/{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;RenderInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageSize&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageOrientation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Portrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// parameterless Save() returns the PDF bytes&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"invoice-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the classic Windows library the code is the same apart from &lt;code&gt;using SelectPdf;&lt;/code&gt; and one extra line to pick the engine: &lt;code&gt;converter.Options.RenderingEngine = RenderingEngine.Chromium;&lt;/code&gt; (SelectPdf.Universal renders with Chromium only, so it needs no such line).&lt;/p&gt;

&lt;h3&gt;
  
  
  About that lifecycle change
&lt;/h3&gt;

&lt;p&gt;You probably noticed the DI singleton is gone. That's deliberate, and it's the question a careful reviewer should ask: &lt;em&gt;is &lt;code&gt;new HtmlToPdf()&lt;/code&gt; per request safe?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes. Unlike DinkToPdf's converter, there's no "load the native lib exactly once" dance — you construct a converter per conversion. Parallelism is governed by a single knob, &lt;code&gt;HtmlToPdfOptions.MaximumConcurrentConversions&lt;/code&gt; (default &lt;code&gt;8&lt;/code&gt; in SelectPdf.Universal, &lt;code&gt;4&lt;/code&gt; in the classic library), which you set &lt;strong&gt;once at startup, before the first conversion&lt;/strong&gt;; requests beyond the limit queue for a slot rather than thrashing the box. So the mental model is: &lt;code&gt;new&lt;/code&gt; freely per request, cap total concurrency globally. If you'd rather keep a DI registration for testability, register the converter as transient — it doesn't need to be a singleton. SelectPdf.Universal also has &lt;code&gt;ConvertHtmlStringAsync&lt;/code&gt; and &lt;code&gt;ConvertUrlAsync&lt;/code&gt;, with cancellation, if your controllers are async.&lt;/p&gt;

&lt;h3&gt;
  
  
  NuGet packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# SelectPdf.Universal — Windows, Linux, Docker, macOS on Apple Silicon.&lt;/span&gt;
&lt;span class="c"&gt;# The library, plus one native package per runtime you deploy to&lt;/span&gt;
&lt;span class="c"&gt;# (win-x64, win-x86, linux-x64, linux-arm64, osx-arm64).&lt;/span&gt;

&lt;span class="c"&gt;# Free Community Edition — HTML-&amp;gt;PDF only, 5-page cap;&lt;/span&gt;
&lt;span class="c"&gt;# no PDF post-processing (merge/split, forms, signing, encryption, extraction)&lt;/span&gt;
dotnet add package SelectPdf.HtmlToPdf.Universal
dotnet add package SelectPdf.Universal.Native.linux-x64

&lt;span class="c"&gt;# Commercial library once you outgrow 5 pages (from $499, perpetual)&lt;/span&gt;
dotnet add package SelectPdf.Universal
dotnet add package SelectPdf.Universal.Native.linux-x64

&lt;span class="c"&gt;# Optional on Linux: fonts for non-Latin scripts&lt;/span&gt;
dotnet add package SelectPdf.Universal.Fonts

&lt;span class="c"&gt;# Classic library on Windows (.NET Framework 4.6.1+ and modern .NET;&lt;/span&gt;
&lt;span class="c"&gt;# for .NET Framework 2.0/4.0 use Select.HtmlToPdf / Select.Pdf)&lt;/span&gt;
dotnet add package Select.HtmlToPdf.NetCore                    &lt;span class="c"&gt;# free CE&lt;/span&gt;
dotnet add package Select.HtmlToPdf.NetCore.Chromium.Windows
dotnet add package Select.Pdf.NetCore                          &lt;span class="c"&gt;# commercial&lt;/span&gt;
dotnet add package Select.Pdf.NetCore.Chromium.Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference several native packages if you build for several targets — developing on Windows and deploying to a Linux container is the common case. Be honest with yourself about that &lt;strong&gt;5-page cap&lt;/strong&gt;: it's free forever, but a typical multi-page invoice or report blows past it, so for real workloads the CE is effectively an evaluation and you'll want a license (&lt;a href="https://selectpdf.com/pricing/" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;). One perpetual license covers both the classic and the Universal library. The classic packages still target &lt;code&gt;net20&lt;/code&gt; and &lt;code&gt;net40&lt;/code&gt; (&lt;code&gt;Select.Pdf&lt;/code&gt;, &lt;code&gt;Select.HtmlToPdf&lt;/code&gt;) and &lt;code&gt;net461&lt;/code&gt;, &lt;code&gt;net472&lt;/code&gt; and &lt;code&gt;netstandard2.0&lt;/code&gt; (the &lt;code&gt;.NetCore&lt;/code&gt; packages), so migrating a .NET Framework app doesn't force a TFM bump.&lt;/p&gt;




&lt;h2&gt;
  
  
  Migrating your wkhtmltopdf flags
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ConvertHtmlString&lt;/code&gt; call is the easy 20%. The part that actually took you an afternoon in wkhtmltopdf was the CLI flags — headers, footers, page numbers, margins. Here's the mapping so you're not reverse-engineering it (it is the same in both libraries):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;wkhtmltopdf&lt;/th&gt;
&lt;th&gt;SelectPdf&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--page-size A4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Options.PdfPageSize = PdfPageSize.A4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--orientation Landscape&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Options.PdfPageOrientation = PdfPageOrientation.Landscape&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;--margin-top 20&lt;/code&gt; (etc.)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Options.MarginTop = 20&lt;/code&gt; (&lt;code&gt;MarginBottom/Left/Right&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--header-html header.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Options.DisplayHeader = true;&lt;/code&gt; then &lt;code&gt;converter.Header.Add(new PdfHtmlSection(url))&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--footer-html footer.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Options.DisplayFooter = true;&lt;/code&gt; then &lt;code&gt;converter.Footer.Add(...)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;[page] / [topage]&lt;/code&gt; footer tokens&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{page_number}&lt;/code&gt; / &lt;code&gt;{total_pages}&lt;/code&gt; in a &lt;code&gt;PdfTextSection&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--print-media-type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Options.CssMediaType = HtmlToPdfCssMediaType.Print&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Footer with page numbers, end to end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayFooter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Height&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageNo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Page {page_number} of {total_pages}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfFont&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateStandardFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfStandardFont&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;pageNo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HorizontalAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfTextHorizontalAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageNo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(On the classic library, &lt;code&gt;PdfTextSection&lt;/code&gt; takes a &lt;code&gt;System.Drawing.Font&lt;/code&gt; instead, for example &lt;code&gt;new System.Drawing.Font("Arial", 9)&lt;/code&gt;. SelectPdf.Universal has its own font types because System.Drawing is Windows-only on current .NET.)&lt;/p&gt;

&lt;p&gt;That — headers, footers, page numbering — all works in the &lt;strong&gt;free&lt;/strong&gt; Community Edition too, within the 5-page cap.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Azure App Service angle
&lt;/h2&gt;

&lt;p&gt;This is the one I get asked about most, so I'll be explicit.&lt;/p&gt;

&lt;p&gt;Azure App Service on Windows runs your app in a sandbox that blocks most User32/GDI32 (Win32k.sys) system calls — exactly what a GDI-based browser engine bundled in a .NET app needs. That's what makes wkhtmltopdf flaky there: P/Invoke load failures, missing GDI calls, font issues. Bundled headless-Chrome setups tend to struggle in the same sandbox too, for related reasons (process/GPU restrictions rather than GDI specifically).&lt;/p&gt;

&lt;p&gt;SelectPdf's Chromium engine — on &lt;strong&gt;Chromium 154&lt;/strong&gt; as of v26.4 — is built to run inside that sandbox. With SelectPdf.Universal the same code runs on &lt;strong&gt;App Service and Azure Functions, on both Windows and Linux&lt;/strong&gt;, on the Basic plan or above. One caveat worth knowing up front: on Windows, don't deploy with "Run From Package" (&lt;code&gt;WEBSITE_RUN_FROM_PACKAGE&lt;/code&gt;) — the engine cannot load its libraries from the mounted package; Zip Deploy and Web Deploy are fine. The classic library runs on Windows App Service (Basic and above), and on Azure Functions when hosted on a Premium or App Service plan. From your code it's the same call you already saw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/report"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No "but it works locally" Slack thread at 11pm.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing the SSRF loop
&lt;/h2&gt;

&lt;p&gt;We opened on CVE-2022-35583, so let's not hand-wave the fix. Two things change when you migrate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You get a kill-switch for local-file exfiltration.&lt;/strong&gt; Set &lt;code&gt;HtmlToPdfOptions.DenyLocalFileAccess = true&lt;/code&gt; per conversion, or &lt;code&gt;GlobalProperties.ForceDenyLocalFileAccess = true&lt;/code&gt; process-wide, and &lt;code&gt;file://&lt;/code&gt; reads are blocked — shutting off the local-file-read half of the classic wkhtmltopdf attack. Both libraries have both switches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The internal-IP SSRF half is a network problem, and the right answer depends on trust.&lt;/strong&gt; If you convert genuinely untrusted, user-supplied HTML, don't render it on your own infrastructure next to your internal network at all — push it to the &lt;strong&gt;&lt;a href="https://selectpdf.com/html-to-pdf-api/" rel="noopener noreferrer"&gt;Online REST API&lt;/a&gt;&lt;/strong&gt;, so the conversion runs off your infrastructure, away from your internal network. And unlike the archived binary, when a rendering-side issue &lt;em&gt;is&lt;/em&gt; found, there's a maintained product that can actually ship a fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the real difference: not "SelectPdf is magically SSRF-proof," but "you get controls, isolation options, and someone who patches."&lt;/p&gt;




&lt;h2&gt;
  
  
  What to actually do this week
&lt;/h2&gt;

&lt;p&gt;A pragmatic checklist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;grep&lt;/code&gt; the solution for &lt;code&gt;DinkToPdf&lt;/code&gt;, &lt;code&gt;NReco.PdfGenerator&lt;/code&gt;, &lt;code&gt;Rotativa&lt;/code&gt;, &lt;code&gt;WkHtmlToX&lt;/code&gt;, &lt;code&gt;wkhtmltopdf&lt;/code&gt;. Every hit is a candidate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick the package for where you deploy&lt;/strong&gt; (see the top): SelectPdf.Universal for Linux, Docker and new projects; the classic library for an existing Windows or .NET Framework app; the Online API for anything else.&lt;/li&gt;
&lt;li&gt;Pick the one endpoint that renders user-influenced HTML. Highest-risk surface; start there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotnet add package SelectPdf.HtmlToPdf.Universal&lt;/code&gt; + &lt;code&gt;SelectPdf.Universal.Native.&amp;lt;rid&amp;gt;&lt;/code&gt; for each runtime you deploy to. Free, 5-page cap.&lt;/li&gt;
&lt;li&gt;Port the converter call and your header/footer flags using the mapping above; run your existing tests; eyeball the output diff.&lt;/li&gt;
&lt;li&gt;If layout shifts (it might — wkhtmltopdf has 2012-era quirks your CSS may lean on), the fix is almost always a CSS cleanup, not a converter tweak.&lt;/li&gt;
&lt;li&gt;Past 5 pages, get a license — but validate output on the free build first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If SelectPdf isn't right for your stack, &lt;strong&gt;still migrate.&lt;/strong&gt; Anything maintained beats an archived 9.8. And if you try it and hit a snag, drop me a line — I read the inbox.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-platform library (Windows, Linux, Docker, macOS on Apple Silicon): &lt;a href="https://selectpdf.com/pdf-library-cross-platform/" rel="noopener noreferrer"&gt;selectpdf.com/pdf-library-cross-platform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Free Community Edition: &lt;a href="https://selectpdf.com/community-edition/" rel="noopener noreferrer"&gt;selectpdf.com/community-edition&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo (paste any URL): &lt;a href="https://selectpdf.com/demo-universal/" rel="noopener noreferrer"&gt;selectpdf.com/demo-universal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Online API for any language: &lt;a href="https://selectpdf.com/html-to-pdf-api/" rel="noopener noreferrer"&gt;selectpdf.com/html-to-pdf-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs, including Docker and Azure deployment: &lt;a href="https://selectpdf.com/pdf-library/" rel="noopener noreferrer"&gt;selectpdf.com/pdf-library&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NuGet: &lt;a href="https://www.nuget.org/packages/SelectPdf.HtmlToPdf.Universal/" rel="noopener noreferrer"&gt;&lt;code&gt;SelectPdf.HtmlToPdf.Universal&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, follow — the next post is &lt;strong&gt;"Top 10 HTML-to-PDF Libraries for C# / .NET (2026): A Practical Comparison,"&lt;/strong&gt; a fair head-to-head of the real options in this space, including where SelectPdf &lt;em&gt;isn't&lt;/em&gt; the right pick.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>azure</category>
      <category>pdf</category>
    </item>
    <item>
      <title>Stop your AI assistant from hallucinating PDF APIs: SelectPdf AI Tools</title>
      <dc:creator>Florentin Badea</dc:creator>
      <pubDate>Wed, 01 Jul 2026 14:38:44 +0000</pubDate>
      <link>https://dev.to/florentin_badea/stop-your-ai-assistant-from-hallucinating-pdf-apis-selectpdf-ai-tools-39nb</link>
      <guid>https://dev.to/florentin_badea/stop-your-ai-assistant-from-hallucinating-pdf-apis-selectpdf-ai-tools-39nb</guid>
      <description>&lt;p&gt;AI coding assistants are great at .NET boilerplate, but ask one to generate PDF code and it will happily invent a method that doesn't exist, or reach for a commercial feature while claiming it's in the free edition. The model is guessing from training data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/selectpdf/ai-tools" rel="noopener noreferrer"&gt;SelectPdf AI Tools&lt;/a&gt; fixes that. It's a free, open-source (MIT) set of &lt;strong&gt;Agent Skills&lt;/strong&gt; that give your assistant accurate, version-matched knowledge of the &lt;a href="https://selectpdf.com/pdf-library-for-net/" rel="noopener noreferrer"&gt;SelectPdf .NET library&lt;/a&gt; — real API signatures, working code, and the gotchas that matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's in it
&lt;/h3&gt;

&lt;p&gt;A single Claude Code plugin with two skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;selectpdf-lib-net&lt;/code&gt;&lt;/strong&gt; — the full commercial &lt;a href="https://selectpdf.com/pdf-library-for-net/" rel="noopener noreferrer"&gt;Select.Pdf library&lt;/a&gt;: HTML→PDF, building/editing PDFs, merge/split, AcroForms, digital signatures, encryption, PDF→text/image, and accessible tagged PDF/UA-1 and PDF/A-3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;selectpdf-lib-htmltopdf-net&lt;/code&gt;&lt;/strong&gt; — the free &lt;a href="https://selectpdf.com/community-edition/" rel="noopener noreferrer"&gt;Community Edition&lt;/a&gt; (HTML→PDF).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every sample is in &lt;strong&gt;C# and VB.NET&lt;/strong&gt;, tracking SelectPdf v26.3.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install in Claude Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add selectpdf/ai-tools
/plugin install selectpdf@selectpdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The right skill activates automatically when you ask it to work with PDFs in a .NET project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor, Copilot, Codex
&lt;/h3&gt;

&lt;p&gt;The same knowledge ships in each tool's native format — Cursor &lt;code&gt;.mdc&lt;/code&gt; rules, Copilot &lt;code&gt;.instructions.md&lt;/code&gt;, and a Codex &lt;code&gt;AGENTS.md&lt;/code&gt; guide. Drop the file into your repo and your assistant is up to speed.&lt;/p&gt;

&lt;p&gt;It's all open source, so you can read exactly what your assistant is being told — and send a PR if you spot something. 👉 &lt;a href="https://github.com/selectpdf/ai-tools" rel="noopener noreferrer"&gt;https://github.com/selectpdf/ai-tools&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want to see the library itself? Browse the &lt;a href="https://selectpdf.com/pdf-library/" rel="noopener noreferrer"&gt;online documentation&lt;/a&gt; or try the &lt;a href="https://selectpdf.com/demo/" rel="noopener noreferrer"&gt;C# and VB.NET live demos&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>ai</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
