Skip to content

DevNamedZed/rend

Repository files navigation

Rend

Rend is an HTML/CSS rendering engine for .NET. It parses HTML, resolves CSS, computes layout, and renders the result to PDF or images.

It implements the rendering pipeline itself: HTML5 parsing, CSS cascade and inheritance, block/inline/flex/grid/table layout, text shaping with HarfBuzz, and painting through pluggable backends. It does not rely on a browser, WebView, or external rendering engine.

Playground | Visual Regression Report

Quick Start

using Rend;

using var pdfOutput = File.Create("report.pdf");
Render.ToPdf(html, pdfOutput);

using var imageOutput = File.Create("report.png");
Render.ToImage(html, imageOutput);

Async

await Render.ToPdfAsync(html, outputStream, cancellationToken: ct);

Render Options

var options = new RenderOptions
{
    PageSize = PageSize.Letter,
    MarginTop = 48f,
    MarginRight = 48f,
    MarginBottom = 48f,
    MarginLeft = 48f,
    Title = "Invoice #1234",
    Author = "Acme Corp",
    HeaderHtml = "<div style='font-size:10px;text-align:center'>Page {pageNumber} of {totalPages}</div>",
    FooterHtml = "<div style='font-size:9px;text-align:right'>{date}</div>",
};

Render.ToPdf(html, output, options);

PDF Options

using Rend.Pdf;

var options = new RenderOptions
{
    PdfOptions = new PdfDocumentOptions
    {
        FontEmbedMode = FontEmbedMode.Subset, // Subset (default), Full, or None
        Compression = PdfCompression.FlateFast, // FlateFast (default), Flate, FlateOptimal, or None
    }
};

Render.ToPdf(html, output, options);

Font embed modes:

Mode Speed File Size Use Case
Subset Default Smallest Production documents with correct fonts
Full Faster Larger Skip subsetting when file size doesn't matter
None Fastest Smallest Maximum throughput, renders in Helvetica

Image Output

var options = new RenderOptions
{
    ImageFormat = ImageOutputFormat.Jpeg, // Png, Jpeg, Webp
    ImageQuality = 85,
    Dpi = 150f,
};

Render.ToImage(html, output, options);

Custom Fonts

var fonts = new FontCollection();
fonts.RegisterFromResolver(new SystemFontResolver());
fonts.RegisterFontDirectory("/path/to/fonts");

var options = new RenderOptions
{
    FontProvider = fonts
};

Custom Image Resolver

Use a custom resolver to control how images are loaded for <img>, background-image, border-image, and list-style-image.

public class S3ImageResolver : IImageResolver
{
    public async Task<Stream?> ResolveAsync(string url, CancellationToken cancellationToken = default)
    {
        return await _s3Client.GetObjectStreamAsync(url, cancellationToken);
    }
}

var options = new RenderOptions
{
    ImageResolver = new S3ImageResolver()
};

await Render.ToPdfAsync(html, output, options);

Progress Reporting

var progress = new Progress<RenderProgress>(p =>
    Console.WriteLine($"[{p.Percentage}%] {p.Stage}: {p.Description}"));

Render.ToPdf(html, output, new RenderOptions
{
    Progress = progress
});

PDF Digital Signatures

Sign any PDF using a local certificate or an external signer. Works with any PDF, not just ones generated by Rend.

using Rend.Pdf;

var signer = new Pkcs12Signer(File.ReadAllBytes("cert.pfx"), "password");

using var input = File.OpenRead("document.pdf");
using var output = File.Create("signed.pdf");

await PdfSigning.SignAsync(input, output, new PdfSignatureOptions
{
    Signer = signer,
    SignerName = "John Doe",
    Reason = "Approved",
    Location = "New York",
});

For HSM or cloud KMS scenarios where the private key is not directly accessible, implement IPdfSigner:

public class AzureKeyVaultSigner : IPdfSigner
{
    public int EstimatedSignatureSize => 8192;

    public async Task<byte[]> SignAsync(byte[] data, CancellationToken cancellationToken = default)
    {
        return await _keyVaultClient.SignCmsAsync(data, cancellationToken);
    }
}

await PdfSigning.SignAsync(input, output, new PdfSignatureOptions
{
    Signer = new AzureKeyVaultSigner(),
});

There is also a convenience overload for simple cases:

var cert = new X509Certificate2("cert.pfx", "password");
await PdfSigning.SignAsync(input, output, cert);

For DI, use IPdfSigningService and PdfSigningService:

services.AddSingleton<IPdfSigningService, PdfSigningService>();

PDF Overlays

Draw text and images onto specific positions on existing PDF pages. Useful for filling form fields, adding signatures, or placing watermarks.

using Rend.Pdf;

using var input = File.OpenRead("template.pdf");
using var output = File.Create("filled.pdf");

await PdfOverlays.ApplyAsync(input, output, new PdfOverlayElement[]
{
    new TextOverlay
    {
        Page = 1,
        X = 100,
        Y = 200,
        Text = "John Doe",
        FontSize = 14,
        FontFamily = "Helvetica",
    },
    new ImageOverlay
    {
        Page = 1,
        X = 100,
        Y = 500,
        Width = 200,
        Height = 80,
        Data = File.ReadAllBytes("signature.png"),
    },
});

Coordinates use top-left origin. Supports Helvetica, Times, and Courier font families with bold and italic variants. JPEG and PNG image formats are supported.

For DI, use IPdfOverlay and PdfOverlay:

