Net4x.HtmlToPdfLibrary 1.0.0.26249

dotnet add package Net4x.HtmlToPdfLibrary --version 1.0.0.26249
                    
NuGet\Install-Package Net4x.HtmlToPdfLibrary -Version 1.0.0.26249
                    
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="Net4x.HtmlToPdfLibrary" Version="1.0.0.26249" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Net4x.HtmlToPdfLibrary" Version="1.0.0.26249" />
                    
Directory.Packages.props
<PackageReference Include="Net4x.HtmlToPdfLibrary" />
                    
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 Net4x.HtmlToPdfLibrary --version 1.0.0.26249
                    
#r "nuget: Net4x.HtmlToPdfLibrary, 1.0.0.26249"
                    
#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 Net4x.HtmlToPdfLibrary@1.0.0.26249
                    
#: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=Net4x.HtmlToPdfLibrary&version=1.0.0.26249
                    
Install as a Cake Addin
#tool nuget:?package=Net4x.HtmlToPdfLibrary&version=1.0.0.26249
                    
Install as a Cake Tool

Net4x.HtmlToPdfLibrary

Turns an HTML document into a PDF, or into an image, by driving the wkhtmltopdf command line tools. It ships the tools, copies them next to your assembly at build time, and finds them at run time without anything being configured. There is also an IHttpHandler that serves the PDF as a file download.

Target frameworks: net35, net40, net6.0-windows, net8.0-windows, net10.0-windows. On the modern targets the System.Web types come from AspNetCore.Web.Base, so the same handler code runs unchanged.

Platform: Windows. The library starts wkhtmltopdf.exe / wkhtmltoimage.exe and can optionally run them as another Windows account.

Install

dotnet add package Net4x.HtmlToPdfLibrary

That is all the setup there is. The package carries wkhtmltopdf 0.11.0 rc2 under tools/, and its build/Net4x.HtmlToPdfLibrary.props copies the two converters and their four dependent DLLs into your output directory on every build, only when they are newer:

bin\Debug\net8.0-windows\
    YourApp.dll
    wkhtmltopdf.exe
    wkhtmltoimage.exe
    libeay32.dll  ssleay32.dll  libgcc_s_dw2-1.dll  mingwm10.dll
Property Default Effect
CopyWkHtmlConvertersToOutputDirectory true Set to false to stop the copy entirely.
WkHtmlConvertersPath the package's tools/wkhtmltopdf/ Point it at your own build of the tools, trailing separator included.
<PropertyGroup>
  <CopyWkHtmlConvertersToOutputDirectory>false</CopyWkHtmlConvertersToOutputDirectory>
</PropertyGroup>

Converting to PDF

using System.IO;
using HtmlToPdfLibrary;

using (var pdf = File.Create(@"C:\reports\invoice.pdf"))
{
    // The converter is found next to your assembly; nothing to configure.
    new HtmlToPdfGenerator().ConvertToPdf("https://example.com/invoices/42", pdf);
}

Rendering to an image

var generator = new HtmlToImageGenerator();          // PNG by default
generator.ImageFormat = HtmlToImageGenerator.JpegFormat;   // or "bmp", "svg", …

using (var image = File.Create(@"C:\reports\invoice.jpg"))
{
    generator.ConvertToImage("https://example.com/invoices/42", image);
}

wkhtmltoimage leaves its standard output in text mode on Windows, which turns every 0x0A in the image into 0x0D 0x0A and corrupts the file. The library renders to a temporary file and copies that out, so what you get back is byte for byte what the tool would have written itself.

Where the converters are looked for

Both generators take the converter directory as an optional argument. When you do not supply one, these directories are searched in order, and the first that holds the executable wins:

  1. the folder holding HtmlToPdfLibrary.dll — bin\ in a web application, the output root elsewhere;
  2. the base directory of the application — the site root for a web application;
  3. a wkhtmltopdf sub folder of 1;
  4. a wkhtmltopdf sub folder of 2 — this is the classic ~/wkhtmltopdf web layout.

If none of them holds it, the name is left to the PATH variable. WkHtmlConverter.GetProbeDirectories() and WkHtmlConverter.FindConverterDirectory("wkhtmltopdf.exe") expose this, which is handy when a deployment cannot find its tools.

To override it, pass the directory explicitly — that always wins over probing:

new HtmlToPdfGenerator().ConvertToPdf(url, pdf, @"C:\tools\wkhtmltopdf");
new HtmlToPdfGenerator().ConvertToPdf(url, pdf, @"C:\tools\wkhtmltopdf", "wkhtmltopdf.exe");

Running as another account

Both generators take a Windows user name and password. The name may be qualified, DOMAIN\user:

new HtmlToPdfGenerator().ConvertToPdf(url, pdf, converterDirectory, null, @"CORP\reporting", secret);

