HubtelPdfGenerator.Abstractions 1.0.6

dotnet add package HubtelPdfGenerator.Abstractions --version 1.0.6
                    
NuGet\Install-Package HubtelPdfGenerator.Abstractions -Version 1.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HubtelPdfGenerator.Abstractions" Version="1.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HubtelPdfGenerator.Abstractions" Version="1.0.6" />
                    
Directory.Packages.props
<PackageReference Include="HubtelPdfGenerator.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add HubtelPdfGenerator.Abstractions --version 1.0.6
                    
#r "nuget: HubtelPdfGenerator.Abstractions, 1.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package HubtelPdfGenerator.Abstractions@1.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=HubtelPdfGenerator.Abstractions&version=1.0.6
                    
Install as a Cake Addin
#tool nuget:?package=HubtelPdfGenerator.Abstractions&version=1.0.6
                    
Install as a Cake Tool

Hubtel HTML to PDF SDK

HubtelPdfGenerator is a modular .NET SDK for converting HTML to PDF using Playwright + Chromium, with support for advanced headers/footers, page visibility rules, watermarks, and robust print pagination behavior.

This guide is written for production use across Windows, macOS, Linux, and containers.

What You Get

  • HTML string to PDF (byte[] or Stream)
  • Custom header and footer templates
  • Page-number tokens (pageNumber, totalPages, date, title, url)
  • Per-page header/footer visibility rules (first/last/exclude, etc.)
  • Dedicated last-page footer template support
  • Text and image watermarks
  • Modern page-break support (break-*) with compatibility helper CSS
  • Cross-platform runtime support: Windows, macOS, Linux, Docker

Packages

Choose the package set based on your usage style:

  • HubtelPdfGenerator
    Facade package with DI registration (AddHubtelPdfGenerator()).
  • HubtelPdfGenerator.Playwright
    Concrete converter implementation (PlaywrightHtmlToPdfConverter).
  • HubtelPdfGenerator.Abstractions
    Contracts/options (IHtmlToPdfConverter, PdfOptions, etc.).

Target Framework Guidance

The SDK package targets netstandard2.0, so it can be consumed by .NET Core 3.1+ and later .NET versions.

Install from NuGet Feed

Assuming your organization already published the packages to a NuGet feed:

1) Add your feed source

dotnet nuget add source "https://your-feed-url/index.json" --name hubtel-feed

If credentials are required, use your standard feed auth process (PAT, Azure Artifacts credential provider, GitHub Packages token, etc.).

2) Install package(s)

With DI facade:

dotnet add package HubtelPdfGenerator

Or direct implementation:

dotnet add package HubtelPdfGenerator.Playwright
dotnet add package HubtelPdfGenerator.Abstractions

Quick Start

using HubtelPdfGenerator;
using HubtelPdfGenerator.Abstractions;

// Program.cs / Startup.cs
services.AddHubtelPdfGenerator();

Then inject and use:

using HubtelPdfGenerator.Abstractions;

public sealed class ReportService
{
    private readonly IHtmlToPdfConverter _converter;

    public ReportService(IHtmlToPdfConverter converter)
    {
        _converter = converter;
    }

    public async Task<byte[]> RenderAsync(string html, CancellationToken ct)
    {
        var options = new PdfOptions
        {
            Format = "A4",
            PrintBackground = true,
            HeaderFooter = new HeaderFooterOptions
            {
                Enabled = true,
                FooterTemplateHtml =
                    "<div style='font-size:10px;width:100%;text-align:right;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>"
            }
        };

        return await _converter.ConvertHtmlAsync(html, options, ct);
    }
}

Direct usage (no DI)

using HubtelPdfGenerator.Abstractions;
using HubtelPdfGenerator.Playwright;

var converter = new PlaywrightHtmlToPdfConverter();

var options = new PdfOptions
{
    HeaderFooter = new HeaderFooterOptions
    {
        Enabled = true,
        FooterTemplateHtml =
            "<div style='font-size:10px;width:100%;text-align:right;'>Page <span class='pageNumber'></span> / <span class='totalPages'></span></div>"
    },
    Watermark = new WatermarkOptions
    {
        Kind = WatermarkKind.Text,
        Text = "CONFIDENTIAL",
        Opacity = 0.12m,
        RotationDegrees = -30
    }
};

byte[] pdf = await converter.ConvertHtmlAsync("<html><body><h1>Hello PDF</h1></body></html>", options);

