Repository navigation
Releases: MriyaLab/Pysar
Release list
v0.1.63
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. InternalsVisibleToforPysar.AvaloniaandPysar.Avalonia.Tests.
Full changelog: v0.1.56...HEAD
v0.1.56
Zoom & gestures
Trackpad wheel events are now aggregated into a single gesture.
Wheel events are timestamped and grouped using a new WheelGestureGap, and the wheel
anchor in ReportView is kept persistent for the duration of the gesture instead of
being recomputed per event.
Sub-threshold pinch frames are deferred.
GestureModel.PinchByStep / PinchByScale now report whether the change actually
reached the ZoomModel. Small frames are accumulated and only written once they exceed
ZoomStepThreshold. This fixes the visual drift between the model zoom and the rendered
pages during slow pinches.
Added tests covering the accumulation behaviour and confirming that presenter and page
layout do not drift across many sub-threshold frames.
Internal
InternalsVisibleToadded for the WPF test assembly, enabling direct unit tests of
internalPysar.Wpflogic without widening the public API.
Full changelog: v0.1.53...HEAD
v0.1.53
Highlights
ReportAsset — a single way to ship report assets
Fonts, images and other report resources can now be declared once as a
ReportAsset MSBuild item. The build translates it into each host framework's
own item type (MauiAsset, AvaloniaResource, EmbeddedResource, …), and a new
EmbeddedAssetFileSystem reads assets straight from the manifest resources of
assemblies marked with [PysarAssetSource]. This means a shared report library
can carry its own fonts and images, and every host can see them.
A new FallbackFileSystem chains the platform's own asset source ahead of the
embedded one. All five UI platforms (MAUI, WPF, Avalonia, Uno, Blazor) and both
disk-backed DefaultReportPlatformHandler constructors install this chain, so
console apps, workers, server-side rendering and the design-time preview resolve
embedded assets too.
An
IFileSystemyou pass explicitly is not widened — it stays the caller's
whole answer.
Trimming support
Pysar.dll now embeds an ILLink.Descriptors.xml, and Pysar.Xaml ships a
build/Pysar.Xaml.targets that auto-generates an embedded trimmer descriptor for
any project containing .rxaml reports (opt out with PysarDisableTrimmerRoots).
See docs/trimming.md for WebAssembly trimming behaviour.
Avalonia: shared renderer and export
New PysarAvalonia entry point with a shared renderer/export service and proper
reset logic behind AppBuilderExtensions, plus headless Avalonia tests.
Platform layer refactor
Platform-specific handlers are replaced by DefaultReportPlatformHandler backed
by per-platform IFileSystem implementations. Desktop/macOS printing and the
macOS pinch monitor moved into Pysar.Viewer.Platform, and desktop print logic is
centralised in DesktopPdfPrint. Obsolete platform shims were removed.
Performance
ImageRenderCache— a session-scoped cache for image bytes, bitmaps and
SVGs, wired into both the prefetch and draw paths, with failure tracking and
deterministic disposal.- Faster layout —
GridLayoutMeasurer,StackLayoutMeasurer,TextMeasurer
andLayoutEnginewere reworked;BindingEngineandPropertyPathResolver
were optimised. - Removed the
#if DEBUG[Pysar.Perf]zoom instrumentation that logged to the
console in every consumer's Debug build.
Fixes
- Stale pinch-zoom tiles — rapid pinch commits could leave superseded zoom
generations in the tile cache, keeping cells from older scales on screen. Only
the active generation and one bridge generation are kept now. - Touch axis lock —
ReportViewlocks a swipe to its dominant axis, so
scrolling no longer drifts sideways. - WPF printing — the printer now imports the viewer platform namespace it
needs for the print flow.
Authoring and tooling
- XAML source generation: richer binding validation with namespace/name
collection and real diagnostics. - New API surface:
StyleExtensions.WithStyle,AddElementsoverloads on
ReportContainer,PysarBuilder.AddFonts, and a defaultBandheight. - Quick start and the MAUI/Uno/Avalonia READMEs now document
ReportAsset
instead of hand-declared asset items.
Breaking changes
MeasureAsync/ProbeAsyncare now synchronousMeasure/Probe
throughout the layout and rendering pipeline. Custom element measurers and any
code calling the measure API must dropawaitand theTaskreturn type.- Platform handler types removed —
MauiReportPlatformHandler,
WpfReportPlatformHandlerandAvaloniaReportPlatformHandlerare gone; use
DefaultReportPlatformHandler(installed for you byUsePysar/
AddPysar/UsePysar()on the app builder). IImageCache/LocalImageCachelost members superseded byImageRenderCache.PysarWpfandPysar.Avalonia.ReportViewhelper shims were removed.
Tests
~2,000 lines of new test coverage: embedded-asset and fallback file systems,
per-platform asset chains, pinch-commit placement, image-render caching, PDF
print on desktop, trimmer roots and package layout, and binding validation.
v0.1.46
Changed
- Lowered the
Uno.WinUIfloor from 6.7.103 to 6.6.184.Pysar.Unopreviously
demanded a version no app onUno.Sdk 6.6.42could satisfy — the Sdk supplies
6.6.184 itself, making the higher floor a hard resolution failure rather than a
warning.Pysar.Unouses no API newer than 6.6, so the floor now matches. - This is a floor, not a ceiling: consumers on
Uno.Sdk 6.7.30still resolve
6.7.135, and the Uno sample builds against 6.8.0-dev.159 from its own Sdk. HarfBuzzSharpremains at 14.2.1.1 — only its outdated rationale comment was
corrected, sinceSvg.Skia(14.2.0), not Uno, is what drives that version now.
Notes
- Apps blocked on
Uno.WinUI 6.7.103can now stay on Uno 6.6 — or move to
Uno.Sdk 6.7.30, which is published as stable.
v0.1.44
Highlights
Content assets under Assets/
Packaged Uno Content lives under Assets/. Report code still asks for Fonts/, Images/, and Styles/. UsePysarAsync preloads ms-appx:///Assets/... at startup so later reads stay synchronous.
Report sharing
PysarUno.Sharer (UnoReportSharer) offers exported bytes to the host: a file download on WebAssembly, and open/share on desktop, Android, and iOS.
var pdf = await PysarUno.ExportService.ExportAsync(builtReport, ExportFormat.Pdf);
await PysarUno.Sharer.ShareAsync(pdf, "report.pdf");v0.1.41
Highlights
Uno integration: a real entry point
Registering Pysar in an Uno application is now a single call on Application, and it works the same
way from every head (WebAssembly, Desktop, Android, iOS, WinAppSDK) — OnLaunched is the one place
they all run through.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
this.UsePysar(typeof(App).Assembly, pysar => pysar
.AddFont("Fonts/Ubuntu-Regular.ttf", "Ubuntu")
.AddFont("Fonts/Ubuntu-Bold.ttf", "Ubuntu", FontStyle.Bold));
}ApplicationExtensions.UsePysar(...)andUsePysarAsync(...)— the latter preloads
ms-appx:///assets for applications that ship them asContentrather thanEmbeddedResource.assetAssemblyis required: on the WebAssembly head the entry assembly is the head project, not
the application project the assets are packaged into.- Registration moved into
UnoRegistration;PysarUnonow exposesPlatformHandler/
ExportServiceand resets the export service on re-registration.
Ctrl+wheel and trackpad pinch zoom the report, not the page (browser head)
ReportView has always zoomed on Ctrl+wheel and marked the event handled, but on a browser head
that changed nothing visible: "handled" is a managed routing flag, while page zoom is a DOM default
action that only preventDefault on a non-passive listener stops. The reader got a scaled page and
a report that never moved — and the trackpad pinch went with it, since Chrome and Safari deliver it
as a wheel event with ctrlKey set.
UsePysar now installs a small embedded script, imported from a data URL, so a consuming
application adds one call and no files. Opt out with suppressBrowserZoom: false to keep the
browser's own zoom as an accessibility affordance.
Suppression covers the whole Uno canvas: Uno draws the entire application into a single canvas, so
the DOM cannot tell the report from the toolbar beside it. Anything on the page outside that canvas
keeps the browser's zoom.
Measure probe caching
New MeasureContext and LayoutEngine.ProbeSizeAsync cache probe measurements, and
GridLayoutMeasurer / StackLayoutMeasurer now measure through probes instead of re-measuring the
same subtree repeatedly — a large drop in repeat measures on nested layouts.
A readable diagnostic for the SkiaSharp native/managed split on WebAssembly
An Uno browser head pulls SkiaSharp.NativeAssets.WebAssembly through
Uno.WinUI.Runtime.Skia.WebAssembly.Browser, which asks for the 3.119 line, while Pysar renders
through 4.151. NuGet resolves one managed SkiaSharp and one native archive, and the two no longer
agree.
Every other platform reports that split as a startup exception with a message of its own.
WebAssembly links the native side statically at build time, so it surfaces instead as a wall of
wasm-ld: undefined symbol: sk_* lines naming entry points the application never wrote, with
nothing pointing at the version that caused them.
The check now ships as buildTransitive, so it reaches consumers who referenced Pysar.Uno or
Pysar.Blazor rather than Pysar itself — those are the ones who end up on a browser head.
Declaring a dependency on the native package would fix it silently, but it is a 67 MB download
charged to every WPF, console and Uno desktop consumer that will never link a wasm binary.
Breaking changes
PysarUno.Use(...)andPysarUno.UseAsync(...)are removed. UseApplication.UsePysar(...)/
UsePysarAsync(...)instead.
Other
- Docs updated: root
README.md,src/Pysar.Uno/README.md,docs/quick-start.md. - New
AGENTS.md; addedopencode.json. - Tests:
UnoRegistrationTests,MeasureProbeCachingTests, and a newPackageLayoutTests
assertion for thebuildTransitivepayload.
Full Changelog: v0.1.38...v0.1.42
v0.1.38
Added
Pysar.Uno: a new platform package for Uno Platform. Onenet10.0target covers every Uno Skia host - Desktop, WebAssembly, Android and iOS - and it brings the sameReportViewthe other platform packages do: a scrollable, zoomable viewer that rasterises only the visible region, so memory follows the viewport rather than the zoom level. Built against Uno 6.7.PysarUno.Use(assembly, configure)/PysarUno.UseAsync(...)(Pysar.Uno): registration for an Uno application, called fromOnLaunched. A static entry point rather than a service registration, because an Uno application has no service collection of its own unless it also uses Uno.Extensions. Returns the handler, and exposes the sharedPysarUno.RendererandPysarUno.ExportService.UnoReportPlatformHandlerandUnoAssetFileSystem(Pysar.Uno): report assets are read from embedded resources whoseLogicalNameis the path the report asks for. Embedded rather thanms-appx:///because font registration,ResourceDictionarysources and image loading all read synchronously, and blocking on Uno's asynchronousStorageFiledeadlocks the single-threaded WebAssembly host.UnoAssetFileSystem.PreloadAsyncfetchesContent-packaged assets once at startup for applications that would rather keep them that way.UnoReportPrinter(Pysar.Uno): desktop printing through the same vector PDF pipeline as export - the macOS Print panel via PDFKit, the shell print verb on Windows, the default viewer on Linux. Android, iOS and WebAssembly throwPlatformNotSupportedException; produce the bytes throughPysarUno.ExportServiceand share or download them from the application.MacPinchMonitorandMacMagnifyEventArgs(Pysar.Core.Platform, inPysar): an AppKit local event monitor forNSEventTypeMagnify, now public and shared by every host that needs it. No user-interface framework tested surfaces a trackpad pinch as a gesture on macOS - it arrives as plain wheel deltas indistinguishable from a two-finger scroll - so a trackpad zoom has to come from AppKit directly.Start/Stopare no-ops on every other platform.
Changed
MacPinchMonitormoved fromPysar.Avalonia, where it was internal, intoPysar. Behaviour is unchanged for Avalonia applications; the type is simply no longer duplicated per host. It is plain P/Invoke against libobjc with no dependency on any user-interface framework, which is why it belongs besideMacOsPdfPrintin the core package.- HarfBuzzSharp moves from 14.2.0 to 14.2.1.1 across every package, managed wrapper and native assets together. Required by Uno, and applied as a family because a split between the managed wrapper and its native assets is a startup crash rather than a build error.
- Docs: the quick start and README now cover Uno alongside the other platforms, including the two places it deviates - registration is
PysarUno.Userather thanUsePysar/AddPysar, and assets are embedded resources rather than package URIs.
Notes
Pysar.Uno 0.1.35-preview, published earlier to the internal feed, is superseded and should not be used. It required anUno.WinUIprerelease that no releasedUno.Sdkprovides, so no standard Uno application could consume it. This release targets stable Uno 6.7 instead and ships as an ordinary stable package.- The Uno report view has been exercised on macOS Desktop - loading, pagination, zoom modes, and trackpad pinch. Its other hosts (WebAssembly, Android, iOS) build from the same single target but have not yet been run.
v0.1.34
Added
DefaultReportPlatformHandler(Pysar.Skia): a ready-madeIReportPlatformHandlerfor hosts without a UI framework - console and worker applications, server-side rendering, and the design-time preview. Pass a directory to its constructor when assets do not sit next to the binaries.LocalFileSystem(Pysar.Skia): anIFileSystem/ISyncFileSystemthat reads report assets from disk. Relative paths resolve against the application's deployment directory, rooted paths are read as given, and a missing asset reads asnullinstead of throwing.
Fixed
- Asset paths now resolve against
AppContext.BaseDirectoryrather than the executing binary, so images and fonts are found when the assembly is loaded by a host such asdotnet app.dllor the design-time preview.
Changed
- Rounded-border rendering builds its ring path with
SKPathBuilder, matching the current SkiaSharp path API. - Docs: quick start and README now describe
DefaultReportPlatformHandleras the default, with the UI-framework handlers (AvaloniaReportPlatformHandler,WpfReportPlatformHandler,MauiReportPlatformHandler,WasmPlatformHandler) registered byUsePysar/AddPysar.
v0.1.31
Added
- Report watermarks:
Report.Watermark/ReportBuilder.WithWatermark, XAML child, repeats on every page, full physical page,Layer(behind or in front of content),IsVisible. Opacity(0..1) and visualRotation(around bounds center) on report elements.- Rounded frames:
CornerRadius(1 or 4 values). Borders wrap the inner content radius; children clip to the inner arc. - XAML file overlay for unsaved editor buffers during preview/resource load (overlay wins over disk).
Fixed
- MAUI pinch/zoom after Shell flyout navigation (stale recognizers on the old scroll view).
- ReportView gesture lifecycle: detach/reattach on handler changes and
Loaded, so gestures survive navigation.
Changed
- Native libraries: SkiaSharp 4.151.2, Svg.Skia 5.2.3, HarfBuzzSharp + native assets, MAUI / Microsoft.Extensions 10.x.
0.1.24
Fixed
- Print dialogs now use the report’s page size and orientation (Blazor, MAUI, macOS), including landscape and Android media size.
- Blank report after navigation (e.g. Shell flyout): session is recreated when the tile cache was disposed.
- MAUI share on iOS / Mac Catalyst no longer crashes after a successful share.
- Local XAML values (e.g.
FontFamily) are no longer overwritten by implicit styles; styles and bindings now follow value precedence.
Improved
- Faster, smoother scrolling/zoom: tile pooling, coalesced redraws, per-page tile cache, less work per frame.
- Each NuGet package now ships its own README.
Notes
- Sample apps were removed from this repo.