PeachPDF Documentation

repository·main·Indexed 19 days ago

https://github.com/jhaygood86/peachpdf

A pure .NET 8+ library for rendering HTML, MHTML, and local files into PDF documents without external dependencies like headless browsers. It features support for Flexbox, CSS Math, SVG vector rendering, and Tagged PDF (PDF/UA) output. The library is trimming-safe, Native AOT compatible, and includes a standalone command-line tool and a Blazor WebAssembly demo for client-side rendering.

Tokens
58.5K
Snippets
79
Records
189
Agent score
65%

What's inside PeachPDF

  1. PeachPDF Compatibility and Features

    main

    PeachPDF is a pure .NET library (requires .NET 8+) that renders HTML to PDF without external processes like Puppeteer or wkhtmltopdf.

    Key Features:

    • CSS Support: Flexbox, Multi-column, CSS Math (calc, min, max, clamp), 2D/3D transforms, Gradients, and CSS Custom Properties.
    • Paged Media: @page rules, named pages, margin boxes, and running headers/footers via string-set/string().
    • SVG: Native vector rendering (never rasterized).
    • PDF Output: Supports optional Tagged PDF (PDF/UA) via PdfGenerateConfig.EnableTaggedPdf and automatic metadata extraction from <title> and <meta>.
    • Deployment: Trimming-safe and Native AOT compatible.
  2. Understand the PeachPDF testing strategy

    main

    PeachPDF uses a multi-layered testing approach to ensure rendering accuracy, as PDF token presence does not always guarantee visual correctness. The strategy includes:

    1. Automated xUnit Suite: Over 3,000 tests covering the HTML parser, CSS cascade, layout engines (block, inline, flex, table, multi-column), painting, SVG, fonts, and PDF output.
    2. Continuous Integration (CI): Runs on Windows, Ubuntu, and macOS to catch platform-specific font and text metric issues.
    3. Coverage Gates: Enforces a 90% diff-coverage requirement for new code.
    4. Visual Verification: A manual recommendation to use rasterization-based checks for graphics-state features (masks, gradients, transparency).
    5. Showcase Harness: A tool to visually exercise new capabilities and generate feature showcases.
    6. Benchmarks: Performance regression testing using BenchmarkDotNet.
  3. Identify third-party component licenses in PeachPDF

    main

    PeachPDF is licensed under the BSD 3-Clause license. However, it embeds and adapts several third-party components directly within its source tree. If you are redistributing PeachPDF or its components, you must comply with the specific licenses of these embedded parts:

    • PdfSharpCore (embedded fork): MIT License. Located at src/PeachPDF/PdfSharpCore/.
    • ExCSS (CSS parser, adapted in-tree): MIT License. Located at src/PeachPDF/CSS/.
    • Unicode Character Database (bidi data tables): Unicode License v3. Used for bidirectional text support via Brotli-compressed resources in src/PeachPDF/Text/Resources/Bidi/.
    • Bundled font assets: Licenses vary per font (typically SIL OFL 1.1 or 3-Clause BSD). Note that these fonts are not shipped in the PeachPDF library or NuGet package; they are used for tests and demos.
  4. Overview of the PDF Rendering Pipeline

    main

    The rendering process follows these stages:

    1. Configuration: PdfGenerator initializes a PdfDocument using settings from PdfGenerateConfig (page size, orientation, etc.).
    2. Style Resolution: @page margin overrides are resolved from the stylesheet.
    3. Pipeline Execution: The engine runs the HTML $\rightarrow$ DOM $\rightarrow$ CSS $\rightarrow$ Layout $\rightarrow$ Paint pipeline.
    4. Graphics Translation: The XGraphicsPdfRenderer translates drawing calls into PDF content stream operators, handling the coordinate flip from CSS top-left to PDF bottom-left.
    5. Output: The completed PdfDocument is returned and can be saved to any Stream.
  5. Understand CSS integration in SVG rendering

    main

    PeachPDF supports a full CSS selector engine for styling SVG elements. Styling follows the standard CSS cascade rules with the following precedence (from highest to lowest):

    1. Inline style= attributes: style="fill: red;" on an element.
    2. <style> element rules: Rules defined within a <style> block, matched via selectors.
    3. Presentation attributes: Plain XML attributes like fill="red".

    CSS Selector Engine Capabilities

    The engine supports a wide range of selectors:

    • Type selectors: e.g., rect
    • Class and ID selectors: e.g., .foo, #foo (Note: SVG selectors are case-sensitive).
    • Compound selectors: e.g., rect.foo
    • Combinators: Descendant (g rect), child (.wrap > circle), and sibling combinators.
    • Attribute selectors: e.g., [gradientUnits="userSpaceOnUse"], [data-x^="a"].
    • Structural pseudo-classes: :first-child, :nth-of-type(), :only-of-type, :not(), :empty (where :empty matches elements with no children other than whitespace), and :only-of-type.

    Advanced CSS Features

    • Specificity & Importance: Standard specificity applies, and !important overrides normal declarations.
    • Calculations & Variables: var() custom properties, calc(), min(), max(), and clamp() are fully resolved.
    • @property registrations: Custom properties registered via @property are honored, including initial-value, inherits flags, and syntax validation.
    • CSS-wide keywords: initial, inherit, unset, and revert are supported on SVG paint/geometry properties.

    Inline vs. Standalone SVG Cascading

    • Inline <svg>: Participates in the host document's cascade. Rules in the HTML document's <style> or <link> tags will apply to the SVG shapes.
    • Standalone SVG (e.g., <img src="x.svg"> or data:image/svg+xml): Acts as an independent document. It is only styled by its own internal <style> rules; host-document CSS cannot reach it.
  6. Trimming and Native AOT compatibility

    main

    PeachPDF is designed for modern .NET deployment patterns:

    • Trimming-safe: It sets IsTrimmable to ensure it works with the .NET trimmer.
    • Native AOT-compatible: It sets IsAotCompatible and uses source-generated LibraryImport marshalling instead of reflection-based DllImport. This allows you to publish fully native, self-contained executables using PublishTrimmed or PublishAot without additional configuration.
  7. Understand CSS parsing and rule types

    main

    PeachPDF uses a custom fork of ExCSS integrated directly into the source tree to allow the engine full access to parsed token and rule structures. This enables efficient selector resolution and immediate support for new CSS properties.

    Supported Rule Types

    Parsed stylesheets contain a collection of the following rule types:

    • StyleRule: Regular selector + declaration block
    • MediaRule: @media (wraps child rules)
    • FontFaceRule: @font-face
    • ImportRule: @import
    • ContainerRule: @container
    • KeyframesRule: @keyframes (parsed but not animated)
    • ViewportRule: @viewport
    • DocumentRule: @document
  8. Understand limitations of spanning cells in multi-column layouts

    main

    When using a table inside a multi-column container, there are specific behaviors for spanning cells:

    • No Splitting: A spanning cell is not split across columns; instead, the table's rows are left to the table's own grid rather than being moved against the column flow.
    • Vertical Alignment: The vertical-align property of a spanning cell resolves against the specific fragment on the page where the cell began, rather than against the entire height of the cell. For example, vertical-align: middle will center content within that specific page fragment.
  9. Thread safety in PeachPDF

    main

    PeachPDF is designed for thread safety by using an instance-scoped model.

    • Rule: Do not share a single PdfGenerator instance across multiple threads.
    • Best Practice: Use one PdfGenerator per thread.

    While PdfGenerator is not thread-safe, the underlying process-wide state is protected:

    • System Font Discovery: Scans OS directories once and stores results in immutable structures. Custom fonts registered on one instance cannot mutate the shared system-font data.
    • Global Caches: Process-wide caches (like GlyphTypefaceCache) are guarded by a reentrant monitor (Lock.EnterFontFactory()) to allow concurrent resolution from different generator instances.
  10. Use Multi-column Layouts with CSS

    main

    PeachPDF supports CSS multi-column layouts. You can control the number of columns, their width, and how content is distributed.

    Key behaviors:

    • Column Spanning: Use column-span: all on a direct child of the multi-column container to break the flow. The element will render at the full width of the container, splitting the columns before and after it. Note that this only works on direct children; it has no effect on deeper descendants.
    • Column Filling:
      • column-fill: balance (default): Distributes content evenly across columns using a binary search for minimum height.
      • column-fill: auto: Fills each column to capacity before starting the next.
    • Unbreakable Content: Elements that cannot be fragmented (like <table> or other layout engine containers) will be placed in a column whole. If the element is taller than the column height, the column will grow to accommodate it rather than clipping the overflow.
    • Column Rules: Use column-rule (shorthand for width, style, and color) to render vertical lines between columns.
    .container {
      column-count: 3;
      column-gap: 1em;
      column-rule: 1px solid black;
      column-fill: balance;
    }
    
    .spanning-header {
      column-span: all;
    }
  11. Understand forced break propagation and container behavior

    main

    When using break-before (or legacy page-break-before) or break-after (or legacy page-break-after), the break property propagates outward to the container.

    • Container Movement: If a break is applied to a container's first in-flow child, the break point is treated as being before the container itself. The entire container—including its background, border, padding, and margin—moves to the new page.
    • Propagation Limits: Break propagation stops at the fragmentation context itself or at any box whose children are positioned by a unique layout engine (e.g., flex items, grid items, or table cells).
    • No Empty Fragments: A forced break declared on the very first element of a document will not create a blank page at the start.