{"id":13496703,"url":"https://github.com/coenttb/swift-html-to-pdf","last_synced_at":"2026-02-22T05:34:06.808Z","repository":{"id":248659318,"uuid":"828974536","full_name":"coenttb/swift-html-to-pdf","owner":"coenttb","description":"The Swift package for printing HTML to PDF.","archived":false,"fork":false,"pushed_at":"2026-01-27T11:53:16.000Z","size":485,"stargazers_count":69,"open_issues_count":0,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-01-27T23:38:18.348Z","etag":null,"topics":["actor-based","concurrency","document-generation","html","ios","macos","pdf","pdf-generation","pdf-printer","printing","server-side-swift","swift","swift6","wkhtmltopdf","wkwebview"],"latest_commit_sha":null,"homepage":"https://coenttb.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coenttb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"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},"funding":{"github":["coenttb"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2024-07-15T13:54:56.000Z","updated_at":"2026-01-27T11:53:20.000Z","dependencies_parsed_at":"2024-09-08T20:49:33.561Z","dependency_job_id":"a9020f02-5a2b-4bcc-bba2-ac4655511a2c","html_url":"https://github.com/coenttb/swift-html-to-pdf","commit_stats":null,"previous_names":["coenttb/swift-html-to-pdf"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/coenttb/swift-html-to-pdf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coenttb%2Fswift-html-to-pdf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coenttb%2Fswift-html-to-pdf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coenttb%2Fswift-html-to-pdf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coenttb%2Fswift-html-to-pdf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coenttb","download_url":"https://codeload.github.com/coenttb/swift-html-to-pdf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coenttb%2Fswift-html-to-pdf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29705536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T03:17:42.375Z","status":"ssl_error","status_checked_at":"2026-02-22T03:17:31.622Z","response_time":110,"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":["actor-based","concurrency","document-generation","html","ios","macos","pdf","pdf-generation","pdf-printer","printing","server-side-swift","swift","swift6","wkhtmltopdf","wkwebview"],"created_at":"2024-07-31T19:01:57.421Z","updated_at":"2026-02-22T05:34:06.780Z","avatar_url":"https://github.com/coenttb.png","language":"Swift","funding_links":["https://github.com/sponsors/coenttb"],"categories":["Swift"],"sub_categories":[],"readme":"# swift-html-to-pdf\n\n[![CI](https://github.com/coenttb/swift-html-to-pdf/actions/workflows/ci.yml/badge.svg)](https://github.com/coenttb/swift-html-to-pdf/actions/workflows/ci.yml)\n[![Swift 6.0](https://img.shields.io/badge/Swift-6.0-orange.svg)](https://swift.org)\n[![Platforms](https://img.shields.io/badge/Platforms-macOS%20%7C%20iOS-blue.svg)](https://github.com/coenttb/swift-html-to-pdf)\n[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)\n\n**The fastest HTML to PDF library for Swift**\n\n⚡ **1,939 PDFs/sec** • 💾 **35 MB memory (4-24 workers)** • 🎯 **Type-safe** • 🧪 **Swift 6**\n\n---\n\n## Why\n\nEvery other solution makes you choose: **fast** *or* **safe** *or* **easy**.\n\nThis library gives you all three.\n\n```swift\n@Dependency(\\.pdf) var pdf\ntry await pdf.render(html: \"\u003ch1\u003eInvoice #1234\u003c/h1\u003e\", to: fileURL)\n```\n\n**One line. Zero configuration. Production-ready.**\n\n---\n\n## The Numbers\n\n### Performance\n\n**Continuous Mode** (single-page, maximum speed):\n\n| Batch Size | Throughput      | Avg Latency | Memory |\n|------------|-----------------|-------------|--------|\n| 100        | 1,772/sec       | 0.56ms      | 146 MB |\n| 1,000      | **1,939/sec**   | 0.52ms      | 146 MB |\n| 10,000     | 1,814/sec       | 0.55ms      | 148 MB |\n\n**Paginated Mode** (multi-page, print-ready):\n\n| Batch Size | Throughput      | Avg Latency | Memory |\n|------------|-----------------|-------------|--------|\n| 100        | 142/sec         | 7.05ms      | 102 MB |\n| 1,000      | **677/sec**     | 1.48ms      | 110 MB |\n| 10,000     | 485/sec         | 2.06ms      | 137 MB |\n\n*Test environment: macOS 26.0, Apple Silicon M1 (8 cores), 24 GB RAM, Swift 6.2*\n\n### Memory Efficiency\n\nMemory usage **doesn't scale** with concurrency:\n\n| Concurrency | Steady-State | Peak  | Expected  |\n|-------------|--------------|-------|-----------|\n| 4 workers   | 34 MB        | 34 MB | 400 MB    |\n| 8 workers   | 34 MB        | 35 MB | 800 MB    |\n| 16 workers  | 35 MB        | 35 MB | 1,600 MB  |\n| 24 workers  | 35 MB        | 35 MB | 2,400 MB  |\n\n**Why?** Shared WebKit infrastructure. Memory determined by pool overhead, not worker count.\n\n*Measured empirically with 50+ PDF warmup, sustained rendering workload. See `WebViewMemoryTests.swift` for methodology.*\n\n**Memory stays constant during extended batches:**\n- 500 PDFs with 8 concurrent: Peak 98 MB, range 74 MB (includes startup), steady-state variance \u003c5 MB\n- No leaks. No accumulation. Constant memory regardless of batch size.\n\n---\n\n## Quick Start\n\n### HTML String → PDF\n\n```swift\nimport HtmlToPdf\nimport Dependencies\n\n@Dependency(\\.pdf) var pdf\n\n// To file\ntry await pdf.render(html: \"\u003ch1\u003eInvoice #1234\u003c/h1\u003e\", to: fileURL)\n\n// To data (in-memory)\nlet pdfData = try await pdf.render(html: \"\u003ch1\u003eReceipt\u003c/h1\u003e\")\n\n// Batch processing\nlet html = invoices.map { \"\u003chtml\u003e\u003cbody\u003e\\($0.html)\u003c/body\u003e\u003c/html\u003e\" }\nfor try await result in try await pdf.render(html: html, to: directory) {\n    print(\"Generated \\(result.url)\")\n}\n```\n\n**That's it.** No setup. No configuration.\n\n### Type-Safe HTML (Optional)\n\nFor compile-time safety, enable the HTML trait to use [swift-html](https://github.com/coenttb/swift-html):\n\n**Package.swift:**\n```swift\ndependencies: [\n    .package(\n        url: \"https://github.com/coenttb/swift-html-to-pdf.git\",\n        from: \"1.0.0\",\n        traits: [\"HTML\"]  // ← Enable HTML trait\n    )\n]\n```\n\n**Usage:**\n```swift\nimport HtmlToPdf\n\nstruct Invoice: HTMLDocument {\n    let number: Int\n    let total: Decimal\n\n    var head: some HTML {\n        title { \"Invoice #\\(number)\" }\n    }\n\n    var body: some HTML {\n        h1 { \"Invoice #\\(number)\" }\n        p { \"Total: $\\(total)\" }\n    }\n}\n\n@Dependency(\\.pdf) var pdf\ntry await pdf.render(html: Invoice(number: 1234, total: 99.99), to: fileURL)\n```\n\n**Invalid HTML?** Won't compile. **Type safety** all the way down.\n\n---\n\n## Why It's Different\n\n### 1. Streaming Results\n\nProcess PDFs as they're generated. Don't wait for the batch to finish.\n\n```swift\nfor try await result in try await pdf.render(html: html, to: directory) {\n    // This PDF is ready NOW\n    try await uploadToS3(result.url)        // Upload immediately\n    try await db.markComplete(result.index) // Update database\n}\n```\n\n**Benefits:** Lower latency, constant memory, real-time progress.\n\n### 2. WebView Resource Pooling\n\n- Pre-warmed WKWebView instances (instant availability)\n- Automatic lifecycle management\n- FIFO fairness under load\n- Optimal concurrency: 1x CPU count (8 WebViews on 8-core Mac)\n- Powered by [swift-resource-pool](https://github.com/coenttb/swift-resource-pool)\n\n### 3. Swift 6 Strict Concurrency\n\n- Full type safety in concurrent code\n- Sendable guarantees throughout\n- Actor-isolated state management\n- No data races possible\n\n---\n\n## Installation\n\n### Swift Package Manager\n\nAdd to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/coenttb/swift-html-to-pdf.git\", from: \"1.0.0\")\n]\n```\n\nAdd to your target:\n\n```swift\n.target(\n    name: \"YourTarget\",\n    dependencies: [\n        .product(name: \"HtmlToPdf\", package: \"swift-html-to-pdf\")\n    ]\n)\n```\n\n**Optional: Enable type-safe HTML DSL**\n\nTo use the [swift-html](https://github.com/coenttb/swift-html) integration, enable the HTML trait:\n\n```swift\ndependencies: [\n    .package(\n        url: \"https://github.com/coenttb/swift-html-to-pdf.git\",\n        from: \"1.0.0\",\n        traits: [\"HTML\"]  // ← Enable HTML trait\n    )\n]\n```\n\n### Requirements\n\n- **Swift 6.0+**\n- **macOS 14.0+** or **iOS 17.0+**\n- **Xcode 16.0+**\n\n---\n\n## Configuration\n\nNeed to customize? Full configuration available:\n\n```swift\ntry await withDependencies {\n    $0.pdf.render.configuration.paperSize = .letter\n    $0.pdf.render.configuration.margins = .wide\n    $0.pdf.render.configuration.paginationMode = .paginated\n    $0.pdf.render.configuration.concurrency = .automatic\n} operation: {\n    try await pdf.render(html: html, to: fileURL)\n}\n```\n\n**Common configurations:**\n\n- **Paper sizes:** `.a4`, `.letter`, `.legal`, `.a3`, `.a5`, or custom `CGSize`\n- **Margins:** `.none`, `.minimal`, `.standard`, `.comfortable`, `.wide`, or custom `EdgeInsets`\n- **Pagination:** `.continuous` (fast), `.paginated` (print-ready), `.automatic`\n- **Concurrency:** `.automatic` (1x CPU), `.fixed(n)`, or specific count\n\nSee [Configuration Guide](Sources/HtmlToPdf/Documentation.docc/ConfigurationGuide.md) for all options.\n\n---\n\n## Production Metrics\n\nExport metrics to Prometheus, StatsD, or other monitoring systems via [swift-metrics](https://github.com/apple/swift-metrics):\n\n```swift\nimport Metrics\nimport Prometheus\n\n// Bootstrap once at startup\nMetricsSystem.bootstrap(PrometheusMetricsFactory())\n\n// Use library normally - metrics automatically collected\n@Dependency(\\.pdf) var pdf\ntry await pdf.render(html: invoices, to: directory)\n```\n\n**Available Metrics:**\n\n- `htmltopdf_pdfs_generated_total` - Counter\n- `htmltopdf_pdfs_failed_total` - Counter (with `reason` dimension)\n- `htmltopdf_render_duration_seconds` - Timer (with `mode` dimension; p50/p95/p99)\n- `htmltopdf_pool_replacements_total` - Counter\n- `htmltopdf_pool_utilization` - Gauge\n- `htmltopdf_throughput_pdfs_per_sec` - Gauge\n\n---\n\n## Documentation\n\n- **[Getting Started Guide](Sources/HtmlToPdf/Documentation.docc/GettingStarted.md)** - Installation, basic usage, first PDF\n- **[Performance Guide](Sources/HtmlToPdf/Documentation.docc/PerformanceGuide.md)** - Optimization, benchmarks, tuning\n- **[Configuration Guide](Sources/HtmlToPdf/Documentation.docc/ConfigurationGuide.md)** - All configuration options\n- **[API Documentation](https://coenttb.github.io/swift-html-to-pdf/)** - Full DocC documentation\n\nGenerate docs locally:\n\n```bash\nswift package generate-documentation --open\n```\n\n---\n\n## Testing\n\n```bash\n# All tests\nswift test\n\n# Performance benchmarks\nswift test --filter PerformanceBenchmarks\n\n# Memory analysis\nswift test --filter WebViewMemoryTests\n\n# Stress tests (10K-1M PDFs)\nswift test --filter StressTests\n```\n\n---\n\n## Platform Support\n\n| Platform    | Status           | Notes                                      |\n|-------------|------------------|--------------------------------------------|\n| **macOS**   | ✅ Full support  | Optimal performance, 8 concurrent workers (8-core) |\n| **iOS**     | ✅ Full support  | 8 concurrent workers, mobile-optimized     |\n| **Linux**   | 🚧 Coming soon   | Architecture ready, needs WebKit renderer  |\n| **Windows** | 🚧 Possible      | Pending WebKit integration                 |\n\n---\n\n## Contributing\n\nContributions welcome! Please:\n\n1. **Add tests** - We have 95%+ coverage\n2. **Follow conventions** - Swift 6, strict concurrency, no force-unwraps\n3. **Update docs** - DocC comments + README updates\n\n**Areas for contribution:**\n- Linux support (implement WebKit renderer)\n- Performance improvements\n- Documentation and examples\n- Bug reports with reproduction steps\n\n---\n\n## Related Projects\n\nPart of the [coenttb Swift ecosystem](https://github.com/coenttb), and optionally integrates with [swift-html](https://github.com/coenttb/swift-html) - Type-safe HTML \u0026 CSS DSL.\n\nBuilt on [Point-Free](https://www.pointfree.co)'s [swift-dependencies](https://github.com/pointfreeco/swift-dependencies), and integrates with [swift-metrics](https://github.com/apple/swift-metrics). \n\n---\n\n## License\n\nApache 2.0 - See [LICENSE](LICENSE) for details.\n\n---\n\n## Acknowledgments\n\n- **Point-Free** for swift-dependencies and HTML DSL foundations\n- **Apple** for WKWebView and Swift 6\n- **The Swift Community** for feedback and contributions\n\n---\n\n**Questions?**\n\n- **Issues:** [GitHub Issues](https://github.com/coenttb/swift-html-to-pdf/issues)\n- **Discussions:** [GitHub Discussions](https://github.com/coenttb/swift-html-to-pdf/discussions)\n- **Email:** [coen@coenttb.com](mailto:coen@coenttb.com)\n\n---\n\n**Made with ❤️ by [Coen ten Thije Boonkkamp](https://coenttb.com)**\n\n⚡ **Fast** • 💾 **Efficient** • 🎯 **Type-Safe** • 🧪 **Production-Ready**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoenttb%2Fswift-html-to-pdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoenttb%2Fswift-html-to-pdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoenttb%2Fswift-html-to-pdf/lists"}