DKNet

DKNet.Svc.PdfGenerators

Converts HTML or Markdown into a PDF file using headless Chromium (PuppeteerSharp) and Markdig, with page layout, header/footer, and margin control.

[!NOTE] This package is a fork of Markdown2Pdf 2.x — see THIRD-PARTY-NOTICES.md for the upstream attribution. Several option types carried over from upstream are not wired into the current PdfGenerator pipeline — the feature pages below mark exactly which options affect the output today.

✨ Why use it?

Reach for it to turn Markdown documentation, generated reports, or arbitrary HTML into a downloadable PDF.

🚀 Quick Start

Use a .NET 10 console project. Install the package, then replace Program.cs with the example.

dotnet new console -f net10.0 -n PdfDemo
cd PdfDemo
dotnet add package DKNet.Svc.PdfGenerators
echo "# Hello PDF" > notes.md
using DKNet.Svc.PdfGenerators;
using DKNet.Svc.PdfGenerators.Options;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddPdfGenerator(new PdfGeneratorOptions
{
    MarginOptions = new MarginOptions { Top = "2cm", Bottom = "2cm", Left = "1.5cm", Right = "1.5cm" }
});
await using var provider = services.BuildServiceProvider();

var generator = provider.GetRequiredService<IPdfGenerator>();
var path = await generator.ConvertMarkdownFileAsync("notes.md", "reports/monthly.pdf");
Console.WriteLine(path);

Run with dotnet run. AddPdfGenerator(options) registers a factory for a singleton IPdfGenerator, so the PdfGenerator is built on first resolve; the call is idempotent, and the options passed to the first call are the ones the instance keeps for the process lifetime. The first conversion in a fresh environment downloads a Chromium build via PuppeteerSharp’s BrowserFetcher unless ChromePath points at an existing install — expect a one-time delay.

🏗️ Architecture

The host application calls AddPdfGenerator to register a singleton PdfGenerator, then calls IPdfGenerator. PdfGenerator renders Markdown through a fixed Markdig pipeline, guards every outgoing request with RequestGuard, and drives a headless Chromium process that writes the PDF file.

PdfGeneratorSetup.AddPdfGenerator registers one PdfGenerator as a singleton; it launches Chromium on first use and relaunches it only if the process disconnects. Not pictured: ThemeService, TableOfContentsCreator and ModuleService exist in the package but are never constructed by PdfGenerator, and there is no page or browser pool — every conversion opens and closes its own Chromium page.

🔄 How it works

A Markdown file goes through Markdig's fixed pipeline into HTML text, or an HTML string enters at the same point; the HTML is set on a headless Chromium page with the screen media type, PdfOptions supplies format, margins and scale, and PdfAsync writes the PDF whose path is returned. Theme, table-of-contents and module options sit beside the HTML stage with no code path into it.

The conversion is short, and the diagram is mostly useful for what it does not contain — there is no theme, module, table-of-contents, or metadata stage between Markdig and Chromium. PrintBackground is always true and the page renders with the screen media type, so @media print CSS rules never apply.

🧩 Features