API Surface

IHtmlToPdfConverter exposes:

  • ConvertHtmlAsync(string html, PdfOptions options, CancellationToken ct = default)
  • ConvertHtmlAsync(string html, Stream output, PdfOptions options, CancellationToken ct = default)
  • ConvertHtmlAsync(string html, IReadOnlyCollection<HtmlResource> resources, PdfOptions options, CancellationToken ct = default)

Configuration Reference

PdfOptions

  • BaseUrl - base URL for relative asset resolution
  • Format - page format (default A4)
  • Landscape - landscape orientation
  • PrintBackground - include CSS backgrounds
  • Scale - print scale
  • MarginTopInches, MarginRightInches, MarginBottomInches, MarginLeftInches
  • TimeoutMs - render timeout
  • HeaderFooter - header/footer options
  • Watermark - optional watermark configuration
  • AddCompatPageBreakStyles - include compatibility page-break styles (default true)
  • BrowserExecutablePath - custom Chromium path when needed
  • DisableSandbox - Chromium sandbox toggle (use carefully; usually container-specific)

HeaderFooterOptions

  • Enabled
  • HeaderTemplateHtml
  • FooterTemplateHtml
  • LastPageFooterTemplateHtml
  • HeaderVisibility (AllPages, FirstPageOnly, ExcludeFirstPage, LastPageOnly, ExcludeLastPage, None)
  • FooterVisibility (same enum values)
  • ReplaceFooterWithLastPageFooter (default true)
  • UseChromiumDefaultHeaderFooterWhenTemplateMissing
    Set false to suppress Chromium default date/title/url when templates are missing.

Last-page footer behavior:

  • ReplaceFooterWithLastPageFooter = true → last page shows only LastPageFooterTemplateHtml (regular footer is replaced).
  • ReplaceFooterWithLastPageFooter = false → last page can show both the regular footer and LastPageFooterTemplateHtml.
  • Combine with FooterVisibility to choose regular footer visibility (for example AllPages vs ExcludeLastPage).

WatermarkOptions

  • Kind (Text or Image)
  • Text
  • ImageUrl
  • Opacity
  • RotationDegrees
  • FontFamily
  • FontSizePx
  • ColorHex
  • ZIndex
var options = new PdfOptions
{
    HeaderFooter = new HeaderFooterOptions
    {
        Enabled = true,
        HeaderTemplateHtml = "<div style='font-size:9px;width:100%;padding:0 16px;'>My Header</div>",
        FooterTemplateHtml = "<div style='font-size:9px;width:100%;padding:0 16px;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
        LastPageFooterTemplateHtml = "<div style='font-size:9px;width:100%;padding:0 16px;'>Disclaimer text for final page</div>",
        HeaderVisibility = HeaderFooterPageVisibility.FirstPageOnly,
        FooterVisibility = HeaderFooterPageVisibility.ExcludeLastPage,
        ReplaceFooterWithLastPageFooter = true,
        UseChromiumDefaultHeaderFooterWhenTemplateMissing = false
    }
};

Resource Loading (CSS/Images/Fonts)

If HTML contains relative paths, use BaseUrl and/or in-memory resources:

var resources = new[]
{
    new HtmlResource("/styles/report.css", "text/css", File.ReadAllBytes("report.css")),
    new HtmlResource("/images/logo.png", "image/png", File.ReadAllBytes("logo.png"))
};

var options = new PdfOptions { BaseUrl = "https://assets.example.com/" };
byte[] pdf = await converter.ConvertHtmlAsync(html, resources, options);

For maximum reliability in generated headers/footers/watermarks, prefer embedded or absolute assets (for example base64 data URIs).

Page Break Guidance (Important for Large Reports)

Use modern print CSS:

.group { break-inside: avoid; }
.allow-flow { break-inside: auto; }
.new-page { break-before: page; }
thead { display: table-header-group; }
tr { break-inside: avoid; }

PdfOptions.AddCompatPageBreakStyles is enabled by default to improve behavior on older/quirky print engines.

Playwright and Chromium installation (required)

The NuGet packages do not bundle the browser. At runtime, Playwright must find a Chromium build compatible with your installed Microsoft.Playwright version. PDF generation uses headless Chromium (installed via Playwright), not a separate Google Chrome install.

