↔DINKTOPDF ALTERNATIVE · C# · .NET

A DinkToPdf alternative that keeps your code.

wkhtmltopdf is archived, and DinkToPdf hasn't had a release since 2017. SelectPdf.Compat.DinkToPdf keeps the DinkToPdf API, so your converter code builds as it is, and renders with Chromium instead of Qt WebKit.

Free for commercial use · up to 5 pages per document · MIT licensed

terminal
dotnet remove package DinkToPdf
dotnet add package SelectPdf.Compat.DinkToPdf
dotnet add package SelectPdf.Universal.Native.linux-x64

Swap the package, add the engine for your platform. Your code stays as it is.

§WHY MOVE

Why move off DinkToPdf.

  • wkhtmltopdf, the engine under DinkToPdf, is no longer maintained: its GitHub repository is archived, and its last release, 0.12.6, dates from June 2020. Source
  • DinkToPdf's last NuGet release, 1.0.8, is from April 2017. Source
  • wkhtmltopdf renders with an old Qt WebKit, so flexbox, grid and current JavaScript don't work, and layouts have to work around it.
  • You ship and load the native libwkhtmltox library yourself, one file per platform, plus the system packages it needs on Linux.
§MIGRATE

Migrate in three steps.

  1. 1Swap the package

    terminal
    dotnet remove package DinkToPdf
    dotnet add package SelectPdf.Compat.DinkToPdf
  2. 2Add the engine for your platform

    Add SelectPdf.Universal.Native.<rid>, where <rid> is win-x64, win-x86, linux-x64, linux-arm64 or osx-arm64. Reference one engine package per build, because they all install into the same folder.

    terminal
    dotnet add package SelectPdf.Universal.Native.linux-x64

    A project developed on Windows and deployed to a Linux container can pick the engine by platform in the project file:

    YourApp.csproj
    <PropertyGroup>
      <SelectPdfRid>$(RuntimeIdentifier)</SelectPdfRid>
      <SelectPdfRid Condition="'$(SelectPdfRid)' == '' And
          $([MSBuild]::IsOSPlatform('Windows'))">win-x64</SelectPdfRid>
      <SelectPdfRid Condition="'$(SelectPdfRid)' == ''">linux-x64</SelectPdfRid>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="SelectPdf.Universal.Native.$(SelectPdfRid)"
                        Version="26.5.0" />
    </ItemGroup>
  3. 3Delete the native wkhtmltopdf files

    Remove the libwkhtmltox files from your project and the CustomAssemblyLoadContext code that loaded them. Your converter code stays as it is:

    Your existing code
    using DinkToPdf;
    using DinkToPdf.Contracts;
    
    services.AddSingleton(typeof(IConverter),
        new SynchronizedConverter(new PdfTools()));
    
    byte[] pdf = converter.Convert(new HtmlToPdfDocument
    {
        GlobalSettings =
        {
            PaperSize = PaperKind.A4,
            Orientation = Orientation.Portrait,
            Margins = new MarginSettings { Top = 10 }
        },
        Objects =
        {
            new ObjectSettings
            {
                HtmlContent = html,
                FooterSettings = { Center = "Page [page] of [toPage]" }
            }
        }
    });
§SETTINGS

How DinkToPdf settings map.

Your settings are translated into SelectPdf's. Settings with no equivalent, such as Copies, DPI and MinimumFontSize, are ignored, and each one raises the Warning event so you can see it.

DinkToPdfSelectPdf
PaperSize and OrientationThe exact page size in points
Margins (mm, cm or in)Margins in points; 10 mm on each side by default, as in wkhtmltopdf
HeaderSettings / FooterSettings text, font, line and spacingText sections placed inside the margin, where wkhtmltopdf placed them
[page], [topage], [date], [title] and the other variablesPage number, page count or the value itself (case-insensitive, so [toPage] works)
ObjectSettings.Page / HtmlContentConverting a URL or local file / an HTML string
Several ObjectsOne PDF with page breaks between them; page numbering runs across all of them
EnableIntelligentShrinking, ZoomFactorThe scale of the content, as wkhtmltopdf applied it
PrintMediaType, EnableJavascript, Background, UserStyleSheetCSS media type, JavaScript, backgrounds, custom CSS
Username/Password, JSDelay, Proxy, CustomHeaders, CookiesHTTP authentication, conversion delay (rounded up to whole seconds), proxy, headers, cookies
Outline, DocumentTitle, ColorMode.GrayscaleBookmarks from the headings, document title, grayscale output
PhaseChanged, ProgressChanged, Finished, Error, WarningRaised at the same points as before

