{"id":49582934,"url":"https://github.com/sahebansari/terrapdf","last_synced_at":"2026-05-07T00:02:20.107Z","repository":{"id":354887594,"uuid":"1225712592","full_name":"sahebansari/TerraPDF","owner":"sahebansari","description":"TerraPDF is a lightweight, zero-dependency, pure C# library for generating professional PDF 1.7 documents programmatically.  No native binaries, no third-party library required.","archived":false,"fork":false,"pushed_at":"2026-05-03T20:24:58.000Z","size":397,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-03T21:27:32.366Z","etag":null,"topics":["document","fluent-api","image","invoice","no-dependency","pdf","pdf-generation","reporting","table","zero-dependency"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sahebansari.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-30T14:59:45.000Z","updated_at":"2026-05-03T20:25:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sahebansari/TerraPDF","commit_stats":null,"previous_names":["sahebansari/terrapdf"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/sahebansari/TerraPDF","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sahebansari%2FTerraPDF","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sahebansari%2FTerraPDF/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sahebansari%2FTerraPDF/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sahebansari%2FTerraPDF/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sahebansari","download_url":"https://codeload.github.com/sahebansari/TerraPDF/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sahebansari%2FTerraPDF/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32626501,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["document","fluent-api","image","invoice","no-dependency","pdf","pdf-generation","reporting","table","zero-dependency"],"created_at":"2026-05-03T21:02:17.721Z","updated_at":"2026-05-05T23:01:17.168Z","avatar_url":"https://github.com/sahebansari.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TerraPDF \n\nA free, pure C# library designed for fast and reliable PDF generation.\n\n![TerraPDF](https://github.com/sahebansari/TerraPDF/raw/master/logo.png)\n\n[![NuGet](https://img.shields.io/nuget/v/TerraPDF.svg)](https://www.nuget.org/packages/TerraPDF)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n📚 **Documentation:** https://github.com/sahebansari/TerraPDF/tree/master/docs\n\n**TerraPDF** is a lightweight, zero-dependency, pure C# library for generating professional PDF 1.7 documents programmatically. \nIt provides a fluent, composable API that covers the full document-authoring lifecycle — from page layout and \nrich text to tables, images, hyperlinks, and multi-page pagination — with no native binaries, no third-party \nruntime packages, and no licensing restrictions.\n\n- No native dependencies, no third-party packages\n- Targets **.NET 8** and **.NET 9**\n- Text styling — bold, italic, bold-italic, strikethrough, underline, font size, colour\n- Configurable line-height multiplier per text block\n- Per-span formatting inside mixed-style text blocks\n- Margin and padding decorators with full unit support\n- Background fills and borders (full, rounded, and per-edge)\n- Rounded-corner borders and filled rounded boxes\n- Per-edge borders — `BorderTop`, `BorderBottom`, `BorderLeft`, `BorderRight`\n- Horizontal and vertical alignment\n- Column, Row, and Table layouts\n- PNG and JPEG image embedding\n- Horizontal and vertical rule lines\n - Explicit page breaks via `PageBreak()`\n - Clickable hyperlink (URI) annotations via `Hyperlink()`\n - Internal document links (GoTo) via `InternalLink()`\n - Automatic Table of Contents generation from H1–H6 headings\n - PDF bookmarks / outlines with hierarchical nesting\n - Document metadata (Title, Author, Subject, Keywords, Creator)\n - Conditional rendering via `ShowIf`\n - Reusable components via `IComponent`\n - Headers, footers, and page numbers\n - Fluent, composable API\n\n---\n\n## Installation\n\n```sh\ndotnet add package TerraPDF\n```\n\n---\n\n## Quick Start\n\n```csharp\nusing TerraPDF.Core;\nusing TerraPDF.Helpers;\n\nDocument.Create(container =\u003e\n{\n    container.Page(page =\u003e\n    {\n        page.Size(PageSize.A4);\n        page.Margin(2, Unit.Centimetre);\n        page.PageColor(Color.White);\n        page.DefaultTextStyle(s =\u003e s.FontSize(11));\n\n        page.Header()\n            .Text(\"My Report\")\n            .Bold()\n            .FontSize(24)\n            .FontColor(Color.Blue.Darken2);\n\n        page.Content()\n            .Column(col =\u003e\n            {\n                col.Spacing(8);\n                col.Item().Text(\"Hello, TerraPDF!\");\n                col.Item().Text(\"This paragraph is italic.\").Italic();\n                col.Item()\n                   .Margin(6).Background(Color.Grey.Lighten4).Padding(10)\n                   .Text(\"Indented callout box\").Bold();\n            });\n\n        page.Footer()\n            .AlignCenter()\n            .Text(t =\u003e\n            {\n                t.Span(\"Page \");\n                t.CurrentPageNumber().FontSize(9);\n                t.Span(\" / \");\n                t.TotalPages().FontSize(9);\n            });\n    });\n})\n.PublishPdf(\"output.pdf\");\n```\n\n---\n\n## API Overview\n\n### Document entry points\n\n| Method | Description |\n|--------|-------------|\n| `Document.Create(Action\u003cIDocumentContainer\u003e)` | Inline composition callback |\n| `Document.Create(IDocument)` | Reusable `IDocument` class |\n\n### Page configuration\n\n```csharp\npage.Size(PageSize.A4);\npage.Margin(2, Unit.Centimetre);   // page margin\npage.PageColor(Color.White);\npage.DefaultTextStyle(s =\u003e s.FontSize(11));\npage.Header()   // returns IContainer\npage.Content()  // returns IContainer\npage.Footer()   // returns IContainer\n```\n\n---\n\n## Text\n\n### Single-string text\n\n```csharp\ncontainer.Text(\"Hello, world!\")\n    .Bold()\n    .SemiBold()\n    .Italic()\n    .Strikethrough()\n    .Underline()\n    .FontSize(18)\n    .LineHeight(1.5)  // line-height multiplier (default ≈ 1.4)\n    .FontColor(Color.Blue.Darken2)\n    .AlignLeft()      // default\n    .AlignCenter()\n    .AlignRight()\n    .Justify();\n```\n\n### Multi-span text\n\nEach `Span()`, `CurrentPageNumber()`, and `TotalPages()` returns a `SpanDescriptor`\nso formatting applies **only to that span**, not to the whole block.\n\n```csharp\ncontainer.Text(t =\u003e\n{\n    t.Span(\"Normal  \");\n    t.Span(\"Bold  \").Bold();\n    t.Span(\"Italic  \").Italic();\n    t.Span(\"Struck  \").Strikethrough();\n    t.Span(\"Coloured  \").FontColor(Color.Red.Medium);\n    t.Span(\"Large\").FontSize(16).FontColor(\"#1a4a8a\");\n});\n```\n\n### Page numbers in footers\n\n```csharp\ncontainer.Text(t =\u003e\n{\n    t.Span(\"Page \").FontSize(9).FontColor(Color.Grey.Medium);\n    t.CurrentPageNumber().FontSize(9).FontColor(Color.Grey.Medium);\n    t.Span(\" / \").FontSize(9);\n    t.TotalPages().FontSize(9);\n});\n```\n\n---\n\n## Layout\n\n### Column — stacks children vertically\n\n```csharp\ncontainer.Column(col =\u003e\n{\n    col.Spacing(6);                       // gap between items in points\n    col.AlignItemsLeft();                 // default\n    col.AlignItemsCenter();\n    col.AlignItemsRight();\n\n    col.Item().Text(\"First\");\n    col.Item().Text(\"Second\");\n});\n```\n\n### Row — arranges children horizontally\n\n```csharp\ncontainer.Row(row =\u003e\n{\n    row.Spacing(8);                       // gap between items in points\n\n    row.RelativeItem(2).Text(\"2x wide\"); // proportional share of remaining space\n    row.RelativeItem(1).Text(\"1x wide\");\n    row.AutoItem().Text(\"Auto width\");   // natural content width\n    row.ConstantItem(80).Text(\"80 pt\");  // fixed width in points\n});\n```\n\n### Table — grid with repeating header rows\n\n```csharp\ncontainer.Table(table =\u003e\n{\n    table.ColumnsDefinition(cols =\u003e\n    {\n        cols.RelativeColumn(4);   // proportional\n        cols.RelativeColumn(1);\n        cols.ConstantColumn(60);  // fixed width in points\n    });\n\n    // HeaderRow repeats on every continuation page\n    table.HeaderRow(row =\u003e\n    {\n        row.Cell().Background(\"#1a4a8a\").Padding(6).Text(\"Description\").Bold().FontColor(Color.White);\n        row.Cell().Background(\"#1a4a8a\").Padding(6).Text(\"Qty\").Bold().FontColor(Color.White);\n        row.Cell().Background(\"#1a4a8a\").Padding(6).AlignRight().Text(\"Amount\").Bold().FontColor(Color.White);\n    });\n\n    table.Row(row =\u003e\n    {\n        row.Cell().Padding(6).Text(\"Web Development\");\n        row.Cell().Padding(6).Text(\"1\");\n        row.Cell().Padding(6).AlignRight().Text(\"$2,500.00\");\n    });\n});\n```\n\n---\n\n## Decorators\n\nDecorators are chainable and compose from the outside in:\n`.Margin()` → `.Background()` → `.Padding()` → content\n\n### Padding — inner spacing (inside background / border)\n\n```csharp\ncontainer.Padding(10)                    // all sides\ncontainer.PaddingVertical(8)             // top + bottom\ncontainer.PaddingHorizontal(12)          // left + right\ncontainer.PaddingTop(4)\ncontainer.PaddingBottom(4)\ncontainer.PaddingLeft(6)\ncontainer.PaddingRight(6)\n\n// All padding methods also accept a Unit:\ncontainer.Padding(0.5, Unit.Centimetre)\n```\n\n### Margin — outer spacing (outside background / border)\n\n```csharp\ncontainer.Margin(10)                     // all sides\ncontainer.MarginVertical(8)              // top + bottom\ncontainer.MarginHorizontal(12)           // left + right\ncontainer.MarginTop(4)\ncontainer.MarginBottom(4)\ncontainer.MarginLeft(6)\ncontainer.MarginRight(6)\n\n// All margin methods also accept a Unit:\ncontainer.Margin(0.5, Unit.Centimetre)\n```\n\n\u003e **Padding vs Margin**\n\u003e `.Margin(10).Background(\"red\").Padding(5).Text(\"Hi\")`\n\u003e — the red background starts *after* the 10 pt margin gap;\n\u003e the text is inset 5 pt from the red edge.\n\n### Background and Border\n\n```csharp\ncontainer.Background(\"#1a4a8a\")\ncontainer.Border(1.5, \"#1a4a8a\")        // line width + colour\ncontainer.Border(1)                      // black by default\n\n// Rounded-corner border\ncontainer.RoundedBorder(radius: 8, lineWidth: 1, hexColor: \"#1a4a8a\")\n\n// Filled rounded box (background + border)\ncontainer.RoundedBox(radius: 8, fillHexColor: \"#E3F2FD\", borderHexColor: \"#1a4a8a\")\n\n// Per-edge borders\ncontainer.BorderTop(1.5, \"#1a4a8a\")\ncontainer.BorderBottom(1)\ncontainer.BorderLeft(3, Color.Red.Medium)\ncontainer.BorderRight(1, Color.Grey.Lighten2)\n```\n\n### Page Break\n\n```csharp\n// Force a new page at this position inside a Column\ncontainer.PageBreak();\n```\n\n### Hyperlink\n\n```csharp\n// Wrap any content in a clickable URI annotation\ncontainer.Hyperlink(\"https://example.com\").Text(\"Click here\");\ncontainer.Hyperlink(\"https://example.com\").Image(\"logo.png\", 120);\n```\n\n### Internal Link\n\nWrap content in a clickable internal hyperlink that jumps to a specific page and optional vertical position:\n\n```csharp\ncontainer.InternalLink(pageNumber, topPosition).Text(\"Go to section\");\n```\n\nThis creates a `/GoTo` action in the PDF. The automatic Table of Contents uses internal links to make each entry clickable.\n\n### Alignment\n\n```csharp\n// Horizontal\ncontainer.AlignLeft()\ncontainer.AlignCenter()\ncontainer.AlignRight()\n\n// Vertical\ncontainer.AlignMiddle()\ncontainer.AlignBottom()\n```\n\n### Lines\n\n```csharp\ncontainer.LineHorizontal(1.5, \"#1a4a8a\")   // horizontal rule\ncontainer.LineVertical(1)                   // vertical rule (black)\n```\n\n### Conditional rendering\n\n```csharp\ncontainer.ShowIf(isAdmin).Text(\"Admin panel\");\n```\n\n---\n\n## Images\n\n```csharp\n// Fill available width, preserve aspect ratio (PNG or JPEG)\ncontainer.Image(\"path/to/image.png\");\ncontainer.Image(\"path/to/photo.jpg\");\n\n// Fixed width in points, can be positioned with alignment\ncontainer.AlignCenter().Image(\"logo.png\", 120);\n```\n\n---\n\n## Headings\n\nTerraPDF provides six levels of section headings: `.H1()` through `.H6()`. Each heading uses sensible defaults (size + weight), which you can further customise via the fluent `TextDescriptor` API.\n\n```csharp\ncontainer.H1(\"Chapter Title\").FontColor(Color.Blue.Darken2);\ncontainer.H2(\"Section Title\").Underline();\ncontainer.H3(\"Subsection\");\n```\n\n### Default heading styles\n\n| Level | Font size | Style |\n|-------|-----------|-------|\n| H1 | 24 pt | Bold |\n| H2 | 20 pt | Bold |\n| H3 | 16 pt | Bold |\n| H4 | 14 pt | Italic |\n| H5 | 12 pt | Bold |\n| H6 | 11 pt | Regular |\n\n---\n\n## Table of Contents\n\nCall `container.TableOfContents()` to add a contents page that is automatically populated with all headings in the document. Headings appear with correct logical page numbers (excluding the TOC page itself) and clickable internal links that jump to the exact physical page.\n\n```csharp\nDocument.Create(container =\u003e\n{\n    // Create a Table of Contents page\n    container.TableOfContents(p =\u003e\n    {\n        p.Size(PageSize.A4);\n        p.Margin(2, Unit.Centimetre);\n        p.DefaultTextStyle(s =\u003e s.FontSize(11));\n    });\n\n    // Chapters with headings\n    container.Page(p =\u003e\n    {\n        p.Content()\n            .H1(\"Introduction\")\n            .H2(\"Getting Started\")\n            .H3(\"Installation\")\n            .H4(\"NuGet Package\");\n    });\n\n    container.Page(p =\u003e\n    {\n        p.Content()\n            .H1(\"Core Features\")\n            .H2(\"Text \u0026 Typography\")\n            .H2(\"Layout Containers\")\n            .H2(\"Tables\");\n    });\n})\n.PublishPdf(\"toc_demo.pdf\");\n```\n\n\u003e **Note:** Page numbers displayed in the TOC start from 1 for the first page *after* the TOC (i.e., the TOC page is treated as page 0). The internal links point to the correct physical pages, accounting for the TOC's actual page count.\n\n**Two-pass rendering** TerraPDF performs an initial measurement pass to collect heading positions and page numbers, then emits the final PDF with accurate TOC links.\n\n---\n\n## Reusable Components\n\n```csharp\npublic class CalloutBox : IComponent\n{\n    private readonly string _text;\n    public CalloutBox(string text) =\u003e _text = text;\n\n    public void Compose(IContainer container) =\u003e\n        container\n            .Margin(6).Background(Color.Blue.Lighten4).Padding(10)\n            .Text(_text).Italic();\n}\n\n// Usage\ncontainer.Component(new CalloutBox(\"Note: this is important.\"));\n```\n---\n## Reusable Document Template\n```csharp\npublic class InvoiceDocument : IDocument\n{\n    private readonly InvoiceData _data;\n    public InvoiceDocument(InvoiceData data) =\u003e _data = data;\n\n    public void Compose(IDocumentContainer container)\n    {\n        container.Page(page =\u003e\n        {\n            page.Size(PageSize.A4);\n            page.Margin(2, Unit.Centimetre);\n            page.Content().Text($\"Invoice #{_data.Number}\").Bold().FontSize(24);\n        });\n    }\n}\n// Usage\nDocument.Create(new InvoiceDocument(data)).PublishPdf(\"invoice.pdf\");\n```\n---\n## Output Methods\n```csharp\nvar composer = Document.Create(...);\n// To file\ncomposer.PublishPdf(\"output.pdf\");\n// To byte array (HTTP responses, email attachments, etc.)\nbyte[] bytes = composer.PublishPdf();\n// To any writable stream\ncomposer.PublishPdf(stream);\n```\n\n---\n\n## Reusable Document Template\n\n```csharp\npublic class InvoiceDocument : IDocument\n{\n    private readonly InvoiceData _data;\n    public InvoiceDocument(InvoiceData data) =\u003e _data = data;\n\n    public void Compose(IDocumentContainer container)\n    {\n        container.Page(page =\u003e\n        {\n            page.Size(PageSize.A4);\n            page.Margin(2, Unit.Centimetre);\n            page.Content().Text($\"Invoice #{_data.Number}\").Bold().FontSize(24);\n        });\n    }\n}\n\n// Usage\nDocument.Create(new InvoiceDocument(data)).PublishPdf(\"invoice.pdf\");\n```\n\n---\n\n## Output Methods\n\n```csharp\nvar composer = Document.Create(...);\n\n// To file\ncomposer.PublishPdf(\"output.pdf\");\n\n// To byte array (HTTP responses, email attachments, etc.)\nbyte[] bytes = composer.PublishPdf();\n\n// To any writable stream\ncomposer.PublishPdf(stream);\n```\n\n---\n\n## Built-in Page Sizes\n\n| Constant | Width × Height (pt) |\n|----------|---------------------|\n| `PageSize.A0` | 2383.94 × 3370.39 |\n| `PageSize.A1` | 1683.78 × 2383.94 |\n| `PageSize.A2` | 1190.55 × 1683.78 |\n| `PageSize.A3` | 841.89 × 1190.55 |\n| `PageSize.A4` | 595.28 × 841.89 |\n| `PageSize.A5` | 419.53 × 595.28 |\n| `PageSize.A6` | 297.64 × 419.53 |\n| `PageSize.Letter` | 612.00 × 792.00 |\n| `PageSize.Legal` | 612.00 × 1008.00 |\n| `PageSize.Tabloid` | 792.00 × 1224.00 |\n| `PageSize.Executive` | 521.86 × 756.00 |\n\n```csharp\n// Landscape variant of any size\npage.Size(PageSize.Landscape(PageSize.A4));\n```\n\n---\n\n## Built-in Units\n\n| Enum value | Description |\n|------------|-------------|\n| `Unit.Point` | PDF native unit (1 pt = 1/72 inch) — default |\n| `Unit.Millimetre` | 1 mm ≈ 2.835 pt |\n| `Unit.Centimetre` | 1 cm ≈ 28.35 pt |\n| `Unit.Inch` | 1 in = 72 pt |\n\n---\n\n## Built-in Colours\n\n```csharp\n// Named shades (Material Design palette)\nColor.Red.Darken2      Color.Red.Darken1\nColor.Red.Medium       Color.Red.Lighten1  ...  Color.Red.Lighten4\nColor.Blue.Darken2     Color.Blue.Medium   ...\nColor.Green.Darken2    Color.Green.Medium  ...\nColor.Grey.Darken2     Color.Grey.Medium   Color.Grey.Lighten1 ...\nColor.Orange.Medium\nColor.Purple.Medium\n// Convenience constants\nColor.White            // \"#FFFFFF\"\nColor.Black            // \"#000000\"\n```\n\n---\n\n\n\n## Building from Source\n\n```sh\ngit clone https://github.com/sahebansari/TerraPDF.git\ncd TerraPDF\ndotnet build\ndotnet test\n```\n\nRequires **.NET 8 SDK** or later.\n\n---\n\n## Contributing\n\nContributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for coding standards, project structure, how to run tests, and the pull-request process.\n\n---\n\n## Changelog\n\nAll notable changes are documented in [CHANGELOG.md](CHANGELOG.md), following the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.\n\n---\n\n## Security\n\nTo report a vulnerability, please follow the responsible-disclosure process described in [SECURITY.md](SECURITY.md). **Do not open a public issue for security problems.**\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsahebansari%2Fterrapdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsahebansari%2Fterrapdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsahebansari%2Fterrapdf/lists"}