JetsonPDF.Fluent 1.1.0

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

JetsonPDF.Fluent

Headless, code-first fluent API for building PDFs on top of JetsonPDF. The shape follows QuestPDF's idiom — FluentDocument.Create(d => d.Page(p => ...)) with a chain of decorators and layout containers — but the implementation is self-contained, has no WPF dependency, and emits PDFs through JetsonPDF.Writer.

using JetsonPDF.Fluent;

FluentDocument.Create(d =>
{
    d.Page(p =>
    {
        p.Size(JetsonPDF.PageSize.Letter);
        p.Margin(50);
        p.Content().Column(col =>
        {
            col.Item().Text("Hello, JetsonPDF.Fluent!", s =>
            {
                s.FontSize = 24;
                s.FontStyle = JetsonPDF.FontStyle.Bold;
            });
            col.Item().PaddingTop(8).Text("A code-first PDF API for .NET.");
        });
    });
}).GeneratePdf("hello.pdf");

Contents


Overview

JetsonPDF.Fluent is the second high-level wrapper around the low-level JetsonPDF.Writer API. The first wrapper, JetsonPDF.Wpf.Authoring, drives PDF generation from a XAML tree and a live WPF layout pass — useful for designer-friendly workflows but tied to STA threads and net8.0-windows. JetsonPDF.Fluent covers the headless / server / console scenario: pure net8.0, no WPF, no STA constraint.

The layout engine is a two-pass MeasureDraw model. Each element reports a SpacePlan of FullRender, PartialRender, Wrap, or Empty; the renderer's pagination loop uses those signals to split content across pages. Stateful containers (Column, Table, multi-line Text) carry a resume cursor that advances on Draw, so a paragraph that overflows page 1 finishes on page 2 from the next unrendered line.

A second whole-document counting pass runs first when the document contains IDynamicComponent instances or page-number placeholders, so Page X of Y labels and dynamic components see the final page count rather than a running estimate.

Quick start

Add a project reference to JetsonPDF.Fluent and a using JetsonPDF.Fluent;. Build a document by calling FluentDocument.Create with a configuration callback, then GeneratePdf(path), GeneratePdf(stream), or the parameterless byte[] GeneratePdf() for in-memory serialization:

using JetsonPDF.Fluent;

FluentDocument.Create(d =>
{
    d.Page(p =>
    {
        p.Size(JetsonPDF.PageSize.A4);
        p.Margin(40);
        p.Content().Text("Hello, A4 world!");
    });
})
.WithMetadata(title: "First Document", author: "You")
.GeneratePdf("first.pdf");

Core concepts

Type Role
Document Top-level builder; carries metadata and the Page blocks.
IDocumentContainer What the FluentDocument.Create callback receives. Has .Page(...).
IPageDescriptor What each .Page(...) callback receives. Configures size/margin and the five page slots (Background, Header, Content, Footer, Foreground).
IContainer The chain anchor. Returned by every decorator method and by descriptor slots (Header(), Content(), Footer(), ColumnDescriptor.Item(), etc.).
TextStyle Family / weight / size / color / line height for text leaves.
FontRegistry Per-document custom font registrations + standard-14 fallback.
Colors Material-style named-color palette plus FromHex.
IDrawingSurface Public escape-hatch handed to Canvas(...). Top-left origin, y-down, points.
IDynamicComponent Per-page user-supplied content with access to IDynamicContext.CurrentPage / TotalPagesEstimate.

The chain idiom: every decorator method returns the next IContainer slot to chain into; every leaf (Text, Image, Column, …) terminates the chain.

container
    .Padding(8)             // returns the inner slot
    .Border(1, Colors.Grey400)
    .Background(Colors.White)
    .Column(col =>          // leaf — chain ends here
    {
        col.Item().Text("inside the box");
    });

Page setup

d.Page(p =>
{
    p.Size(JetsonPDF.PageSize.Letter);   // or .Size(width, height)
    p.Margin(50);                      // .Margin(h, v) for asymmetric
    p.DefaultTextStyle(s => s.FontSize = 11);

    p.Background().Background(Colors.Grey50);  // behind everything
    p.Header()    .Row(r => { /* repeats per page */ });
    p.Content()   .Column(c => { /* auto-paginates */ });
    p.Footer()    .Text("Confidential");        // repeats per page
    p.Foreground().Text("WATERMARK");           // on top of everything
});