Leaving the user name empty runs the converter as the identity that owns the current process, which is what a normal application pool wants.

Timeouts

TimeoutMilliseconds (one minute by default) bounds the whole conversion, including a converter stuck waiting on a server that never answers. When the deadline passes the converter is killed and a TimeoutException is thrown. Set it to Timeout.Infinite to wait indefinitely.

var generator = new HtmlToPdfGenerator { TimeoutMilliseconds = 15000 };

What can go wrong

Situation Result
url is null or blank, or the stream is not writable ArgumentNullException / ArgumentException
The converter is not in the directory you named FileNotFoundException
The converter never finishes TimeoutException, converter killed
The converter produced nothing at all InvalidOperationException carrying its diagnostics
Writing to your stream failed IOException wrapping the original failure

A converter that reports a recoverable problem — a missing image, say — but still emits a document is not treated as a failure: you get the document it produced.

Serving PDFs over HTTP

HtmlToPdfHandler answers ?url=…&filename=… with the converted document as an attachment.

<system.webServer>
  <handlers>
    <add name="HtmlToPdf" verb="GET" path="htmltopdf.axd"
         type="HtmlToPdfLibrary.HtmlToPdfHandler, HtmlToPdfLibrary" />
  </handlers>
</system.webServer>
GET /htmltopdf.axd?url=https://example.com/invoices/42&filename=Invoice 42
→ 200, application/pdf, Content-Disposition: attachment; filename="invoice-42.pdf"

GET /htmltopdf.axd
→ 400, text/plain, "Please specify a url"

filename is a title, not a path: it is lower-cased invariantly, spaces become single hyphens, anything outside a-z, 0-9 and - is dropped, and the result is capped at 50 characters. A title that leaves nothing usable falls back to converted.

Note: the handler converts whatever url the caller asks for. If it is reachable anonymously, restrict which urls it will accept — override GetDescriptor — before exposing it.

Configuration

All four settings are optional appSettings entries. With none of them present the converter is probed for, which already covers both bin\ and ~/wkhtmltopdf:

Key Default Meaning
HtmlToPdf:ConverterDirectory (probe) Folder holding the converter. Application relative values such as ~/wkhtmltopdf are mapped against the current request; anything else is an absolute path.
HtmlToPdf:ConverterExecutable wkhtmltopdf.exe Converter file name.
HtmlToPdf:UserName (none) Windows account to run the converter as. Absent means the application pool identity.
HtmlToPdf:Password (none) Password for the account above.
<appSettings>
  <add key="HtmlToPdf:ConverterDirectory" value="~/wkhtmltopdf" />
  <add key="HtmlToPdf:UserName" value="CORP\reporting" />
</appSettings>

Extending the handler

Everything worth changing is protected virtual, so a derived handler can take over one piece without reimplementing the rest:

Member Override it to
GetPdfGenerator supply a configured or derived generator
GetDescriptor read the request differently, or restrict which urls are allowed
ConverterDirectory, ConverterExecutable, UserName, Password take the settings from somewhere other than appSettings
ResolveConverterDirectory change how the converter folder is located
WriteToResponse, WriteMissingUrlResponse change the shape of the response
public class ReportPdfHandler : HtmlToPdfHandler
{
    protected override HtmlToPdfGenerator GetPdfGenerator()
    {
        return new HtmlToPdfGenerator { TimeoutMilliseconds = 15000 };
    }

    protected override HtmlDescriptor GetDescriptor(HttpContext context)
    {
        HtmlDescriptor descriptor = base.GetDescriptor(context);
        if (descriptor != null && !descriptor.Url.StartsWith("https://reports.example.com/"))
            return null;

        return descriptor;
    }
}

HtmlToPdfHandler.CreateSafeFileName is public and static, so the same sanitising is available to callers that build their own responses.

Extending the converters

HtmlToPdfGenerator and HtmlToImageGenerator both derive from WkHtmlConverter, which owns the process plumbing. Override BuildArguments to add command line switches, CreateProcess or ApplyCredentials to change how the tool is started, GetExecutablePath to change how it is located, or CreateTemporaryFilePath to render somewhere other than the temp folder.

public class LandscapePdfGenerator : HtmlToPdfGenerator
{
    protected override string BuildArguments(string url, string outputTarget)
    {
        return "--orientation Landscape " + base.BuildArguments(url, outputTarget);
    }
}

License

Copyright © 2013. A License.txt at the repository root is packed with the library when present.

Product Compatible and additional computed target framework versions.
.NET net6.0-windows7.0 is compatible.  net7.0-windows was computed.  net8.0-windows was computed.  net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed.  net10.0-windows7.0 is compatible. 
.NET Framework net35 is compatible.  net40 is compatible.  net403 was computed.  net45 was computed.  net451 was computed.  net452 was computed.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0.26249 102 9/6/2026