Skip to content

thoven87/gotenberg-kit

Repository files navigation

GotenbergKit

CI

A Swift library that interacts with Gotenberg's different modules to convert a variety of document formats to PDF files.

Table of Contents

  1. Getting Started
  2. Authentication
  3. Core Features
  4. Usage Example

Getting Started

Snippets

To incorporate gotenberg-kit into your project, follow the snippets below for SPM dependencies.

SPM

.package(url: "https://github.com/thoven87/gotenberg-kit.git", from: "0.1.0")

.target(name: "MyApp", dependencies: [.product(name: "GotenbergKit", package: "gotenberg-kit")]),

Prerequisites

Before attempting to use GotenbergKit, be sure you install Docker if you have not already done so.

Once the docker Daemon is up and running, you can start a default Docker container of Gotenberg as follows:

docker run --rm -p 7100:7100 gotenberg/gotenberg:8 gotenberg --api-port=7100

Configuration

Create an instance of Gotenberg class and pass your Gotenberg endpoint url as a constructor parameter.

let client = GotenbergClient(
    baseURL: URL(string: ProcessInfo.processInfo.environment["GOTENBERG_URL"] ?? "http://localhost:7100")!
)

Authentication

Basic Authentication

Gotenberg introduces basic authentication support starting from version 8.4.0. Suppose you are running a Docker container using the command below:

docker run --rm -p 3000:3000 \
-e GOTENBERG_API_BASIC_AUTH_USERNAME=gotenberg \
-e GOTENBERG_API_BASIC_AUTH_PASSWORD=password \
gotenberg/gotenberg:8 gotenberg --api-enable-basic-auth

To integrate this setup with Chromiumly, you need to update your client instance as outlined below:

let client = GotenbergClient(
    baseURL: URL(
        string: ProcessInfo.processInfo.environment["GOTENBERG_URL"] ?? "http://localhost:7100"
    )!,
    username: "gotenberg",
    password: "password"
)

Advanced Authentication

To implement advanced authentication or add custom HTTP headers to your requests, you can use the customHttpHeaders option during initialization or for every function call. This allows you to pass additional headers, such as authentication tokens or custom metadata, with each API call.

For example, you can include a Bearer token for authentication along with a custom header as follows:

let client = GotenbergClient(
    baseURL: URL(
        string: ProcessInfo.processInfo.environment["GOTENBERG_URL"] ?? "http://localhost:7100"
    )!
)

let token = try await generateToken()

let response = try await client.convert(
    url: URL(string: "https://swift.org")!,
    clientHTTPHeaders: [
        "Authorization": "Bearer \(token)",
        "X-Custom-Header": "value",
    ]
)

Core Features

GotenbergKit exposes different funcs that serve as wrappers to Gotenberg's routes

Chromium

GotenbergKit client comes with a convert function that call one of Chromium's routes to convert html, markdown files, or a url to a GotenbergResponse which holds the content of the converted PDF file.

convert expects two parameters; the first parameter represents what will be converted (i.e. url, html, or markdown files), and the second one is a ChromiumOptions parameter.

URL

let response = try await client.convertUrl("https://gotenberg.dev/")
let response = try await client.capture(url: URL(string: "https://gotenberg.dev/")!)

HTML

The only requirement is that one of the files name should be index.html.

let index = try Data(contentsOf: URL(string:"path/to/index.html"))
let header = try Data(contentsOf: URL(string:"path/to/header.html"))
let response = try await client.convertHtml(
    documents: [
        "index.html": index,
        "header.html": header
    ]
)
let response = try await client.capture(
    htmlString: "<html>CONTENT</html>"
)

Markdown

This route accepts an index.html file plus a markdown file.

let html = """
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>My PDF</title>
</head>
<body>
    {{ toHTML "file.md" }}
</body>
"""
let response = try await client.convertMarkdown(
    files: [
        "index.html": html.data(using: .utf8)!,
        "file.md": "Markdown Content".data(using: .utf8)!
    ]
)

let response = try await client.capture(
    html: html.data(using: .utf8)!,
    markdown: "Markdown Content".data(using: .utf8)!
)

Each convert() method takes an optional properties parameter of the following type which dictates how the PDF generated file will look like.

ChromiumOptions

In addition to the ChromiumOptions customization options, the convert() method also accepts a set of parameters to further enhance the versatility of the conversion process.