Slots are drawn in this z-order on every page: Background → Header → Content → Footer → Foreground. Background and Foreground span the full inner page (margin-aware). Header sits at the top, Footer at the bottom; Content fills the remaining vertical slot and auto-paginates on overflow.

A document can have multiple .Page(...) blocks — each is an independent pagination unit with its own size/margins/slots. Page-number placeholders count across all blocks (a 3-page block followed by a 2-page block sees TotalPages = 5).

Layout containers

Column

Stacks children vertically. Auto-paginates at child boundaries.

container.Column(col =>
{
    col.Spacing(8);                              // gap between items, in points
    col.Item().Text("First");
    col.Item().Padding(4).Border(1).Text("Boxed");
    col.Item().Image(image);
});

Row

Lays out children horizontally with mixed constant- and relative-width slots.

container.Row(row =>
{
    row.Spacing(10);
    row.ConstantItem(80).AlignRight().Text("Date:");
    row.RelativeItem().Text("2026-04-29");        // takes remainder
    row.RelativeItem(weight: 2).Text("Wider half");
});

Row does not paginate — if a child reports Partial or Wrap, the entire row reports Wrap and is pushed to the next page by the surrounding Column.

Stack

Z-stack: children draw on top of each other, all anchored at the slot origin. Reported size is the max of the children's measured sizes.

container.Width(200).Height(100).Stack(s =>
{
    s.Item().Background(Colors.YellowLight);
    s.Item().AlignCenter().AlignMiddle().Text("ON TOP");
});

Inlined

Horizontal flow with row-wrap. Items pack left-to-right at their intrinsic width; when the next item would exceed the slot width, the layout wraps to a new row. Paginates at row boundaries.

container.Inlined(i =>
{
    i.Spacing(6);            // horizontal gap between items in a row
    i.VerticalSpacing(4);    // vertical gap between rows
    foreach (var tag in tags)
    {
        i.Item()
            .Background(Colors.GreenLight)
            .PaddingHorizontal(6).PaddingVertical(2)
            .Text(tag);
    }
});

Grid

Fixed-column flow. Items distribute across N equal-width columns and wrap to the next row.

container.Grid(g =>
{
    g.Columns(3);
    g.Spacing(8);
    g.VerticalSpacing(8);
    foreach (var card in cards)
        g.Item().Border(1).Padding(8).Text(card.Name);
});

Table

Auto-paginating multi-column table with optional header (repeats on each page) and footer (renders only on the last page). Supports column span and row span.

container.Table(t =>
{
    t.ColumnsDefinition(c =>
    {
        c.RelativeColumn(3);     // proportional, weight 3
        c.ConstantColumn(80);    // fixed 80 points
        c.ConstantColumn(60);
    });

    t.Header(h =>
    {
        h.Cell().Text("Item");
        h.Cell().AlignRight().Text("Qty");
        h.Cell().AlignRight().Text("Price");
    });

    foreach (var line in lines)
    {
        t.Cell().Text(line.Name);
        t.Cell().AlignRight().Text(line.Qty.ToString());
        t.Cell().AlignRight().Text($"${line.Price:F2}");
    }

    t.Footer(f =>
    {
        f.Cell(columnSpan: 2).AlignRight().Text("Total");
        f.Cell().AlignRight().Text($"${total:F2}");
    });
});

Column span: t.Cell(columnSpan: 3).Text("banner") widens a cell to cover three columns.

Row span: t.Cell(rowSpan: 2).Text("group label") makes a cell occupy two rows. Auto-flow honours occupancy: subsequent Cell() calls skip the cells reserved by the row-span. Pagination is by atomic blocks — a row-span never splits across pages; if the block doesn't fit on the current page, the entire row-span pushes to the next page.

Decorators

Each decorator wraps the slot's content in a layout transformation. They chain — each returns the new inner IContainer for further chaining.