The full list is in the package README.

§WHAT CHANGES

What behaves differently.

CSS sizes are scaled the way wkhtmltopdf's smart shrinking scaled them, so existing templates keep their size. A few things do change:

The engine

Chromium lays pages out like a current browser. Layouts that worked around WebKit's missing flexbox and grid now render as written, and text metrics differ slightly. Control page breaks with CSS break-before, break-after and break-inside: avoid.

Wide content

With smart shrinking turned off, content wider than the page is shrunk to fit instead of being cut at the right edge.

HTML header and footer URLs

They no longer receive wkhtmltopdf's ?page= and ?topage= parameters. Use text headers and footers for page numbers.

Several objects

The first object's header, footer and web settings apply to the whole document.

Concurrency

SynchronizedConverter no longer runs every conversion on one thread. SelectPdf converts in parallel, so a singleton converter serves concurrent requests.

Failures

A failed conversion returns an empty array and raises Error, as before. Set SelectPdfCompat.ThrowOnError = true to throw instead.

§LINUX AND DOCKER

Run it on Linux and in Docker.

The engine package bundles the Chromium libraries, so the image is built from the official .NET images with no apt-get lines:

Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "YourApp.dll"]

Linux needs glibc 2.30 or later (Debian 11+, Ubuntu 20.04+, RHEL 9+), which the official .NET images have. For ARM64 hosts, use SelectPdf.Universal.Native.linux-arm64. Linux images often have no fonts installed: the engine has built-in fonts for Latin scripts, and SelectPdf.Universal.Fonts adds every other script.

§FREE OR LICENSED

Free up to 5 pages, then licensed.

The free package renders through the SelectPdf Community Edition. The .Licensed package is the same code on SelectPdf.Universal, so moving up means changing the package reference.

SelectPdf.Compat.DinkToPdfSelectPdf.Compat.DinkToPdf.Licensed
PriceFree for commercial useNeeds a SelectPdf license
Pages per documentUp to 5. A longer document throws an error that says how many pages it hadNo limit
Several objects with a URL among themNot supported (needs PDF merging)Converted one by one and merged
Your codeIdenticalIdentical

To accept the first 5 pages of a longer document instead of an error, set SelectPdfCompat.FailOnPageLimit = false; the Warning event then reports the cut.

§WKHTMLTOPDFDOTNET

Using WkHtmlToPdfDotNet instead?

There is a package for Haukcode.WkHtmlToPdfDotNet too, with its WkHtmlToPdfDotNet namespace and its extra members such as CoverSettings. The steps are the same, and the apt-get lines its Dockerfile needed can go:

terminal
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet add package SelectPdf.Compat.WkHtmlToPdfDotNet
dotnet add package SelectPdf.Universal.Native.linux-x64
?FAQ

Questions, answered.

Something else? Write to support@selectpdf.com with your settings and, if you can, the HTML.

No. The SelectPdf engine package replaces it. Delete the libwkhtmltox.dll, .so and .dylib files from your project, and the CustomAssemblyLoadContext code that loaded them.
No. SelectPdf.Compat.DinkToPdf uses DinkToPdf's own namespace and types (IConverter, SynchronizedConverter, HtmlToPdfDocument, GlobalSettings, ObjectSettings), so the code builds as it is. You change the package references and remove the native files.
Yes, for documents up to 5 pages. A longer document throws an InvalidOperationException that says how many pages it had, so a cut PDF never reaches your users unnoticed. SelectPdf.Compat.DinkToPdf.Licensed is the same code on the licensed SelectPdf.Universal library, with no page limit.
Text headers and footers do, with [page], [topage] and the other wkhtmltopdf variables. HTML header and footer URLs still work, but they no longer receive wkhtmltopdf's ?page= and ?topage= parameters, so use text headers for page numbers.
Not with the engine packages: they need glibc 2.30 or later, and Alpine uses musl. Use the official Debian- or Ubuntu-based .NET images, which need no extra packages.
Yes. SelectPdfCompat.Configure receives the SelectPdf converter after your DinkToPdf settings are applied, so you can set any other SelectPdf option on it before each conversion.