Screenshot

Similarly, the capture() function takes an optional properties parameter of the specified type, influencing the appearance of the captured screenshot file.

ScreenshotOptions

LibreOffice

The LibreOffice utility comes with a function called convertWithLibreOffice. This function interacts with LibreOffice route to convert different documents to PDF files. You can find the file extensions accepted here.

let response = try await client.convertWithLibreOffice(
    urls: [
        .init(url: "https://someurl.com/myfile.csv"),
        .init(url: "https://someurl.com/myfile.odt"),
        .init(url: "https://someurl.com/myfile.doc"),
        .init(url: "https://someurl.com/myfile.pdf")
    ],
)

Similarly to Chromium's route convert function, this function takes the following optional parameters :

LibreOfficeConversionOptions

Note: not setting merge to true will return a zip file containing all PDF files

PDF Engines

The PDFEngines funcs interacts with Gotenberg's PDF Engines routes to manipulate PDF files.

Format Conversion

This function interacts with PDF Engines convertion route to transform PDF files into the requested PDF/A format and/or PDF/UA.

let response = try await client.convertWithPDFEngines(
    documents: [
        "file_1.pdf": Data,
        "file_2.pdf": Data
    ],
    options: PDFEngineOptions(
        pdfua: true,
        format: .A1B
    )
)

let response = try await client.convertWithPDFEngines(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ],
    options: PDFEngineOptions(
        pdfua: true,
        format: .A1B
    )
)

Merging

These functions interact with PDF Engines merge route which gathers different engines that can manipulate and merge PDF files such as: PDFtk, PDFcpu, QPDF, and UNO.

let response = try await client.mergeWithPDFEngines(
    documents: [
        "file_1.pdf": Data,
        "file_2.pdf": Data
    ],
    options: PDFEngineOptions(
        pdfua: true,
        format: .A1B
    )
)

let response = try await client.mergeWithPDFEngines(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ],
    options: PDFEngineOptions(
        pdfua: true,
        format: .A1B
    )
)

Metadata Management

readMetadata

This function reads metadata from the provided PDF files.

let response = try await client.readPDFMetadata(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ],
)

let response = try await client.readPDFMetadata(
    documents: [
        "file_1.pdf": Data,
        "file_2.pdf": Data
    ]
)
writeMetadata

This function writes metadata to the provided PDF files.

let response = try await client.writePDFMetadata(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ],
    metadata: [
        "Author": "Stevenson Michel",
        "Title": "GotenbergKit"
        "Keywords": ["pdf"', "gotenberg", "swift"]
    ]
)

Referr to ExifTool for a comprehensive list of accessible metadata options.

PDF Splitting

Each Chromium and LibreOffice route has a split parameter that allows splitting a PDF file into multiple files. The split parameter is an object with the following properties:

  • mode: the mode of the split. It can be pages or intervals.
  • span: the span of the split. It is a string that represents the range of pages to split.
  • unify: a boolean that allows unifying the split files. Only works when mode is pages.
  • flatten: a boolean that, when set to true, flattens the split PDF files, making form fields and annotations uneditable.
let response = try await client.convertUrl(
    url: URL(string: "https://gotenberg.dev")!,
    options: ChromiumOptions(
        mode: .pages,
        span: "1-2",
        unify: true,
    ),
)

On the other hand, PDFEngines' has a split function that interacts with PDF Engines split route which splits PDF files into multiple files.

let response = try await client.splitPDF(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ],
    options: SplitPDFOptions(
        splitMode: .pages,
        splitSpan: "1-2",
        splitUnify: true,
    ),
)

⚠️ Note: Gotenberg does not currently validate the span value when mode is set to pages, as the validation depends on the chosen engine for the split feature. See PDF Engines module configuration for more details.

PDF Flattening

PDF flattening converts interactive elements like forms and annotations into a static PDF. This ensures the document looks the same everywhere and prevents further edits.

let response = try await client.flattenPDF(
    urls: [
       .init(url: "https://someurl.com/myfile.pdf")
    ]
)

File Generation

client.writeToFile is just a complementary function that takes the GotenbergResponse returned by any functions beside readPDFMetadata, and a chosen filepath with name to generate a PDF file or zip file. Note that note that this function will not create sub directories if not already exist.