PdfScriptCompiler 2.2.0
dotnet add package PdfScriptCompiler --version 2.2.0
NuGet\Install-Package PdfScriptCompiler -Version 2.2.0
<PackageReference Include="PdfScriptCompiler" Version="2.2.0" />
<PackageVersion Include="PdfScriptCompiler" Version="2.2.0" />
<PackageReference Include="PdfScriptCompiler" />
paket add PdfScriptCompiler --version 2.2.0
#r "nuget: PdfScriptCompiler, 2.2.0"
#:package PdfScriptCompiler@2.2.0
#addin nuget:?package=PdfScriptCompiler&version=2.2.0
#tool nuget:?package=PdfScriptCompiler&version=2.2.0
PdfScriptCompiler
Zero-dependency .NET 8 PDF compiler. Write plain markup or use the fluent C# API to generate real PDF binaries — no Word, no LaTeX, no third-party packages.
byte[] pdf = PdfScriptCompiler.Compile("""
@page a4
@title "Hello World"
# Hello from PdfScriptCompiler
Generate PDFs with **zero dependencies** in pure C#.
""");
Table of Contents
- Installation
- Quick Start
- Method 1 — PDFScript Markup Language
- Method 2 — Fluent C# API
- Method 3 — Compile from String
- Method 4 — Compile from File
- Method 5 — Compile to Stream
- Encryption
- Watermarks
- Colors
- Page Sizes and Margins
- ASP.NET Core Integration
Installation
dotnet add package PdfScriptCompiler
Or in your .csproj:
<PackageReference Include="PdfScriptCompiler" Version="2.2.0" />
Requirements: .NET 8 or later. No other dependencies.
Quick Start
using PdfScript;
using PdfScript.Core;
// 1. From markup string
byte[] pdf = PdfScriptCompiler.Compile("""
@page a4
@title "My Report"
# Sales Report
Revenue grew by **42%** this quarter.
""");
File.WriteAllBytes("report.pdf", pdf);
// 2. From a .pdfs file
PdfScriptCompiler.CompileFile("report.pdfs", "report.pdf");
// 3. To a stream (ASP.NET Core response, memory, etc.)
PdfScriptCompiler.CompileToStream(source, Response.Body);
// 4. Fluent builder API
byte[] pdf2 = new PdfDocumentBuilder()
.SetTitle("Invoice #1001")
.AddHeading("Invoice #1001", 1)
.AddTable(t => t
.AddColumn(ColSpec.Star())
.AddColumn(ColSpec.Fixed(80))
.SetHeader("Item", "Amount")
.AddRow("Consulting", "$1,200")
.AddRow("Hosting", "$80")
.SetFooter(["Total", "$1,280"])
)
.Build();
Method 1 — PDFScript Markup Language
PDFScript is a lightweight plain-text format (.pdfs files) that compiles directly to PDF. It is designed to be readable as-is and writable by hand or by template engines.
Document Directives
Directives start with @ and must appear before any content.
| Directive | Syntax | Description |
|---|---|---|
@page |
@page a4 |
Page size: a4 letter a5 legal a3 |
@orientation |
@orientation landscape |
landscape or portrait (default) |
@margin |
@margin 60 50 60 50 |
Top Right Bottom Left in pt. Also accepts 1 value (all sides) or 2 values (vertical horizontal) |
@title |
@title "My Document" |
PDF metadata: document title |
@author |
@author "Jane Doe" |
PDF metadata: author |
@subject |
@subject "Q1 Report" |
PDF metadata: subject |
@keywords |
@keywords "pdf report" |
PDF metadata: keywords |
@encrypt |
@encrypt userpwd="open" ownerpwd="admin" permissions=all |
Password-protect the PDF |
@watermark |
@watermark text="DRAFT" opacity=0.12 angle=45 |
Diagonal watermark on every page |
Example — full document header:
@page a4
@orientation portrait
@margin 60 50 60 50
@title "Quarterly Report"
@author "Finance Team"
@subject "Q1 2026 Results"
@keywords "finance quarterly pdf"
@encrypt userpwd="open123" ownerpwd="admin456" permissions=all
@watermark text="CONFIDENTIAL" opacity=0.10 angle=45
Headings
# H1 — largest heading
## H2 — section heading
### H3 — sub-section heading
#### H4 — smallest heading
Paragraphs and Inline Styles
Any line that is not a directive or block element is a paragraph.
| Syntax | Result |
|---|---|
**text** |
Bold |
*text* |
Italic |
***text*** |
Bold-Italic |
`text` |
Monospace |
[color=#ff0000]text[/color] |
Colored text |
->text<- |
Centered paragraph |
->text |
Right-aligned paragraph |
Example:
This paragraph has **bold**, *italic*, ***bold-italic***, and `mono` text.
Here is [color=#cc0000]red[/color] and [color=#0055cc]blue[/color] inline.
->This paragraph is centered.<-
->This paragraph is right-aligned.
Comments — lines starting with // are ignored:
// This line will not appear in the PDF
Tables
.table [options]
| Header A | Header B | Header C |
| row data | row data | row data |
.end
Table options:
| Option | Default | Description |
|---|---|---|
cols="spec" |
equal star | Column width specification (see below) |
rowh=22 |
18 |
Minimum row height in pt |
fontsize=9 |
9 |
Font size for all cell text |
padding=5 |
5 |
Cell padding in pt |
headerbg=#hex |
#1a2a5a |
Header row background colour |
headerfg=#hex |
#ffffff |
Header row text colour |
evenbg=#hex |
#f5f5f5 |
Even data row background colour |
bordercol=#hex |
#b8b8b8 |
Border and divider colour |
Column width specification (cols):
Specify widths as a space-separated list inside quotes:
| Token | Meaning | Example |
|---|---|---|
120 |
Fixed width in pt | cols="60 120 80" |
* |
Fill remaining space, weight 1 | cols="auto * *" |
*2 |
Fill remaining space, weight 2 | cols="60 * *2" |
auto |
Auto-fit to header text width | cols="auto auto *" |
// 3-column: auto ID, flexible description, fixed 80pt price
.table cols="auto * 80" fontsize=9 headerbg=#1a3a6b headerfg=#ffffff evenbg=#eef3ff
| Product | Description | :Price: |
| PDF Builder | Full-featured PDF engine | :$499: |
| Support Bundle | 12-month priority support | :$199: |
.end
Cell alignment — wrap the cell value with colons:
| Syntax | Alignment |
|---|---|
\| value \| |
Left (default) |
\| :value: \| |
Center |
\| value: \| |
Right |
| Left cell | :Centered cell: | Right cell: |
Multi-page tables — the header row repeats automatically when the table spans multiple pages.
Boxes
A box is a highlighted content region with a background fill and optional border.
.box [bg=#eef3ff] [border=#99aadd] [pad=14]
Any block content — headings, paragraphs, tables, rules.
.end
| Option | Default | Description |
|---|---|---|
bg=#hex |
#edf0ff |
Background fill colour |
border=#hex |
none | Border colour (omit for no border) |
pad=14 |
14 |
Internal padding in pt |
Example:
.box bg=#fff8e0 border=#f0c060
## ⚠ Important Notice
Please read the terms carefully before signing.
.end
.box bg=#ffeef0 border=#ffaaaa
**Error:** The submitted value is invalid.
.end
Watermarks
A diagonal text overlay rendered behind all content on every page.
@watermark text="DRAFT" opacity=0.12 angle=45 fontsize=80
| Option | Default | Description |
|---|---|---|
text="..." |
DRAFT |
Watermark label |
opacity=0.12 |
0.12 |
Intensity: 0 = invisible, 1 = solid black |
angle=45 |
45 |
Rotation in degrees counter-clockwise |
fontsize=80 |
80 |
Font size in pt |
Common values:
@watermark text="DRAFT" opacity=0.12 angle=45 // light diagonal
@watermark text="CONFIDENTIAL" opacity=0.10 angle=30 // lighter, shallower
@watermark text="SAMPLE" opacity=0.18 angle=45 // slightly darker
@watermark text="APPROVED" opacity=0.12 angle=0 // horizontal
Page Breaks, Spacers, and Rules
<<< Force a page break
.spacer 20 Vertical gap of 20 pt
--- Horizontal rule (default 0.5pt, light gray)
Raw PDF Operators
Inject content stream operators directly for custom graphics, shapes, or effects.
.raw
BT /F2 14 Tf 50 700 Td (Custom text via raw ops) Tj ET
.end
.raw
q
0.85 0.9 1.0 rg
50 600 495 80 re f
Q
.end
Warning: No bounds checking is performed on raw operators. Invalid operators will corrupt the page stream.
Method 2 — Fluent C# API
The PdfDocumentBuilder provides a fully programmatic way to construct PDFs without any markup.
PdfDocumentBuilder Reference
Document configuration:
var builder = new PdfDocumentBuilder()
.SetTitle("My Document") // PDF metadata
.SetAuthor("Jane Doe")
.SetSubject("Annual Report")
.SetKeywords("pdf annual report")
.SetPageSize(PageSize.A4) // PageSize.A4 | Letter | A5 | Legal | A3
.SetLandscape(true) // true = landscape orientation
.SetMargin(Margin.Normal) // Margin.Normal | Narrow | Wide | All(v) | Symmetric(v,h)
.SetEncryption(EncryptionSettings.PasswordProtect("open", "admin"))
.SetWatermark("DRAFT", intensity: 0.12f, angleDeg: 45f, fontSize: 80f);
Content methods:
| Method | Description |
|---|---|
.AddHeading(text, level) |
Heading level 1–4. Default level 1 |
.AddParagraph(markup, align) |
Paragraph supporting inline styles. Align: TextAlign.Left\|Center\|Right |
.AddTable(Action<TableBuilder>) |
Table — configured via TableBuilder callback |
.AddBox(Action<PdfDocumentBuilder>, background, border, padding) |
Highlighted content box |
.AddRule(thickness, color) |
Horizontal rule. Default 0.5pt, light gray |
.AddSpacer(pts) |
Vertical gap in pt. Default 12pt |
.AddPageBreak() |
Force a new page |
.AddRaw(operators) |
Inject raw PDF content stream operators |
Output methods:
byte[] bytes = builder.Build(); // returns byte[]
builder.BuildToFile("output.pdf"); // writes directly to disk
TableBuilder Reference
Configure via a callback passed to .AddTable():
builder.AddTable(t => t
// Column widths (call once per column, in order)
.AddColumn(ColSpec.Fixed(120)) // fixed 120pt
.AddColumn(ColSpec.Star()) // fill remaining space
.AddColumn(ColSpec.Star(2)) // fill with weight 2 (twice as wide as Star())
.AddColumn(ColSpec.Auto) // auto-size to header text
// Row sizing
.SetMinRowHeight(20)
.SetFontSize(9)
.SetPadding(5)
// Styling
.SetHeaderBackground(PdfColor.DarkBlue)
.SetHeaderForeground(PdfColor.White)
.SetEvenRowBackground(new PdfColor(0.95f, 0.97f, 1f))
.SetBorderColor(new PdfColor(0.75f, 0.75f, 0.75f))
.SetBorderWidth(0.4f)
.SetRepeatHeader(true) // repeat header row on page breaks
// Data
.SetHeader("No", "Product", "Description", "Price")
.AddRow("1", "Alpha", "First product", "$299")
.AddRow("2", "Beta", "Second product", "$149")
// Optional footer (bold, appears after all data rows)
.SetFooter(["", "", "Total", "$448"],
[TextAlign.Left, TextAlign.Left, TextAlign.Right, TextAlign.Right])
);
Colspan cells — merge columns in footer or data rows:
using PdfScript.Core;
.SetFooter(
[ColspanCell.Encode(3, "Total Amount:"), "$85,976"],
[TextAlign.Right, TextAlign.Right]
)
Full Fluent Example
using PdfScript;
using PdfScript.Core;
byte[] pdf = new PdfDocumentBuilder()
.SetTitle("Q1 2026 Sales Report")
.SetAuthor("Finance Team")
.SetSubject("Quarterly Sales")
.SetKeywords("sales quarterly finance")
.SetPageSize(PageSize.A4)
.SetLandscape(false)
.SetMargin(Margin.Normal)
.SetWatermark("DRAFT", intensity: 0.10f)
// Page 1 — Summary
.AddHeading("Q1 2026 Sales Report", 1)
.AddParagraph("Revenue grew by **42%** year-on-year with strong results across all regions.")
.AddSpacer(10)
.AddBox(
b => b.AddParagraph("**Highlight:** Best quarter in company history."),
background: PdfColor.FromHex("#eef8ff"),
border: PdfColor.FromHex("#99ccff")
)
.AddSpacer(10)
.AddTable(t => t
.AddColumn(ColSpec.Auto)
.AddColumn(ColSpec.Star())
.AddColumn(ColSpec.Fixed(80))
.AddColumn(ColSpec.Fixed(80))
.SetHeaderBackground(PdfColor.DarkBlue)
.SetHeaderForeground(PdfColor.White)
.SetEvenRowBackground(new PdfColor(0.93f, 0.96f, 1f))
.SetRepeatHeader(true)
.SetHeader("Region", "Manager", "Target", "Actual")
.AddRow("North", "Alice Johnson", "$50,000", "$61,200")
.AddRow("South", "Bob Smith", "$45,000", "$48,750")
.AddRow("East", "Carol White", "$55,000", "$59,900")
.AddRow("West", "David Lee", "$40,000", "$38,200")
.SetFooter(
[ColspanCell.Encode(2, "Total"), "$190,000", "$208,050"],
[TextAlign.Right, TextAlign.Right, TextAlign.Right]
)
)
// Page 2 — Notes
.AddPageBreak()
.AddHeading("Notes", 2)
.AddParagraph("All figures are in USD. Targets were set in January 2026.")
.AddRule()
.AddParagraph("*Report generated by PdfScriptCompiler*", TextAlign.Center)
.Build();
File.WriteAllBytes("q1-report.pdf", pdf);
Method 3 — Compile from String
Use PdfScriptCompiler.Compile() to compile a PDFScript markup string directly to a byte[].
using PdfScript;
string source = """
@page a4
@title "Hello World"
# Hello World
This PDF was generated from a C# string literal.
""";
byte[] pdf = PdfScriptCompiler.Compile(source);
File.WriteAllBytes("hello.pdf", pdf);
This is the lowest-level API — useful when you generate markup dynamically (e.g., from a template engine or user input).
Method 4 — Compile from File
Use PdfScriptCompiler.CompileFile() to compile a .pdfs file on disk.
using PdfScript;
// Output defaults to same path with .pdf extension
PdfScriptCompiler.CompileFile("report.pdfs");
// → writes report.pdf
// Specify a custom output path
PdfScriptCompiler.CompileFile("report.pdfs", "/output/report.pdf");
Throws FileNotFoundException if the input file does not exist.
Method 5 — Compile to Stream
Use PdfScriptCompiler.CompileToStream() to write PDF bytes directly to any Stream.
using PdfScript;
// Write to a MemoryStream
using var ms = new MemoryStream();
PdfScriptCompiler.CompileToStream(source, ms);
byte[] bytes = ms.ToArray();
// Write directly to a FileStream
using var fs = new FileStream("output.pdf", FileMode.Create);
PdfScriptCompiler.CompileToStream(source, fs);
No intermediate byte array is created — the PDF is written directly to the stream. Ideal for HTTP responses.
Encryption
PdfScriptCompiler uses RC4-128 / PDF Standard Security Rev 3, compatible with Acrobat 5+, Adobe Reader, Foxit, Chrome, and all modern PDF viewers.
Markup
@encrypt userpwd="open123" ownerpwd="admin456" permissions=all
permissions value |
Effect |
|---|---|
all |
Full access (default) |
readonly |
Print only — no modify, copy, or extract |
none |
No permissions granted |
Fluent API
// Full access with passwords
.SetEncryption(EncryptionSettings.PasswordProtect("open123", "admin456"))
// Print-only (read-only)
.SetEncryption(EncryptionSettings.ReadOnly("view", "admin"))
// Custom permission flags
.SetEncryption(new EncryptionSettings
{
UserPassword = "user",
OwnerPassword = "admin",
Permissions = PermissionFlags.Print | PermissionFlags.FillForms
})
PermissionFlags reference
PermissionFlags.Print // allow printing
PermissionFlags.Modify // allow content modification
PermissionFlags.Copy // allow text copying
PermissionFlags.Annotations // allow adding annotations
PermissionFlags.FillForms // allow filling form fields
PermissionFlags.Extract // allow content extraction
PermissionFlags.Assemble // allow page assembly
PermissionFlags.PrintHighQual // allow high-quality printing
PermissionFlags.All // all permissions
PermissionFlags.None // no permissions
Watermarks Reference
A watermark is drawn behind all content on every page of the document.
Markup
@watermark text="DRAFT" opacity=0.12 angle=45 fontsize=80
Fluent API
.SetWatermark(
text: "CONFIDENTIAL",
intensity: 0.12f, // 0 = invisible, 1 = solid black
angleDeg: 45f, // degrees counter-clockwise
fontSize: 80f // pt
)
Common presets
| Use case | text |
intensity |
angle |
|---|---|---|---|
| Draft document | "DRAFT" |
0.12 |
45 |
| Confidential | "CONFIDENTIAL" |
0.10 |
30 |
| Sample / demo | "SAMPLE" |
0.18 |
45 |
| Horizontal stamp | "APPROVED" |
0.12 |
0 |
| Dark visible mark | "INTERNAL" |
0.35 |
45 |
Colors
Colors are expressed as PdfColor with RGB values between 0 and 1, or created from hex strings.
// Named constants
PdfColor.Black
PdfColor.White
PdfColor.Gray
PdfColor.LightGray
PdfColor.Silver
PdfColor.Blue
PdfColor.DarkBlue
PdfColor.Navy
PdfColor.Red
PdfColor.Green
PdfColor.Orange
// From hex string
PdfColor.FromHex("#1a3a6b")
PdfColor.FromHex("#eef3ff")
PdfColor.FromHex("#f0c060")
// From RGB floats (0.0–1.0)
new PdfColor(0.1f, 0.4f, 0.85f)
In markup, colors are always specified as #rrggbb hex strings:
headerbg=#1a3a6b
headerfg=#ffffff
bg=#eef3ff
border=#99aadd
[color=#cc0000]text[/color]
Page Sizes and Margins
Page sizes
| Constant | Dimensions (pt) | Common use |
|---|---|---|
PageSize.A4 |
595 × 842 | Standard international |
PageSize.Letter |
612 × 792 | US standard |
PageSize.A5 |
420 × 595 | Half A4, booklets |
PageSize.Legal |
612 × 1008 | US legal documents |
PageSize.A3 |
842 × 1191 | Wide format, posters |
Landscape swaps width and height:
.SetPageSize(PageSize.A4).SetLandscape(true) // 842 × 595 pt
Margins
| Constant | Values (pt) | Use |
|---|---|---|
Margin.Normal |
60 / 50 / 60 / 50 | Default — balanced |
Margin.Narrow |
36 all sides | Dense tables, forms |
Margin.Wide |
72 all sides | Formal documents |
Margin.All(v) |
v all sides |
Custom uniform |
Margin.Symmetric(v, h) |
vertical / horizontal | Custom symmetric |
new Margin(top, right, bottom, left) |
all four | Full custom |
In markup:
@margin 60 50 60 50 // top right bottom left
@margin 36 // all sides
@margin 60 50 // vertical horizontal
ASP.NET Core Integration
Return a PDF directly from a controller or minimal API endpoint:
// Minimal API
app.MapGet("/report", () =>
{
string source = """
@page a4
@title "Live Report"
# Live Report
Generated on demand by ASP.NET Core.
""";
byte[] pdf = PdfScriptCompiler.Compile(source);
return Results.File(pdf, "application/pdf", "report.pdf");
});
// MVC Controller
[HttpGet("invoice/{id}")]
public IActionResult GetInvoice(int id)
{
var source = BuildInvoiceMarkup(id);
Response.ContentType = "application/pdf";
PdfScriptCompiler.CompileToStream(source, Response.Body);
return new EmptyResult();
}
// Stream directly to response (no byte[] allocation)
app.MapGet("/stream", async (HttpResponse response) =>
{
response.ContentType = "application/pdf";
PdfScriptCompiler.CompileToStream(source, response.Body);
});
License
MIT © 2026 AB21RAM — see LICENSE for full text.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.2.0
- Watermark support: @watermark directive and SetWatermark() fluent API
(text, intensity 0–1, angle, font size — all configurable)
- Table last-row bottom border fix (was missing in v2.1)
- Box layout: padding increased to 14pt; background rect no longer clips
tall content; oversized boxes no longer overflow bottom margin
- HRule spacing increased (SpaceY 8→12pt) for better breathing room
- Package icon added (visible in nuget.org and VS/Rider package manager)
- Expanded NuGet tags and keyword-rich description for better search ranking
- PdfScriptTest project: 100-PDF test suite covering all APIs
v2.1.0
- Landscape orientation support
- RC4-128 encryption with user/owner passwords and permission flags
- Smart table columns: fixed, star, auto widths with cell text wrapping
- Per-cell alignment (colon syntax)
- Fluent PdfDocumentBuilder + TableBuilder API
- Symbols package (.snupkg) for step-through debugging