Padding

container.Padding(10);                      // all sides
container.Padding(horizontal: 12, vertical: 4);
container.PaddingLeft(8);                   // single sides
container.PaddingTop(4).PaddingBottom(4);
container.PaddingHorizontal(12).PaddingVertical(8);

Sizing

container.Width(200).Height(50);
container.MinWidth(100).MaxWidth(300);
container.MinHeight(20).MaxHeight(120);

Width/Height pin the dimension exactly. MinWidth/MinHeight widen the reported size to the floor; MaxWidth/MaxHeight clamp the slot before the child measures.

Alignment

container.AlignLeft();      // FillHorizontal — chooses x within full slot width
container.AlignCenter();
container.AlignRight();
container.AlignTop();       // FillVertical — chooses y within full slot height
container.AlignMiddle();
container.AlignBottom();

A horizontal alignment fills only the horizontal axis (reported width = slot width; height = child height); vertical alignment fills only the vertical axis. Combine by chaining (.AlignRight().AlignMiddle()).

When the slot is unbounded in a dimension (e.g. inside a Table cell measured at unbounded height), the fill flag falls back to the child's natural size — "no slot to fill" rather than "infinite size".

Visual

container.Border(width: 1);
container.Border(width: 2, color: Colors.RedDark);
container.Background(Colors.Grey100);
container.AspectRatio(16.0 / 9.0);                    // FitWidth (default)
container.AspectRatio(1.0, AspectRatioMode.FitArea);  // pick the dim that fits both

Border strokes a rectangle at the slot edge after the child draws. Background fills the slot before the child draws.

Transform

container.Translate(dx: 10, dy: -5);
container.TranslateX(10).TranslateY(-5);
container.Rotate(degrees: 45);     // clockwise about slot center

Translate is a pure draw-time offset — measurement is unaffected, so a translated child's pixels can spill outside the slot. Rotate pivots about the slot's center using PDF CTM; same caveat — the axis-aligned slot stays the same, drawn pixels may extend outside.

Pagination control

col.Item().ShowOnce().Text("Title — only on the first page");
col.Item().SkipOnce().Text("Page numbers, blank on first");
col.Item().ShowEntire().Column(c => { /* never split across pages */ });
col.Item().EnsureSpace(40).Text("Won't render in <40pt of remaining space");
Decorator Behaviour
ShowOnce Renders on the first page where it would render, then Empty thereafter.
SkipOnce Empty on the first page, normal on every page after.
ShowEntire If the child returns Partial, promote to Wrap so the renderer pushes the whole element to the next page.
EnsureSpace(min) If less than min height is available, return Wrap so the element doesn't get orphaned at page bottom.

Content leaves

Leaves terminate the chain (their methods return void).

Text

container.Text("hi");
container.Text("hi", s =>
{
    s.FontFamily = "Helvetica";          // string family — see Fonts
    s.FontSize = 16;
    s.FontStyle = JetsonPDF.FontStyle.Bold;
    s.FontColor = Colors.RedDark;
    s.LineHeight = 1.4;
});

Single-style text. Wraps at word boundaries, paginates at line boundaries.

For multi-style runs (mixed bold/italic, inline page numbers), use the rich text descriptor — see Rich text and page numbers.

Image

container.Image(myImage);                          // fills slot at natural aspect
container.Image(myImage, width: 200, height: 100); // explicit size

myImage is an JetsonPDF.Image (load via Image.FromPng(...) / Image.FromJpeg(...) from JetsonPDF.Writer).

Lines, Placeholders, Canvas

container.LineHorizontal(thickness: 1, color: Colors.Grey300);
container.LineVertical(thickness: 0.5);
container.Placeholder(width: 100, height: 50);   // empty slot — for scaffolding
container.Canvas((surface, w, h) =>
{
    surface.DrawRectangle(0, 0, w, h, fill: Colors.YellowLight);
    surface.DrawText("custom",
        new JetsonPDF.Font(JetsonPDF.FontFamily.Helvetica, 12),
        x: 8, y: 20, color: Colors.Black);
});

