PrawnX

A rewrite of Prawn, prawn-table and prawn-svg in one gem: lighter files, faster renders, and PDF/A-3 and Factur-X on top.

gem "prawnx"

In numbers

Loading the latest numbers…

Every measurement, and how to reproduce it

Why

Prawn draws good pages, slowly. Profiling an invoice with a table shows where the time goes: line breaking rebuilds its regular expressions for every line, every number is formatted then patched, and TrueType fonts are read again for each document.

PrawnX keeps Prawn’s Ruby API and its pages, and rewrites what sits underneath. Your code does not change; the PDF it produces looks the same, weighs less, and comes out faster.

What changes

One gem instead of three

pdf.table and pdf.svg work without prawn-table or prawn-svg; require "prawn/table" and require "prawn-svg" keep working.

Installation

Lighter files, same pixels

Every PDF is written as PDF 1.5: compressed streams, the other objects packed in one compressed object stream, a cross-reference stream. Identical images are embedded once.

Output

Fonts parsed once per process

A TrueType or OpenType font is read once, frozen and shared by every document and thread, until its file changes. PrawnX.eager_load! loads it all before a server forks.

Fonts

PDF/A-3 and Factur-X

pdf_a: true writes a PDF/A-3b document; factur_x embeds the invoice XML your invoicing system produced.

PDF/A and Factur-X

Prawn’s bugs, fixed and declared

Each fix is proven by a specification and listed with the exact differences the oracle reports. Everything else matches Prawn.

Compatibility

Safer SVG by default

SVG images fetch nothing from the web unless asked to: a submitted SVG cannot make the server request a URL.

SVG web requests

Same pages

An oracle renders every example of Prawn’s and prawn-table’s manuals and every sample SVG of prawn-svg with Prawn 2.5, prawn-table 0.2.2 and prawn-svg 0.40.4, and with PrawnX, each in its own process. It compares their pages, their text and its positions to 0.01 pt, their pixels at 150 dpi in MuPDF and in Poppler, their validity and their weight. A seeded fuzzer writes random documents and compares them the same way.

How PrawnX is tested

Quick start

Gemfile

gem "prawnx" # instead of prawn, prawn-table and prawn-svg

Your code, unchanged

Prawn::Document.generate("hello.pdf") do
  text "Hello, World!"
  table [%w[SKU Qty], %w[A-1 2]]
end