Changing Your PDF Library without Rewriting Everything

Only part of your program writes documents. Your page designs, your data, your business rules and your screens do not move. What moves is the handful of files that turn a row of data into a page — and those files are built on the same ideas as the engine here.

What You Replace, and What You Leave Alone

Picture your invoicing program. There is the part that decides what goes on an invoice: which customer, which lines, which totals, which rules apply in which country. And there is the part that puts it on paper: this text here, that table there, the logo top left, the barcode bottom right.

Only the second part changes. The first part — the one that took years to get right — is not involved at all. It goes on handing over the same figures. Something else creates the pages.

Nothing else on your side moves either: your database, your web server, your schedules, the way documents are stored and sent, your tests, your build. Your customers get the same invoice.

What Is the Same

Every library that writes PDF is built on the same handful of ideas, because the format has them and nobody gets to invent others. A page of a size. A font put into the file. A block of text that flows and breaks where it runs out of room. A table with columns and rules. A picture, placed and scaled. A barcode. A field somebody fills in. A signature. A set of facts about the document.

You will find all of it here, under names of our own choosing, doing the same job. Somebody whose job has already been writing documents recognises every one of them and has only our names to learn.

What Is Different

Our names are our own, our way of laying out a page is our own, and your programmers rewrite the calls.

What they do not rewrite is the design. The page you have today, with the logo at that height and the table starting at that line, is described again — it is not invented again.

Two more differences. Our engine is called from Rust and from Python; if your program is written in another language, a C API is planned for a future version, and today you would go through the server instead — you send it what to put on the page and it hands you the document, which works from any language at all. And the way you ask for things is written down in full on this site, page by page, with a document to download for each: you can read the whole of it before you commit to anything.

How Long It Takes

Nobody can tell you to the day without seeing your program. Count your document models — not your documents. An invoice is one model even if you send four hundred thousand of them; an invoice, a credit note, a delivery note, a statement and a reminder are five.

What decides the length is that number, how much of your layout is a table running over many pages, and how deeply the code that creates the document is tangled into the rest of your program. Nothing else weighs on it: your data, your rules and your screens stay where they are.

Whatever the size, do this first: take your single most complicated document, write it again with us, and put the two side by side. If that one comes out right, the rest is repetition. If it does not, you have found out at the beginning rather than at the end.

However long yours turns out to be, the team stays with you. The people who write the engine are the people who answer your messages, within a working day and usually less.

Everything the engine writes today

Here is what the engine writes today. It is the list to hold your own requirements against, line by line.

Text
your own fonts carried inside the file, only the letters actually used travelling with it, text that stays selectable and searchable, text that flows over columns and pages, and text you can measure before you draw it.
Tables
columns you size or let the engine size, rules and borders side by side, cells that span, headings repeated at the top of each page, a table that runs over as many pages as it needs.
Images
JPEG, PNG, BMP and TIFF, placed, scaled and cut to shape; a TIFF holding several pictures is read picture by picture.
Colour and Printing
the colours a screen uses and the four inks a press uses, ICC colour profiles, spot inks, overprint, and the flag saying whether the job was trapped. Crop and bleed marks are drawn on the page like anything else, and three of the examples draw theirs.
Barcodes and Square Codes
the striped codes of the shop till, the warehouse and the workshop bench — Code 128, Code 39, Code 93, ITF-14, Codabar, EAN-13, UPC-A, EAN-8, UPC-E, GS1 DataBar and the two add-ons — plus QR codes, Data Matrix, PDF417 and Aztec.
Forms
fields somebody types into, ticks, chooses from a list, and signs.
Standards
PDF/A-2, PDF/A-3 and PDF/A-4 for keeping a document readable, PDF/X-4 for the press, PDF/UA-1 and PDF/UA-2 for a document readable without seeing the page, Factur-X for the electronic invoice — the one built on the European standard EN 16931 — and full tagging underneath all of it.
Signing
PAdES signatures, with your certificate staying on your machine and never on ours.
Protection
AES-256 encryption, a password before the first page shows, and permissions per action.
Reading a PDF You Already Have
open a file written by another program, read its pages, notes, links, fields, bookmarks, layers and structure, and take a whole page of it into the document you are writing.
The File Itself
every usual page size and any size you name, a chosen level of squeezing, a chosen format version, the same data giving back the same bytes every time (a date or an encryption key comes from the program that calls it), and — the one worth a page of its own — a document written so its first page shows before the file has finished arriving. The book itself How that works, and what it saves

Planned for a future version: a C API, which any language able to call C can use, and automatic substitution of a missing font.

Technically

Two language surfaces over one core, each linked into a program of your own: a Rust crate and a CPython wheel built on the stable ABI, both offline, both deterministic, both pinned to a version and resolvable from your own artefact store. The Python surface is the Rust surface — same object families, same call names transposed to Python conventions — so a proof of concept in Python transfers to Rust, or the other way round, without a redesign.

The calls take typed objects, not option strings: you build the objects and hand them to a document. That is a real rewrite cost wherever the calls are written and a real gain on everything after — the compiler catches at build time what a string API catches at run time on the customer's machine.

Layout is measurable before it is committed: ask the width a span of text will occupy, ask the largest size at which a title still fits a given width, ask a flowing block how far it got and get back where it stopped. That is what lets a migration be verified against the old output rather than eyeballed.

Every worked example on this site exists in Rust and in Python, and a growing share of them a third time as a JSON request the server answers. A script re-runs all three and compares the results, byte for byte where the two ways of asking write the same instructions, dot for dot where they do not. That comparison is already written, and it is the shape to copy for verifying your own migration: the old file and the new one, page by page, compared by a program rather than by somebody scrolling.

A third route, with nothing linked into your program: send the server a JSON request describing the document and it hands back the PDF. That is the route for a program written in neither Rust nor Python, and it is the route to start on while the migration itself is planned.

Where to Look Next

Everything the engine puts on a page, group by group The Engine inside Your Own Program Asking for a document over the internet, with nothing to install The electronic invoice, and the dates the law sets

See the Prices See the Examples