Canvas is the escape hatch — if the layout primitives don't cover what you need, draw it directly. Coordinates inside the callback are top-left origin, y-down, in points. The slot's width/height are passed as the second/third parameter.

Shapes and shadows

container.Width(80).Height(40)
    .Ellipse(stroke: Colors.Black, fill: Colors.Yellow);

container.Width(120).Height(60).Polygon(
    points: new (double, double)[] { (60, 0), (120, 60), (0, 60) },
    stroke: Colors.RedDark, fill: Colors.RedLight);

container.Shadow(2, 2, Colors.Grey400)
    .Background(Colors.White).Border(0.5)
    .Padding(10).Text("card with shadow");

.Ellipse(...) inscribes an ellipse in the slot's bounding box. .Polygon(...) takes engine-coord points relative to the slot's top-left; close: true joins the last point back to the first. Both are leaves.

.Shadow(dx, dy, color) paints a flat offset rectangle behind the child (the "card shadow" idiom). Not a Gaussian blur — PDF's blurred-shadow support requires /ExtGState alpha plus a soft-mask form XObject which isn't in the fluent surface. For higher visual polish drop down to JetsonPDF.Writer and emit a soft mask manually.

The IDrawingSurface escape hatch (.Canvas((surface, w, h) => ...)) also gained surface.DrawLine(x1, y1, x2, y2, color), surface.DrawEllipse(cx, cy, rx, ry, ...), and surface.DrawPolygon(points, ...) so custom drawing has the same primitives as the chain leaves.

Rich text and page numbers

Rich text supports multiple styled runs in a single paragraph, with optional inline page-number placeholders. Lines wrap automatically at word boundaries preserving per-run styles.

container.Text(t =>
{
    t.AlignCenter();
    t.Span("Page ");
    t.CurrentPageNumber().Bold();
    t.Span(" of ");
    t.TotalPages().Bold();
});

Per-run styling chains on the descriptor returned by Span/CurrentPageNumber/TotalPages:

container.Text(t =>
{
    t.Span("Hello, ");
    t.Span("world").Bold().FontColor(Colors.RedDark);
    t.Span("!").FontSize(18);
});

Standalone shorthands when you only want a number with no surrounding text:

container.PageNumber();   // 1-based page index
container.TotalPages();   // final document page count

Both placeholders go through the deferred-text mechanism: at measure time they reserve worst-case 6-digit width; the actual digits are stamped after the document has finished laying out so wrapping doesn't shift between pages.

Forms

Form widgets are leaves — they consume the entire slot they land in.

container.Width(200).Height(20).AsTextField("name", tf =>
{
    tf.MaxLength = 50;
    tf.Value = "default";
    tf.IsMultiline = false;
});

container.Width(15).Height(15).AsCheckBox("agree", cb => cb.IsChecked = true);

container.Width(160).Height(18).AsComboBox("region",
    new[] { "NA", "EMEA", "APAC" },
    cb => cb.SelectedValue = "NA");

container.Width(160).Height(60).AsListBox("size",
    new[] { "S", "M", "L" });

container.Width(120).Height(24).AsPushButton("submit", "Send",
    btn => btn.Caption = "Send");

Acrobat / a PDF reader renders the default chrome inside the slot rect. Use .Padding(...) on the parent if you want spacing around the widget.

// External link — wraps content in a clickable region.
container.Link("https://example.com").Text("Visit example.com");

// Internal navigation — declare a destination, then jump to it.
container.Section("intro").Text("Introduction");      // anywhere in the doc
container.SectionLink("intro").Text("Jump to intro"); // clickable rect

Section registers a named destination at the element's top-left position on the page where it draws. SectionLink adds a link annotation that jumps to that destination. Link adds a URL link annotation.

All three can wrap any content — they're decorators, not leaves.

Dynamic components

Per-page custom content with access to the current page number and the final total page count.

public sealed class PageStamp : IDynamicComponent
{
    public void Compose(IDynamicContext ctx)
    {
        ctx.Container.Row(r =>
        {
            r.RelativeItem().Text($"Section {ctx.CurrentPage % 3 + 1}");
            r.RelativeItem().AlignRight()
                .Text($"page {ctx.CurrentPage} of {ctx.TotalPagesEstimate}");
        });
    }
}