Why two steps?

  1. Browser binaries — downloaded by Playwright into a per-user cache (see below).
  2. Linux system libraries — on many distros, Chromium needs extra packages; Playwright can install them when you use --with-deps.

Prerequisites

  • .NET project that references HubtelPdfGenerator / Microsoft.Playwright, then dotnet build so the Playwright install script is copied to your output folder.
  • PowerShell (pwsh) on macOS and Linux if you use the generated playwright.ps1 (recommended). macOS and many Linux images do not include pwsh by default — see If pwsh is not found below.
  • Alternatively, use the global Playwright CLI (no pwsh required for that path).

If pwsh is not found (macOS / Linux)

The install script playwright.ps1 is PowerShell. If the shell reports command not found: pwsh, pick one of these:

Option A — Install PowerShell (then use the project script)

Option B — Skip pwsh: use the global Playwright CLI

You do not need PowerShell for this path:

dotnet tool install --global Microsoft.Playwright.CLI
playwright install chromium

On Linux, prefer:

playwright install --with-deps chromium

Ensure ~/.dotnet/tools is on your PATH (the installer usually tells you to export it). Then run playwright from the same machine user that will run your app.

From your solution or project directory (the folder that contains your .csproj):

dotnet build

Then run the script under the configuration and target framework you use (examples below — replace net8.0 / Release with yours, e.g. net6.0, net9.0):

macOS — install PowerShell first (once per machine), then run the script:

brew install powershell
pwsh ./bin/Debug/net8.0/playwright.ps1 install chromium

Linux

pwsh ./bin/Debug/net8.0/playwright.ps1 install chromium

For Linux, prefer installing OS dependencies in the same step:

pwsh ./bin/Debug/net8.0/playwright.ps1 install --with-deps chromium

Windows (PowerShell)

pwsh .\bin\Debug\net8.0\playwright.ps1 install chromium

Release output example:

pwsh ./bin/Release/net8.0/playwright.ps1 install --with-deps chromium

This ties the browser build to the same Playwright version your app restored from NuGet.

Alternative: global Playwright CLI

Useful for CI images or when you do not want to invoke playwright.ps1 from output:

dotnet tool install --global Microsoft.Playwright.CLI
playwright install chromium

On Linux, install system dependencies as well:

playwright install --with-deps chromium

The global CLI should be kept roughly in sync with the Microsoft.Playwright package version your app uses.

macOS

  1. Install PowerShell (required for the project script path):

    brew install powershell
    

    Or see If pwsh is not found for alternatives (global CLI, no pwsh).

  2. Build your app (dotnet build).

  3. Install Chromium (pick one):

    Project script (recommended; requires pwsh)

    pwsh ./bin/Debug/net8.0/playwright.ps1 install chromium
    

    Global CLI (no pwsh)

    dotnet tool install --global Microsoft.Playwright.CLI
    playwright install chromium
    
  4. Typical cache location for browser files: ~/Library/Caches/ms-playwright/ (exact path may vary by Playwright version).

Linux

  1. Build your app (dotnet build).

  2. Install Chromium and distro dependencies when possible:

    Project script (recommended)

    pwsh ./bin/Debug/net8.0/playwright.ps1 install --with-deps chromium
    

    Global CLI

    dotnet tool install --global Microsoft.Playwright.CLI
    playwright install --with-deps chromium
    
  3. --with-deps uses Playwright’s dependency installer where supported (e.g. Debian/Ubuntu). On other distros, if installs fail, see Playwright system dependencies and your distro’s package list.

  4. Typical cache location: ~/.cache/ms-playwright/.

  5. Headless Chromium often needs a writable temp directory and font packages for correct rendering; install fonts your PDFs require (e.g. fonts-liberation, or language-specific font packages).

Windows

Project script (recommended)

pwsh .\bin\Debug\net8.0\playwright.ps1 install chromium

If playwright is on PATH (e.g. after global CLI install):

playwright install chromium

Browser cache is usually under %USERPROFILE%\AppData\Local\ms-playwright\.

CI and Docker

  • Run browser install during image build or a one-time setup step, not on every HTTP request.
  • On Linux containers, prefer install --with-deps chromium (see Docker Usage below).

Docker Usage

In containers, install Chromium during image build (not at request time).

Example Debian/Ubuntu-based Dockerfile steps:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app

