drawnui/drawnui.net/drawnui-pdf
Claude Code and agent skill by drawnui/drawnui.net
- community
Checking that the SKILL.md file is still in the repository.
Render a DrawnUI layout (XAML or C#) into a PDF, a JPEG/PNG or any Skia canvas without a screen — a report template bound to a view model, measured and drawn by hand, split into real paper pages between table rows. Covers the Pdf helper API, points vs pixels, waiting for async images, the warm-up passes, multi-page export, image export, a desktop preview window with hot reload, and headless server-side rendering with DrawnUi.Net. Trigger on "pdf", "report", "print", "SKDocument", "export to image", "render offscreen", "Pdf.SplitStackToPages".
Install
npx vskill@latest install drawnui/drawnui.net/drawnui-pdfSKILL.md
DrawnUI to PDF
A DrawnUI control does not know where it is drawn. On screen the Canvas measures it, arranges it and hands it a Skia canvas. Hand it a PDF page canvas instead and the same XAML prints. Text, shapes and custom Paint code stay vectors in the PDF, images stay images.
Load drawnui with this skill (and drawnui-fluent when the template is C#). Reference implementation: the RepoReport sample linked from https://taublast.github.io/posts/DrawnPdf/ (Export/ReportExporter.cs, Reports/ReportView.xaml), plus the Sandbox pages src/Maui/Samples/Sandbox/Views/MainPageXaml2Pdf*.xaml.cs in the DrawnUI repo (older, single page and fixed slices). Needs DrawnUi.Maui 1.10.7.1 or newer for correct page splitting (see Pitfalls).
The template
A normal DrawnUI layout in a XAML file with code-behind (or a C# class), like a ContentView:
Rules that differ from a screen:
- No `UseCache` anywhere inside the template. A cached subtree becomes a bitmap in the PDF: text stops being selectable, the file grows. The on-screen instance of the same template may be cached from code (
UseCache = SkiaCacheType.Imageon that instance only). - Root is a Column when the report must break into pages; the table is a templated
SkiaLayout Type="Column"withItemsSource,RecyclingTemplate="Disabled"andMeasureItemsStrategy="MeasureAll": there is no viewport, every row must exist and be measured. - Units are pixels of the chosen dpi,
scale = 1. At 150 dpi a portrait A4 is 1240 x 1753 units andFontSize="19"prints at about 9 pt. Design margins and font sizes for that. - Bindings work as usual, set
BindingContextat export time. Fonts are the ones registered at startup, the Skia PDF backend embeds them. - Images load async (urls, files, map tiles). The template implements a small
IContentReadyAware { bool ContentIsLoaded { get; } }. Decide readiness from STATE, not from counted events: keep theSkiaImageinstances in a list and report ready whenlist.Count >= expected && list.All(i => i.LoadedSource != null || i.HasError || !i.IsLoading). CountingSuccess/Errorevents misses two cases and then the export sits on its timeout: a cached source raisesSuccesssynchronously inside theSourcesetter (before a handler attached after it in an object initializer), and a load cancelled mid-flight (ReloadSource, a secondSourceset) returns without any event. If you do subscribe to events, subscribe before settingSource. For map tiles use the control's own signal (SkiaMapsUi.LoadingChanged). - Custom charts and bars as small
SkiaControlsubclasses overridingPaint(DrawingContext ctx)draw with raw Skia and land in the PDF as paths.
Export, step by step
Warm-up: the first Render starts the async loads, then wait, render again, and keep rendering while something still invalidates. All of it into a throwaway recording, because a PDF canvas keeps every drawing command and Clear only paints over them.
Save to the app cache folder, then Launcher.Default.OpenAsync(new OpenFileRequest(...)) on Windows/Mac, Share.Default.RequestAsync(new ShareFileRequest(...)) on mobile. No storage permission needed for the cache folder.
Pdf helper API (DrawnUi.Infrastructure, every head)
| Member | Meaning | |
|---|---|---|
PaperFormat | A4, A5, A6, Letter, Legal; Custom throws, pass an SKSize instead | |
Pdf.GetPaperSizeInInches(format) | A4 = 8.27 x 11.69 in | |
Pdf.GetPaperSizePixels(format or SKSize inches, dpi) / GetPaperSizePixelsFromMillimeters | paper in pixels at dpi | |
Pdf.SplitStackToPages(control, isTemplated, paper, scale = 1) | page offsets breaking between the children of the first (templated) Column found; a child taller than a page is sliced; needs a prior render at unlimited height; offsets relative to control | |
Pdf.SplitToPages(contentSize, paper) | fixed slices of the paper height, can cut through a row; fallback when there is no stack | |
PdfPagePosition | Index, Position (content offset, apply as ViewportOffsetY = -Position.Y), Height (printable height of that page) |
Image instead of PDF
Same warm-up at the page width, then one render into a surface the size of the content:
Preview window with hot reload (Windows)
Mac Catalyst: Application.OpenWindow needs UIApplicationSceneManifest with UIApplicationSupportsMultipleScenes in Info.plist, and with that manifest a DrawnUI MAUI 10.0.80 app comes up with an empty main window (observed 2026-10-13, cause not found yet). Keep the preview window Windows-only until that is understood.
Open a second Window with a BasePageReloadable page holding Canvas > SkiaScroll > factory(). The factory builds a fresh template on every hot reload, the window is sized to the paper proportions (inches * Dpi * 0.75 fits most screens). Position it next to the main window with Application.Current.Windows[0].X + Width + 20, open with Application.Current.OpenWindow(window).
Pitfalls
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingdocs/skills/drawnui-pdf/SKILL.md
Popularity
- Repository stars
- 409
- Repository forks
- 39
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/drawnui/drawnui.net/drawnui-pdf)