// Use it:
p.Footer().Component(new PageStamp());

The component's Compose is invoked once per page. The renderer does a first counting pass through a no-op canvas to learn the final page count, then a second emitting pass with IDynamicContext.TotalPagesEstimate stamped to the final total. So a "Page X of Y" footer rendered via a dynamic component shows the correct Y.

For most "Page X of Y" cases, prefer the rich-text descriptor — it goes through the deferred-text mechanism without rebuilding the content tree per page.

Fonts

TextStyle.FontFamily is a string. The default FontRegistry recognises the standard 14 PDF fonts plus common aliases:

Family string Resolves to
"Helvetica", "Arial" Helvetica
"Times-Roman", "Times Roman", "Times", "Times New Roman" Times Roman
"Courier", "Courier New" Courier
"Symbol" Symbol
"ZapfDingbats", "Zapf Dingbats" ZapfDingbats

Custom TrueType fonts:

FluentDocument.Create(d =>
{
    d.Page(p =>
    {
        p.DefaultTextStyle(s => s.FontFamily = "Inter");
        p.Content().Text("Inter Regular");
    });
})
.WithFonts(reg =>
{
    reg.RegisterFromFile("Inter", JetsonPDF.FontStyle.Regular,
        @"C:\fonts\Inter-Regular.ttf");
    reg.RegisterFromFile("Inter", JetsonPDF.FontStyle.Bold,
        @"C:\fonts\Inter-Bold.ttf");
})
.GeneratePdf("inter.pdf");

If a styled face isn't registered but the Regular face is, the Regular face is used as a fallback (so users can register one weight and keep working). Unknown family names throw by default; swap OnUnknownFamily for a lenient host:

.WithFonts(reg =>
{
    reg.OnUnknownFamily = (family, style) => { /* log + fall back to Helvetica */ };
})

Colors

Colors.Black    // Color.Black (DeviceGray 0)
Colors.White    // Color.White (DeviceGray 1)
Colors.Red      // Material 500
Colors.RedLight // Material 200
Colors.RedDark  // Material 700

Colors.BlueGrey, Colors.Teal, Colors.Indigo, Colors.Amber, ...
Colors.Grey100, Colors.Grey200, ..., Colors.Grey900

Colors.FromHex("#FF0000");
Colors.FromHex("#80FF0000");   // alpha discarded — PDF has no per-color alpha
Colors.FromHex("888");          // expanded to #888888

For colours not in the named palette, use FromHex. For non-RGB spaces (CMYK, CIE-based, Lab, Separation, DeviceN), drop down to JetsonPDF.Color.Cmyk(...) / JetsonPDF.Color.InSpace(...).

Document-level config

Four builders feed catalog entries the layout engine doesn't see directly:

Outline / bookmarks

FluentDocument.Create(d => { /* ... use .Section("intro"), .Section("ch1") etc. */ })
    .WithOutline(o =>
    {
        o.Item("Introduction", "intro").Bold().Expanded();
        o.Item("Chapter 1", "ch1", inner =>
        {
            inner.Item("Section 1.1", "ch1-1");
            inner.Item("Section 1.2", "ch1-2").Italic();
        });
        o.Item("Chapter 2", "ch2");
    })
    .GeneratePdf("out.pdf");

Outline entries reference named destinations registered via .Section(anchor) on a slot. Bold() / Italic() set the entry's display font; Expanded() opens the entry's children when the document opens.

Conformance

doc.WithConformance(JetsonPDF.Conformance.PdfA1b)
   .WithLanguage("en-US")
   .WithOutputIntent(/* OutputIntent for PDF/A */);

PDF/A-1b, PDF/A-2/3 (a/u/b variants), PDF/UA-1, PDF/UA-2 are all available flags. The fluent layer just sets the catalog flag and hands off to JetsonPDF.Writer, which emits the right XMP namespaces and viewer prefs. Conformance is declarative — the writer doesn't refuse non-conforming content; pair with doc.Validate() (on the underlying Document) for checking, or trust your generation code.

