Pysar 0.1.63

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

Pysar

Pysar is a report engine for .NET: you describe a paginated document once — in XAML markup or with a fluent C# builder — hand it your data, and get back a vector PDF, a set of bitmap pages, or a scrollable, zoomable view inside your application.

This package is the core: the report element tree, data binding, and the SkiaSharp measurement, pagination, rendering and PDF engine. Add Pysar.Xaml for declarative .rxaml markup and one Pysar.<Platform> package for an in-app report view.

var report = ReportBuilder.Create("Hello report")
    .WithPageFormat(new PageFormat { Margin = new Thickness(30) })
    .WithDetail(detail => detail.AddElement(new Text { Content = "Hello from Pysar" }))
    .Build();

await new SkiaReportRenderer().SavePdfAsync(report, "hello.pdf");

What you get

A report is a vertical stack of bands — report header, page header, detail, page footer, report footer — and the detail band is the one that repeats over your data. Inside a band you compose the usual layout primitives: Grid, StackPanel, Frame, Text, Image, plus Repeater for nested master-detail groups.

  • Two authoring styles, one object model. .rxaml markup (package Pysar.Xaml) for reports with a fixed shape, the fluent builder for reports whose structure is computed at runtime. They produce the same tree and can be mixed.
  • Data binding with {Binding}, string formats, value converters and data triggers for conditional formatting. Bindings resolve once, at build time — a report is a document, not a UI.
  • Real pagination. Detail rows are sliced across pages, detail headers can repeat on every page, page bands are re-resolved per page, and PageNumber / PageCount are available to bindings and to an OnPageChangedAsync hook.
  • Vector PDF output — text stays selectable and sharp at any zoom — plus bitmap page rendering at an arbitrary scale.

Everything is measured in points (1/72"). A4 portrait is 595.5 × 842 pt.

Exporting to PDF

SkiaReportRenderer writes the built report as a vector PDF. Build() must run first; a report can only be built once, so build right before you export:

using Pysar.Export;
using Pysar.Skia;

report.Build();

// straight to a file
await new SkiaReportRenderer().SavePdfAsync(report, "invoice.pdf");

// or onto any stream, e.g. an HTTP response body
await new SkiaReportRenderer().RenderToPdfAsync(report, httpContext.Response.Body);

// or as an in-memory byte array, e.g. to attach to an email
byte[] pdfBytes = await new SkiaReportRenderer().RenderToPdfBytesAsync(report);

// PDF/A-2b document setup. Skia does not validate the file.
await new SkiaReportRenderer().RenderToPdfAsync(
    report, httpContext.Response.Body, new PdfExportOptions { PdfA = true });

Requirements

  • .NET 10 SDK
  • SkiaSharp native assets for the target platform (the platform packages bring the right ones)
  • A platform implementation of IReportPlatformHandler for file and font access — DefaultReportPlatformHandler reads assets from the application directory, and the platform packages install one for their own asset source

A consumer names at most three packages: Pysar always, Pysar.Xaml for reports written in .rxaml markup, and one platform package for the target UI framework.

Package Responsibility
Pysar.Xaml Declarative report markup: the runtime loader and the code-behind source generator
Pysar.Maui .NET MAUI integration: app-package assets, font registration, PDF export and sharing
Pysar.Avalonia Avalonia integration: avares:// assets, font registration and the report view
Pysar.Blazor Blazor integration: the report viewer component, printing through the browser
Pysar.Wpf WPF integration (Windows only): pack/manifest assets, font registration and the report view

Pysar.Viewer — the framework-neutral viewer logic — is not referenced directly; it arrives transitively with a platform package.

One rule worth knowing up front

Report.Build() mutates the report tree: it resolves bindings, expands repeaters and applies triggers. A Report instance can therefore be built once. Create or load a new instance for each document — building the same one twice throws.

Rendering that built instance more than once is supported, but only sequentially (PDF and then page bitmaps, or a retry of the same export). Do not render one instance concurrently. PageNumber and PageCount are scratch written during the pass, and OnPageChanged runs again on every render.

Documentation

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on Pysar:

Package Downloads
Pysar.Viewer

Framework-neutral logic for a paginated report viewer: page geometry, zoom, tile planning and the tile cache.

Pysar.Xaml

Runtime XAML loader for Pysar: parses and constructs report objects from declarative markup.

Pysar.Maui

.NET MAUI integration for Pysar: application-package asset access, font registration, PDF export and sharing.

Pysar.Uno

Uno Platform integration for Pysar: application asset access, font registration, a scrollable, zoomable report view, PDF printing and sharing.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.63 89 10/1/2026
0.1.56 231 9/20/2026
0.1.53 141 9/20/2026
0.1.46 149 9/18/2026
0.1.44 150 9/16/2026
0.1.41 149 9/15/2026
0.1.38 141 9/14/2026
0.1.34 140 9/13/2026
0.1.31 146 9/11/2026
0.1.24 150 9/6/2026
0.1.10 140 8/30/2026
0.1.0 146 8/30/2026

## Avalonia fonts

**Report fonts can come from Avalonia `FontManager`.**
`UsePysar` installs a typeface fallback before your configuration. The family string in the report must be the Avalonia `FontFamily` string — `fonts:Inter#Inter` after `WithInterFont`, or `avares://MyApp/Fonts#Ubuntu` for a resource folder — not a file path. A bare name is a system-font lookup; if `TryGetGlyphTypeface` substitutes Helvetica, Pysar treats that as a miss.

`AddFont` still wins. A library `ReportAsset` still needs one `AddFont`: the file is not copied into the head, and `FontManager` does not see it. A XAML `FontFamily` resource is not a registration. Styles stay `Normal`, `Bold`, `Italic` and `BoldItalic`. This bridge is Avalonia only. Console, the design-time preview, MAUI, WPF and Uno keep `AddFont`.

## PDF export

**PDF/A-2b is an option of PDF, not another format.**
Pass `new PdfExportOptions { PdfA = true }` to `SavePdfAsync`, `RenderToPdfAsync`, `RenderToPdfBytesAsync`, or `IReportExportService.ExportAsync`. Skia writes the archival document setup: XMP `pdfaid` identification, a document UUID, and an sRGB output intent. It does not validate the file. A font Skia cannot embed still fails a checker, and the UUID makes those bytes non-reproducible. Existing overloads are unchanged.

## Images

**SVG is drawn from the bytes, not only from a `.svg` path.**
A stream or embedded source whose bytes start with `<svg` (optional XML declaration) is rendered as SVG. A decode or parse failure is recorded on the image cache, so the same bad bytes are not decoded again. Fixes #23.

## Rendering

**A built report may be rendered more than once, only sequentially.**
PDF and then page bitmaps, or a retry of the same export, is supported. Do not render one instance concurrently. `PageNumber` and `PageCount` are scratch written during the pass, and `OnPageChanged` runs again on every render.

## Uno

**Android report pages no longer depend on OpenGL ES.**
`UsePysar` sets `UseOpenGLOnSkiaAndroid` to false before the window is created. OpenGL ES draws image textures as opaque black, which hid every report page.

## Internal

- Host startup (Avalonia, MAUI, WPF, Uno) shares one installation sequence, `PysarInstallation`.
- `InternalsVisibleTo` for `Pysar.Avalonia` and `Pysar.Avalonia.Tests`.

**Full changelog:** v0.1.56...HEAD