tclpdf - PDF generation for Tcl
Synopsis
Create PDF documents from Tcl: pages, graphics, embedded fonts, images, tables and electronic invoices. A pure Tcl package - no compiler, no binary extension, no Tk.
Beyond the usual page, text and graphics work it does two things a PDF writer often leaves out: general file attachments, and form XObjects that store a drawing once and place it as often as wanted. A document is a TclOO object, every command takes Tcl-style -options, and the topical modules are loaded on first use - a caller who writes text never loads the image code.
- Document and graphics - pages and the five page boxes, paths, clipping to a rectangle or an arbitrary path, transparency, form XObjects, tiling patterns, axial and radial shadings, RGB / CMYK / grey / separation colours and 148 colour names without Tk.
- Fonts - the fourteen standard faces, and three formats to embed: TrueType as Type0/CIDFontType2 with Identity-H and a ToUnicode CMap, subset down to the glyphs actually used; OpenType with CFF outlines and Type 1 whole, since subsetting either would need outlines this package does not read. Pair kerning and the standard ligatures are applied from the font's own tables, both on by default. A missing character raises an error instead of disappearing silently.
- Images - JPEG and PNG, both passed through unchanged wherever possible: a JPEG goes in as /DCTDecode, a PNG without alpha as /FlateDecode with /Predictor 15. Neither is ever decoded. PNG alpha becomes a soft mask.
- Tables - column widths, cell wrapping, page breaks with repeated header and footer rows, rowSpan and colSpan, decimal alignment and per-cell hooks.
- SVG - shapes, paths, transforms, groups, reuse, viewBox and gradients, drawn as PDF vectors rather than as a picture. Text in a drawing uses the same faces as the rest of the document, embedded ones included.
- Barcodes - through tzint, which encodes into SVG that tclpdf then draws as vectors. No encoder of its own, and none needed; tzint is optional.
- Tagged PDF and PDF/A-3a - a structure tree with the 49 standard types, nesting checked against Annex L, and artifacts kept out of it.
Electronic invoices - ZUGFeRD / Factur-X as PDF/A-3B: ICC profile, OutputIntent, XMP with the Factur-X extension schema, embedded XML, file specification, /AF entry and name tree. The conformance level is derived from BT-24 of the invoice XML rather than taken on trust.
Accessibility - a tagged structure tree, and on top of it PDF/UA-1 and PDF/UA-2 with the Well-Tagged PDF declaration. The claim is refused when the document does not keep it: a title, a language, every font embedded including the standard fourteen, headings without a gap, tables with the same number of cells in every row, a description on every link. All of them are reported at once when the file is written, each naming the call to change.
Everything listed here is built and tested. Measured against the page count of its chapters that covers roughly a third of ISO 32000-1 - and the missing two thirds are almost entirely what a reader of foreign PDFs needs rather than a writer, plus encryption and form fields.
Dependencies
- Tcl >= 8.6.11, and it runs under Tcl 9 as well. The test suite is green on both.
- tdom - required. It builds the XMP metadata packet, so every document that declares PDF/A, PDF/UA or ZUGFeRD needs it. It is also what reads SVG, where it parses 27 to 48 times faster than the element tree parser tclpdf brings along and refuses an entity expansion bomb - for SVG alone that fallback still works, so a document with no metadata claim runs without tdom.
- tzint - optional, only for barcodes. It produces SVG, which
svg -datadraws; no code in this package knows about barcodes.
Nothing else is needed: zlib is a command built into Tcl, not a package, and Tk is never loaded - not for colour names, not for images.
Documentation
- man-page - every command, the same text as the manual page
tclpdf(n)the package installs - plugins - extending tclpdf without touching its source: the event bus, the supported methods and two worked examples
The package ships that manual page, tclpdf(n), covering every command.
The source archive adds the test suite and 36 examples, which between them write 38 documents: shapes, colour, text layout, attachments, forms, diagonal stamps, flowing text and text along a path, soft hyphens and leader rows, extending the package from outside, font embedding in three formats, kerning, ligatures, five writing systems, missing glyphs, images, gradients, SVG, labels inside a drawing, barcodes, three kinds of table, two ZUGFeRD invoices, a PDF/A certificate, two tagged documents, an accessible one and a PDF/UA-2 guide, and a navigation demo. Each one is a readable script of its own and says in its header what it is for.
Build them all at once and look at the result:
make examples
That runs every example into examples/out - one PDF each, three for the
writing-systems example, which writes one file per face. make clean removes
the directory again. A single example also runs on its own and takes the output
path as its argument:
tclsh examples/04.01-table-basics.tcl mytable.pdf
See Also
- ISO 32000-1 (PDF 1.7) - free of charge from the PDF Association since 2023
- ZUGFeRD / Factur-X - the German e-invoicing standard this implements
- veraPDF - the PDF/A validator both invoice examples are checked against
- tdom
Legal Notice
Copyright (C) 2026 Alexander Schoepe, Bochum, DE
Tcl package: MIT license. That covers everything the package installs: the Tcl
modules, pkgIndex.tcl and the sRGB ICC profile, which is a runtime part
because its bytes end up inside every PDF/A document.
No font is part of the package. The faces under examples/assets/fonts are
there so that the tests and the examples have something to embed, and they
travel in the source archive alone - make install installs no font, and the
binary archives contain none. They are third-party work under their own terms:
DejaVu under the Bitstream Vera licence, and Roboto, Bitcount Prop Single and
Niconne under the SIL Open Font License 1.1. Whether you may embed a font into
a PDF that tclpdf writes is a question for that font's licence, not for
this one.