pdg XML → PDF

Guide

Ruby

The pdg gem — render an XML document to a PDF from Ruby, or raise with the engine's diagnostics.

The pdg gem renders a pdg XML document to PDF bytes. The engine is packed into the gem (one gem bundles a prebuilt binary for every platform), so there's no Rust toolchain to install and nothing to compile.

require "pdg"

pdf = PDG.render(File.read("invoice.xml"), base: "invoices")
File.binwrite("invoice.pdf", pdf)

The XML you pass is the document format documented throughout these guides — see Document structure and the element reference.

Installation

Add it to your Gemfile:

gem "pdg"
bundle install

Rendering

Three entry points, all taking the document as a string and a base: directory (see Assets below):

# PDF bytes (a binary String). Raises on failure.
pdf = PDG.render(xml, base: ".")

# Bytes plus metadata.
result = PDG.render_with_meta(xml, base: ".")
result.pages      # => 3
result.bytes      # => 48213 (size of result.pdf)
result.objects    # => 412   (positioned primitives)
result.timings    # => { "parseMs" => 1.2, "layoutMs" => 8.4, "pdfMs" => 5.1 }
result.warnings   # => [PDG::Diagnostic, ...]
result.pdf        # => "%PDF-2.0…"

# Render straight to a file (returns the Result).
PDG.render_file(xml, "report.pdf", base: "assets")

Assets

Relative paths inside the document — <font-face src>, <image src>, <pdf src> — resolve against base, since a string has no directory of its own. base defaults to the current working directory.

PDG.render(xml, base: Rails.root.join("app/pdf_assets").to_s)

http(s) URLs and <google-font> faces are fetched by the engine regardless of base.

Errors and diagnostics

Everything the gem raises descends from PDG::Error.

  • PDG::RenderError — the engine withheld a PDF: a strict-mode block (the document set <diagnostics mode="strict"> and an error was recorded) or a fatal parse/layout error. It carries the structured diagnostics.
  • PDG::BinaryError — the engine couldn't run (an installation/environment problem, never a problem with the document).
begin
  pdf = PDG.render(xml)
rescue PDG::RenderError => e
  warn e.message            # headline plus each diagnostic, one per line
  e.diagnostics.each do |d|
    d.severity              # "warning" | "error"
    d.code                  # "unknown-tag", "content-dropped", …
    d.message
    d.line                  # 1-based source position (0 if none)
    d.col
    d.trace                 # enclosing tags, innermost first
  end
end

Warnings never raise — a document that renders with recoverable problems returns a Result; inspect result.warnings. Only withheld output raises.

Rails

For rendering PDFs from controllers with views, layouts, and partials, use the Rails guide and the pdg-rails gem — it builds on this gem.

How it works

The gem shells out to the packed engine over a small stdio contract (XML on stdin, PDF on stdout, one JSON meta object on stderr) behind a single adapter, so the same engine that powers the CLI and this playground produces your PDFs. Point the PDG_BINARY environment variable at a pdg binary to override the bundled one.