Page labels

doc.WithPageLabels(pl =>
{
    // Front matter: i, ii, iii, iv
    pl.Range(0, JetsonPDF.PageLabelStyle.LowerRoman);
    // Body: 1, 2, 3, ...
    pl.Range(4, JetsonPDF.PageLabelStyle.DecimalArabic);
    // Appendix: A-1, A-2, ...
    pl.Range(48, JetsonPDF.PageLabelStyle.DecimalArabic, prefix: "A-");
});

Each .Range(startPageIndex, style, prefix?, startNumber?) overrides viewer display from that page onwards. Page labels are independent of physical page-tree order — they're a viewer-facing string scheme.

Optional content layers (OCG)

var doc = FluentDocument.Create(d =>
{
    d.Page(p =>
    {
        // ...
        p.Content().Layer(designLayer).Text("Visible by default");
        p.Content().Layer(notesLayer).Text("Hidden by default");
    });
});
var designLayer = doc.WithLayer("Design", visibleByDefault: true);
var notesLayer  = doc.WithLayer("Notes",  visibleByDefault: false);
doc.GeneratePdf("out.pdf");

.WithLayer(name [, visibleByDefault, intent]) returns a LayerHandle that slot-chain .Layer(handle) calls reference. Viewers (Acrobat, Foxit, etc.) expose the layers panel so end-users can toggle visibility without regenerating the document. Layers are registered on the Document instance, not via the FluentDocument.Create callback — assign before calling GeneratePdf so the body's .Layer(handle) references resolve.

Limitations

  • Standard 14 fonts use WinAnsi (Windows-1252) encoding. That covers Latin-1 plus the CP1252 extras (, , smart quotes, etc.) but not Unicode arrows (↑↓→←›‹), em dashes outside CP1252, or any non-Latin script. Characters outside WinAnsi render as ? (the WinAnsi notdef glyph). If your text needs them, register a TrueType font with full Unicode coverage:
    FluentDocument.Create(d => { /* ... */ })
        .WithFonts(reg =>
        {
            reg.RegisterFromFile("Inter", JetsonPDF.FontStyle.Regular,
                "Inter-Regular.ttf");
        })
        .WithDefaultTextStyle(s => s.FontFamily = "Inter")
        .GeneratePdf("out.pdf");
    
    Embedded TrueType fonts go through Identity-H composite encoding and carry their own cmap, so any glyph the font supplies is renderable.
  • Rich text rotation: wrapped multi-style paragraphs preserve per-run styles per line, but baseline alignment uses the line's max ascent across styles. Mixed font sizes within a single line align on the larger baseline; substantially different sizes may look top-heavy.
  • Stack and Row don't paginate. A child returning Partial inside a Stack or Row causes the whole container to report Wrap. Wrap your content in Column if you need pagination.
  • Two-pass renderer assumes single-iteration convergence. A dynamic component whose composed size depends on TotalPagesEstimate could in principle produce a different final page count in pass 2 than pass 1. In practice "Page X of Y" components produce identical-shape content, so the count is stable. If you hit a divergence case, route page-number text through the rich text descriptor instead — it uses deferred-text resolution that doesn't re-layout.
  • Form widget appearance uses the PDF reader's default chrome (Acrobat draws its own). Custom appearance streams are an JetsonPDF.Writer feature, not exposed via fluent yet.
  • PDF native alpha isn't surfaced in ColorsColor carries no alpha channel. Translucency requires an /ExtGState on the underlying page (drop down to JetsonPDF.Writer).

Targets

  • net8.0
  • netstandard2.0
  • net462

License

MIT.

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 is compatible.  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 is compatible.  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.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on JetsonPDF.Fluent:

Package Downloads
JetsonPDF.Flow

Word-like retained-mode DOM (Section / Paragraph / Run / Table) with auto-pagination, layered on JetsonPDF.Fluent.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 31 6/6/2026
1.0.0 134 5/23/2026
0.2.0-preview 131 5/23/2026
0.1.0-preview 132 5/17/2026