# Install Playwright browser dependencies + Chromium
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    fonts-liberation \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libc6 \
    libcairo2 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libexpat1 \
    libfontconfig1 \
    libgbm1 \
    libgcc1 \
    libglib2.0-0 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libpango-1.0-0 \
    libpangocairo-1.0-0 \
    libstdc++6 \
    libx11-6 \
    libx11-xcb1 \
    libxcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxext6 \
    libxfixes3 \
    libxrandr2 \
    libxrender1 \
    libxshmfence1 \
    libxss1 \
    libxtst6 \
    wget \
    xdg-utils \
    && rm -rf /var/lib/apt/lists/*

Then (during build or startup script) run:

playwright install --with-deps chromium

If you only copy published app binaries into the image, run the same install from the app directory where playwright.ps1 exists, or install the global CLI in the image and use playwright install --with-deps chromium.

Container notes:

  • Prefer running as non-root with sandbox enabled when possible.
  • If your environment requires it, set PdfOptions.DisableSandbox = true only as a controlled fallback.
  • Install fonts required by your documents (for example CJK, Arabic, corporate fonts).

Fail fast at startup instead of first PDF request:

using HubtelPdfGenerator.Playwright;

await PlaywrightBrowser.ValidateInstalledAsync();

Performance and Reliability Tips

  • Reuse DI singleton converter (AddHubtelPdfGenerator() already does this).
  • Avoid downloading external assets during render when possible.
  • Use absolute URLs, base64 images, or HtmlResource for deterministic outputs.
  • Tune TimeoutMs for large reports.
  • Keep print CSS explicit (table layout, break rules, fixed wrappers where needed).

Security Considerations

  • Treat HTML as untrusted input unless sanitized upstream.
  • Restrict remote asset origins if generating documents in sensitive environments.
  • Be careful with DisableSandbox; only use when your runtime constraints require it.

Troubleshooting

Microsoft.Playwright.PlaywrightException: Executable doesn't exist ...

Chromium is not installed for the current user/machine, or the browser revision does not match your Playwright package version.

Fix: follow Playwright and Chromium installation (required). Quick examples:

macOS / Linux (project output, after dotnet build)

pwsh ./bin/Debug/net8.0/playwright.ps1 install chromium

Linux (with OS deps)

pwsh ./bin/Debug/net8.0/playwright.ps1 install --with-deps chromium

Windows

pwsh .\bin\Debug\net8.0\playwright.ps1 install chromium

Replace net8.0 with your app’s target framework folder name.

command not found: pwsh (macOS / Linux)

Install PowerShell (e.g. on macOS: brew install powershell) or use the global Playwright CLI instead — see If pwsh is not found.

Default date/url/title appears in header/footer

Set:

HeaderFooter = new HeaderFooterOptions
{
    Enabled = true,
    UseChromiumDefaultHeaderFooterWhenTemplateMissing = false
}

Images render as broken placeholders

  • Use absolute URLs or base64 data URIs.
  • Ensure BaseUrl is set when using relative paths.
  • For in-memory resources, pass HtmlResource entries with correct content types.

Layout jumps or clipping around page boundaries

  • Review break-inside rules on wrappers, tables, and rows.
  • Avoid fixed-height wrappers for pageable tables.
  • Keep rows unbreakable and let table/container flow.

Minimal End-to-End Example

var html = """
<!doctype html>
<html>
  <head>
    <style>
      body { font-family: Arial, sans-serif; }
      .section { break-inside: avoid; }
    </style>
  </head>
  <body>
    <h1>Monthly Report</h1>
    <div class="section">...</div>
  </body>
</html>
""";

var options = new PdfOptions
{
    Format = "A4",
    PrintBackground = true,
    MarginTopInches = 0.6m,
    MarginBottomInches = 0.6m,
    HeaderFooter = new HeaderFooterOptions
    {
        Enabled = true,
        FooterTemplateHtml = "<div style='font-size:9px;width:100%;text-align:center;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>"
    }
};

byte[] pdfBytes = await converter.ConvertHtmlAsync(html, options);
await File.WriteAllBytesAsync("report.pdf", pdfBytes);
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on HubtelPdfGenerator.Abstractions:

Package Downloads
HubtelPdfGenerator.Playwright

Playwright-based HTML to PDF implementation for HubtelPdfGenerator.

HubtelPdfGenerator

Facade package and DI registration for Hubtel HTML to PDF SDK.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.6 199 5/8/2026
1.0.0 181 5/4/2026