services.AddSingleton<IPdfOverlay, PdfOverlay>();

Standalone PDF Writer

Rend.Pdf can be used independently of the HTML/CSS renderer.

using Rend.Pdf;

var doc = new PdfDocument();
var page = doc.AddPage(595.28f, 841.89f);
var font = doc.AddFont(fontData);

var cs = page.ContentStream;
cs.BeginText();
cs.SetFont(font, 12f);
cs.SetTextPosition(72f, 750f);
cs.ShowText(font.Encode("Hello from Rend.Pdf!"));
cs.EndText();

using var stream = File.Create("output.pdf");
doc.Save(stream);

Features

Layout

  • Block, inline, and inline-block formatting contexts
  • Flexbox, including wrapping, alignment, gap, order, and flex grow/shrink
  • CSS Grid, including auto-placement, fr, minmax(), repeat(), auto-fill/fit, named lines/areas, and subgrid
  • Table layout, including fixed and auto layout, rowspan/colspan, and border-collapse
  • Positioned elements: relative, absolute, fixed, and sticky
  • Floats and clear
  • Multi-column layout
  • Pagination with page breaks, widows, and orphans

CSS

  • Cascade, specificity, and inheritance
  • calc(), var(), and custom properties
  • @media, @font-face, @import, @page, and @supports
  • CSS Color Level 4
  • Shorthand expansion

Rendering

  • Backgrounds: solid colors, gradients, images, and multiple backgrounds
  • Borders, border radius, and border images
  • Box shadows and text shadows
  • Transforms, opacity, filters, and clip paths
  • Linear, radial, and conic gradients
  • SVG rendering
  • text-overflow: ellipsis

Text

  • HarfBuzz text shaping
  • Unicode line and word breaking
  • Bidirectional text
  • White-space handling, text transforms, and letter/word spacing
  • Font fallback chains
  • WOFF and WOFF2 support
  • System font discovery

PDF Output

  • PDF 1.4–1.7 writer with TrueType and CFF/OpenType font subsetting
  • Configurable font embedding: Subset (used glyphs only), Full, or None (Standard14)
  • Bookmarks, clickable links, and document metadata
  • AcroForms: text fields, checkboxes, and dropdowns
  • Digital signatures using local PKCS#12 certificates or external IPdfSigner implementations
  • Content overlays: draw text and images onto existing PDFs
  • Encryption: RC4-128 and AES-128
  • PDF/A conformance (A1b, A2b, A3b) with ICC output intents
  • Linearization for fast web view
  • Object streams and cross-reference streams (PDF 1.5+)
  • ICC color profiles and XMP metadata

Image Output

  • PNG, JPEG, and WebP via SkiaSharp
  • Configurable DPI

Performance

Measured with BenchmarkDotNet on .NET 8, warm font provider.

Test Time Memory
Simple HTML 1.17 ms 498 KB
Styled HTML 1.27 ms 748 KB
Images 1.42 ms 912 KB
50 Lines 1.56 ms 1.3 MB
Table (50 rows) 7.86 ms 4.7 MB

With FontEmbedMode.None (Standard14 Helvetica): 126 µs for Simple HTML.

See docs/performance.md for details.

Dependency Injection

Every static API has a corresponding interface and implementation class for DI and testing.

services.AddSingleton<IRenderer, HtmlRenderer>();
services.AddSingleton<IPdfSigningService, PdfSigningService>();
services.AddSingleton<IPdfOverlay, PdfOverlay>();

Architecture

HTML string
     |
     v
[ HTML Parser ]
     |
     v
[ CSS Parser ]
     |
     v
[ Style Resolution ]
     |
     v
[ Layout Engine ]
     |
     v
[ Painter ]
     |
     +---------+---------+
     |                   |
     v                   v
[ PDF Target ]    [ Skia Target ]
     |                   |
     v                   v
  PDF bytes        Image bytes

Projects

Project Description
Rend.Core Shared types such as geometry, color, and units
Rend.Html HTML5 parser, DOM, and selector engine
Rend.Css CSS parser, cascade, and style resolution
Rend.Pdf Standalone PDF writer, signing, and overlay support
Rend Layout engine, rendering pipeline, text shaping, and public API

All projects target netstandard2.0 (.NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+).

Playground

The Playground runs Rend entirely in the browser via Blazor WebAssembly. Type HTML/CSS in the editor, hit Render, and see the PDF output instantly. No server required.

Visual Regression

Rend is tested against Chrome using a pixel-level comparison suite of 871 test cases covering layout, typography, gradients, shadows, tables, forms, and more.

The latest report shows Chrome vs Rend screenshots with diff overlays for every test.

Run the suite locally:

just visual            # run all tests
just visual-filter foo # run tests matching "foo"
just visual-update     # run and update checked-in results
just report            # open the report

Results are saved to conformance/results/ for check-in.

Building

Requires the .NET 8 SDK.

dotnet build Rend.sln
dotnet test Rend.sln

Benchmarks

dotnet run -c Release --project benchmarks/Rend.Benchmarks -- --filter "*"

Run a specific benchmark class:

dotnet run -c Release --project benchmarks/Rend.Benchmarks -- --filter "*RenderBenchmarks*"

License

MIT

About

A .NET HTML/CSS rendering engine that converts HTML documents to PDF and images. Supports CSS3 layout (Flexbox, Grid, Tables, Multi-column), text shaping via HarfBuzz, and Skia-based output.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages