Skip to content

A Swift package providing an easy-to-use interface for concurrently printing HTML to PDF on iOS and macOS.

License

Notifications You must be signed in to change notification settings

coenttb/swift-html-to-pdf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

84 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HtmlToPdf

HtmlToPdf provides an easy-to-use interface for concurrently printing HTML to PDF on iOS and macOS.

Features

  • Convert HTML strings to PDF documents on both iOS and macOS.
  • Lightweight and fast: it can handle thousands of documents quickly.
  • Customize margins for PDF documents.
  • Swift 6 language mode enabled
  • And one more thing: easily print images in your PDFs!

Examples

Print to a file url:

try await "<html><body><h1>Hello, World 1!</h1></body></html>".print(to: URL(...))

Print to a directory with a file title.

let directory = URL(...)
let html = "<html><body><h1>Hello, World 1!</h1></body></html>"
try await html.print(title: "file title", to: directory)

Print a collection to a directory.

let directory = URL(...)
try await [
    html,
    html,
    html,
    ....
]
.print(to: directory)

Performance

The package includes a test that prints 1000 HTML strings to PDFs in ~2.6 seconds (using UIPrintPageRenderer on iOS or Mac Catalyst) or ~12 seconds (using NSPrintOperation on MacOS).

@Test func collection() async throws {
    [...]
    let count = 1_000
    try await [String].init(
        repeating: "<html><body><h1>Hello, World 1!</h1></body></html>",
        count: count
    )
    .print(to: URL(...))
    [...]
}

AsyncStream<URL>

Optionally, you can invoke an overload that returns an AsyncStream<URL> that yields the URL of each printed PDF.

Note

You need to include the AsyncStream type signature in the variable declaration, otherwise the return value will be Void.

let directory = URL(...)
let urls: AsyncStream = try await [
    html,
    html,
    html,
    ....
]
.print(to: directory)

for await url in urls {
    Swift.print(url)
}

Including Images in PDFs

HtmlToPdf supports base64-encoded images out of the box.

Important

You are responsible for encoding your images to base64.

Example HTML

The example below will correctly render the image in the HTML, assuming the [...] is replaced with a valid base64-encoded string.

"<html><body><h1>Hello, World 1!</h1><img src="data:image/png;charset=utf-8;base64, [...]" alt="imageDescription"></body></html>"
   .print(to: URL(...))

Tip

You can use swift to load the image from a relative or absolute path and then convert them to base64. Here's how you can achieve this using the convenience initializer on Image using coenttb/swift-html:

struct Example: HTML {
    var body: some HTML {
        [...]
        if let image = Image(base64EncodedFromURL: "path/to/your/image.jpg", description: "Description of the image") {
            image
        }
        [...]
    }
} 

Click here for the implementation of Image.init(base64EncodedFromURL:), which shows how to encode an image to base64.

Related projects

The coenttb stack

PointFree foundations

Known Issues

WebKit Process Assertion Warnings

When running tests or using this library in a command-line environment, you may see warnings like:

Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 
"(target is not running or doesn't have entitlement com.apple.runningboard.assertions.webkit AND 
originator doesn't have entitlement com.apple.runningboard.assertions.webkit)" 
UserInfo={NSLocalizedFailureReason=(target is not running or doesn't have entitlement 
com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement 
com.apple.runningboard.assertions.webkit)}>

Why This Happens

These warnings occur because:

  1. WebKit in Non-UI Contexts: This library uses WKWebView to render HTML to PDF, which is designed for use in UI applications, not command-line or test environments.

  2. RunningBoard Service: macOS uses RunningBoard Service (RBS) to manage process lifecycles. When WebKit processes start in a non-UI context, RBS tries to create process assertions but cannot because the process lacks the required entitlements.

  3. Missing Entitlements: The com.apple.runningboard.assertions.webkit entitlement is needed to properly manage WebKit processes, but is only available to proper UI applications.

Impact

Despite these warnings, the library should still function correctly. These messages are warnings, not errors, and don't prevent the PDF generation from working.

Potential Solutions

If these warnings are problematic:

  1. Use in a UI Application: Use this library in a proper UI application context where entitlements can be properly assigned.

  2. Create Test Mocks: For testing, create mock implementations that don't use real WebKit processes.

  3. Custom Test Runner: Run tests inside a properly entitlemented app bundle rather than directly.

Installation

To install the package, add the following line to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/coenttb/swift-html-to-pdf.git", from: "0.1.0")
]

You can then make HtmlToPdf available to your Package's target by including HtmlToPdf in your target's dependencies as follows:

targets: [
    .target(
        name: "TheNameOfYourTarget",
        dependencies: [
            .product(name: "HtmlToPdf", package: "swift-html-to-pdf")
        ]
    )
]

About

A Swift package providing an easy-to-use interface for concurrently printing HTML to PDF on iOS and macOS.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages