pdf API reference
Generate PDF documents - text, lines, rectangles - the way html / label generate their formats. Build a Document of Pages with value-semantic builders, then render() writes the PDF object / xref structure by hand (no stdlib PDF) as bytes. Content streams are FlateDecode-compressed via compress. Two font paths: the standard-14 Type1 fonts (Helvetica / Times / Courier families + Symbol / ZapfDingbats) via text, and embedded TrueType fonts via loadFont / addFont / textUnicode - a Type0 / CIDFontType2 composite (Identity-H) with an embedded FontFile2 and a ToUnicode map, so any script the font covers (accented Latin, Greek, Cyrillic, CJK, ...) renders and stays selectable. Raster images embed as image XObjects via loadImage / addImage / drawImage - PNG (greyscale / RGB / palette, plus 8-bit alpha as a soft mask) and JPEG (DCTDecode). Text layout - measureText width measurement (standard-14 AFM metrics + embedded-font advances), wrapText word-wrap, and textBlock wrapped / aligned paragraphs (left / right / center / justify) - flows text into a column. Object numbers are assigned dynamically. Pure Jennifer (over the font module); both binaries.
Coordinates are in PDF points (1/72 inch), origin bottom-left, y upward. Common page sizes: US Letter 612 x 792, A4 595 x 842. Colours are 0-255 RGB.
Import with import "pdf.j" as pdf;. See the pdf guide for prose and examples.
Functions
pdf.addFont(doc as Document, lf as LoadedFont)
A copy of the document with an embedded font registered, so render writes its font program and dictionaries.
Parameters
doc{Document}- the documentlf{LoadedFont}- the loaded font (fromloadFont)
Returns {Document} - a fresh document with the font registered
pdf.addImage(doc as Document, img as Image)
A copy of the document with an embedded image registered, so render writes its image XObject. Draw it on a page with drawImage.
Parameters
doc{Document}- the documentimg{Image}- the loaded image (fromloadImage)
Returns {Document} - a fresh document with the image registered
pdf.addPage(doc as Document, pg as Page)
A copy of the document with a page appended.
Parameters
doc{Document}- the documentpg{Page}- the page to add
Returns {Document} - a fresh document with the page appended
pdf.bookmark(doc as Document, page as int, y as int, title as string, level as int)
A copy of the document with one outline (bookmark) entry appended (value-semantic). Entries are nested by level in the order added: a level-2 entry becomes a child of the most recent level-1, and so on. The destination scrolls page page (0-based) so that y (PDF points, origin bottom-left) is at the top of the view. With any outline present, the viewer opens showing the bookmark panel.
Parameters
doc{Document}- the documentpage{int}- the 0-based index of the destination pagey{int}- the destination y in PDF pointstitle{string}- the bookmark labellevel{int}- the nesting level (>= 1)
Returns {Document} - a copy with the entry appended
pdf.color(pg as Page, red as int, green as int, blue as int)
Set the fill and stroke colour (0-255 RGB) for subsequent drawing on the page.
Parameters
pg{Page}- the pagered{int}- the red component 0-255green{int}- the green component 0-255blue{int}- the blue component 0-255
Returns {Page} - a fresh page with the colour set
pdf.document()
An empty document. The Producer metadata defaults to "Jennifer pdf"; everything else is unset (no CreationDate is stamped, so output stays deterministic - set one explicitly with info + pdfDate if you want it).
Returns {Document} - the document
pdf.drawImage(pg as Page, img as Image, x as int, y as int, width as int, height as int)
Draw a registered image scaled into the rectangle at (x, y) of the given width and height (points). The image keeps no aspect ratio of its own - it fills the box - so pass a width / height in the image's own proportion to avoid stretching. addImage the image into the document first so the resource name resolves.
Parameters
pg{Page}- the pageimg{Image}- the image (fromloadImage)x{int}- the lower-left x in pointsy{int}- the lower-left y in pointswidth{int}- the drawn width in pointsheight{int}- the drawn height in points
Returns {Page} - a fresh page with the image drawn
pdf.foldLine(font as string, size as int, text as string, maxWidth as int)
Hard-fold one line so every piece fits maxWidth (points). Breaks at the last space or seam punctuation before the overflow, or mid-token when there is none (a bare URL, a slash-joined identifier). Unlike wrapText, it does not reflow on every space - it only breaks where a line would otherwise run past the box - so it is the right tool for a code line or an unbreakable token that must stay on the page. A single character wider than maxWidth is emitted alone.
Parameters
font{string}- the standard-14 fontsize{int}- the point sizetext{string}- the line to fold (no embedded newlines)maxWidth{int}- the target width in points
Returns {list of string} - the fitted pieces (at least one)
pdf.getCurrentPageNr(doc as Document)
The 1-based number of the page currently being built - the next page to be added, i.e. getTotalPages(doc) + 1. Use it while filling a page (before addPage) to label it.
Parameters
doc{Document}- the document
Returns {int} - the current page number
pdf.getTotalPages(doc as Document)
The total number of pages added to the document (the value {pages} expands to).
Parameters
doc{Document}- the document
Returns {int} - the page count
pdf.info(doc as Document, key as string, value as string)
A copy of the document with one metadata field set (value-semantic). key is a PDF Info key - "Title", "Author", "Subject", "Keywords", "Creator", "Producer", "CreationDate", "ModDate" (or any custom key).
Parameters
doc{Document}- the documentkey{string}- the Info-dictionary keyvalue{string}- the value
Returns {Document} - a fresh document with the metadata set
pdf.line(pg as Page, fromX as int, fromY as int, toX as int, toY as int)
Draw a straight line from (fromX, fromY) to (toX, toY).
Parameters
pg{Page}- the pagefromX{int}- the start xfromY{int}- the start ytoX{int}- the end xtoY{int}- the end y
Returns {Page} - a fresh page with the line added
pdf.link(pg as Page, x as int, y as int, width as int, height as int, uri as string)
Add a link annotation: a clickable rectangle (lower-left x, y, plus width / height, in PDF points) that opens uri. The border is invisible, so place it over text drawn with text (measure the text width with measureText) to make that text a hyperlink - a footer backlink, a citation, a URL in prose.
Parameters
pg{Page}- the pagex{int}- lower-left x of the clickable rectangley{int}- lower-left y of the clickable rectanglewidth{int}- rectangle width in pointsheight{int}- rectangle height in pointsuri{string}- the URI the link opens
Returns {Page} - the page with the link recorded
pdf.loadFont(name as string, data as bytes)
Load an embeddable font from its bytes, under a resource name used to select it in textUnicode. The font is embedded (and its Unicode text made selectable) when the document renders.
Parameters
name{string}- the resource name (e.g. "Body"; letters / digits)data{bytes}- the TrueType (.ttf) font file
Returns {LoadedFont} - the loaded font
pdf.loadImage(name as string, data as bytes)
Load a raster image (PNG or JPEG) from its bytes, under a resource name used to select it in drawImage. The format is detected from the file signature. PNG: non-interlaced greyscale / RGB / palette (embedded directly with a FlateDecode predictor) and 8-bit greyscale+alpha / RGBA (decoded to a colour stream plus an alpha soft mask). JPEG: baseline / progressive greyscale / RGB / CMYK, embedded as-is via DCTDecode.
Parameters
name{string}- the resource name (e.g. "Logo"; letters / digits)data{bytes}- the PNG or JPEG file
Returns {Image} - the loaded image
Throws
{Error}- kind "pdf" if the data is not a supported PNG / JPEG
pdf.measureText(font as string, size as int, str as string)
Measure the rendered width (in points) of a string in a standard-14 font at a point size, using the Adobe Core-14 AFM metrics. A character outside WinAnsi, or a Symbol / ZapfDingbats font, throws.
Parameters
font{string}- a standard-14 base font namesize{int}- the font size in pointsstr{string}- the text to measure
Returns {float} - the width in points
Throws
{Error}- kind "pdf" for an unknown / metric-less font
pdf.measureTextUnicode(lf as LoadedFont, size as int, str as string)
Measure the rendered width (in points) of a string in an embedded font at a point size, using the font's own glyph advances.
Parameters
lf{LoadedFont}- the embedded fontsize{int}- the font size in pointsstr{string}- the text to measure
Returns {float} - the width in points
pdf.page(width as int, height as int)
A blank page of the given size in points (e.g. page(612, 792) for Letter, page(595, 842) for A4).
Parameters
width{int}- the page width in pointsheight{int}- the page height in points
Returns {Page} - the page
pdf.pageLabel()
A blank page label (empty slots, Helvetica 9pt, 36-point margin, no border, black). Copy it and set slots / options, then attach with setHeader / setFooter.
Returns {PageLabel} - the default label
pdf.pdfDate(t as time.Time)
Format an instant as a PDF date string (D:YYYYMMDDHHmmSS+HH'mm'), for use as a CreationDate / ModDate value. Passing a time is explicit, so it does not make render non-deterministic on its own.
Parameters
t{time.Time}- the instant
Returns {string} - the PDF date string
pdf.rect(pg as Page, x as int, y as int, width as int, height as int, filled as bool)
Draw a rectangle at (x, y) of the given size. filled fills it; otherwise it is stroked (outline only).
Parameters
pg{Page}- the pagex{int}- the lower-left xy{int}- the lower-left ywidth{int}- the width in pointsheight{int}- the height in pointsfilled{bool}- true to fill, false to stroke
Returns {Page} - a fresh page with the rectangle added
pdf.render(doc as Document)
Render the document to PDF bytes (PDF 1.7). Any running header / footer is drawn onto every page first. Content streams are FlateDecode-compressed; standard-14 fonts become shared Type1 objects and each embedded font a Type0 / CIDFontType2 with an embedded FontFile2 and a ToUnicode map. Registered images become image XObjects (with a soft-mask XObject when they carry alpha). An outline (bookmarks) is emitted when the document has any, with the catalog set to open the bookmark panel. Objects are numbered dynamically, so any mix of pages, fonts, images, and resources references correctly.
Parameters
doc{Document}- the document to render
Returns {bytes} - the PDF file contents
pdf.setFooter(doc as Document, label as PageLabel)
Attach a running footer, drawn on every page when the document renders.
Parameters
doc{Document}- the documentlabel{PageLabel}- the footer spec
Returns {Document} - the document with the footer set
pdf.setHeader(doc as Document, label as PageLabel)
Attach a running header, drawn on every page when the document renders.
Parameters
doc{Document}- the documentlabel{PageLabel}- the header spec
Returns {Document} - the document with the header set
pdf.text(pg as Page, x as int, y as int, font as string, size as int, str as string)
Draw a line of text at (x, y) in the given standard-14 font and point size.
Parameters
pg{Page}- the pagex{int}- the x position (points from the left)y{int}- the y position (points from the bottom)font{string}- a standard-14 base font name (e.g. "Helvetica")size{int}- the font size in pointsstr{string}- the text to draw
Returns {Page} - a fresh page with the text added
Throws
{Error}- kind "pdf" if the font is not a standard-14 name
pdf.textBlock(pg as Page, x as int, y as int, width as int, font as string, size as int, leading as int, str as string, align as string)
Flow standard-14 text into a column: word-wrap str to width points and draw each line, the first line's baseline at (x, y) and each subsequent line leading points lower. align is "left" / "right" / "center" / "justify" (justify pads inter-word gaps on every line but the last of each paragraph). The drawn block is len(wrapText(...)) * leading points tall.
Parameters
pg{Page}- the pagex{int}- the column's left x in pointsy{int}- the first line's baseline y in pointswidth{int}- the column width in pointsfont{string}- a standard-14 base font namesize{int}- the font size in pointsleading{int}- the line-to-line spacing in pointsstr{string}- the text (newlines are hard breaks)align{string}- "left" / "right" / "center" / "justify"
Returns {Page} - a fresh page with the text block drawn
Throws
{Error}- kind "pdf" for an unknown align or font
pdf.textBlockUnicode(pg as Page, x as int, y as int, width as int, lf as LoadedFont, size as int, leading as int, str as string, align as string)
Flow embedded-font (Unicode) text into a column - textBlock for a font from loadFont / addFont. Same wrapping / alignment / leading behaviour.
Parameters
pg{Page}- the pagex{int}- the column's left x in pointsy{int}- the first line's baseline y in pointswidth{int}- the column width in pointslf{LoadedFont}- the embedded fontsize{int}- the font size in pointsleading{int}- the line-to-line spacing in pointsstr{string}- the text (newlines are hard breaks)align{string}- "left" / "right" / "center" / "justify"
Returns {Page} - a fresh page with the text block drawn
Throws
{Error}- kind "pdf" for an unknown align
pdf.textUnicode(pg as Page, x as int, y as int, lf as LoadedFont, size as int, str as string)
Draw Unicode text at (x, y) in an embedded font (from loadFont + addFont) at the given point size. Each character maps through the font's cmap to a glyph, so any script the font covers - including CJK - renders and stays selectable / copyable in a viewer.
Parameters
pg{Page}- the pagex{int}- the x position (points from the left)y{int}- the y position (points from the bottom)lf{LoadedFont}- the embedded fontsize{int}- the font size in pointsstr{string}- the text to draw
Returns {Page} - a fresh page with the text added
pdf.toWinAnsi(s as string, replacement as string)
Return s with every character the standard-14 fonts cannot encode (outside WinAnsi / windows-1252) replaced by replacement ("" drops it). A clean string (the common case) is returned unchanged after a single whole-string check, so the per-character path runs only when there is something to replace. This lets a caller keep one out-of-range glyph from aborting a whole render.
Parameters
s{string}- the textreplacement{string}- the substitute for an un-encodable character
Returns {string} - the WinAnsi-safe text
pdf.wrapText(font as string, size as int, str as string, maxWidth as int)
Word-wrap a standard-14 string to a maximum line width (points), returning the lines. Existing newlines are honoured as hard breaks; runs of spaces collapse. A word-wrapped line still wider than the box (an unbreakable token) is hard-folded with foldLine, so no output line runs past maxWidth.
Parameters
font{string}- a standard-14 base font namesize{int}- the font size in pointsstr{string}- the text to wrapmaxWidth{int}- the maximum line width in points
Returns {list of string} - the wrapped lines
pdf.wrapTextUnicode(lf as LoadedFont, size as int, str as string, maxWidth as int)
Word-wrap an embedded-font string to a maximum line width (points).
Parameters
lf{LoadedFont}- the embedded fontsize{int}- the font size in pointsstr{string}- the text to wrapmaxWidth{int}- the maximum line width in points
Returns {list of string} - the wrapped lines
Structs
pdf.Document
A PDF document: an ordered list of pages, the document metadata (the PDF Info dictionary, keyed by PDF key name - "Title", "Author", ...), any embedded fonts registered with addFont, any outline (bookmark) entries, and an optional running header / footer drawn on every page at render time.
| Field | Type | Description |
|---|---|---|
pages | list of Page | the document's pages |
info | map of string to string | the Info-dictionary metadata |
embedded | list of LoadedFont | the embedded fonts |
images | list of Image | the embedded raster images |
outline | list of OutlineEntry | the outline / bookmark entries, in document order |
header | PageLabel | the running header (drawn when headerOn) |
footer | PageLabel | the running footer (drawn when footerOn) |
headerOn | bool | whether a header has been set |
footerOn | bool | whether a footer has been set |
pdf.GlyphUse
A record of one glyph used by embedded text: which font, its glyph id, and the Unicode codepoint it came from - collected so render can build the font's width array and ToUnicode map.
| Field | Type | Description |
|---|---|---|
font | string | the font resource name |
gid | int | the glyph id |
cp | int | the source Unicode codepoint |
pdf.Image
A loaded raster image (from loadImage), ready to embed as a PDF image XObject and draw with drawImage. Register it in a document with addImage.
| Field | Type | Description |
|---|---|---|
name | string | the resource name (referenced in drawImage) |
width | int | the pixel width |
height | int | the pixel height |
bits | int | bits per colour component |
colorSpace | string | the PDF colour-space token (e.g. "/DeviceRGB") |
filter | string | the stream filter ("DCTDecode" for JPEG, "FlateDecode" for PNG) |
predictor | int | 15 when the FlateDecode stream carries PNG predictors, else 0 |
colors | int | colour components per pixel (for the predictor DecodeParms) |
decode | string | an optional /Decode array token (Adobe CMYK JPEG), else "" |
data | bytes | the image stream bytes |
smask | bytes | the soft-mask (alpha) stream, empty when opaque |
hasSmask | bool | whether the image carries an alpha soft mask |
pdf.LinkAnnot
A link annotation: a clickable rectangle on a page that opens a URI. The rect is given in PDF points by its lower-left corner and its size; the border is drawn invisibly, so only the underlying text (or graphic) shows.
| Field | Type | Description |
|---|---|---|
x | int | lower-left x of the clickable rectangle |
y | int | lower-left y of the clickable rectangle |
width | int | rectangle width in points |
height | int | rectangle height in points |
uri | string | the URI the link opens |
pdf.LoadedFont
A loaded, embeddable font: a resource name (referenced in textUnicode) and the parsed font.Font. Register it in a document with addFont.
| Field | Type | Description |
|---|---|---|
name | string | the resource name (e.g. "Body") |
f | font.Font | the parsed font |
pdf.OutlineEntry
One outline (bookmark) entry: a title that jumps to a position on a page, plus the heading level that nests it under the outline tree. Built with bookmark.
| Field | Type | Description |
|---|---|---|
title | string | the bookmark label |
page | int | the 0-based page index the bookmark points at |
y | int | the destination y coordinate in PDF points (origin bottom-left) |
level | int | the nesting level (1 = top; a level-2 entry nests under the last level-1) |
pdf.Page
A single page: its size (points), its accumulated content-stream operators, and its link annotations.
| Field | Type | Description |
|---|---|---|
width | int | the page width in points |
height | int | the page height in points |
content | string | the content-stream operators built so far |
fonts | list of string | the distinct standard-14 fonts referenced on this page |
glyphUses | list of GlyphUse | embedded-font glyphs drawn on this page |
annots | list of LinkAnnot | the page's link annotations |
pdf.PageLabel
A running header or footer, drawn on every page at render time. Its three text slots are left- / centre- / right-aligned (alignment measured with the font's own metrics), and each may contain the placeholders %page% (the 1-based page number) and %pages% (the total page count), filled in per page - so a footer "sample.pdf" / "" / "%page%/%pages%" reads sample.pdf ... 13/108. The placeholders are percent-delimited (not braces) so they do not collide with Jennifer's own {expr} string interpolation. margin is the distance from the page edge to the text on every side. With border on, a thin rule is drawn under a header / over a footer.
| Field | Type | Description |
|---|---|---|
left | string | left-aligned slot (may use %page% / %pages%) |
center | string | centre-aligned slot |
right | string | right-aligned slot |
font | string | a standard-14 font name |
size | int | the point size |
margin | int | distance from the page edge, in points |
border | bool | draw a separating rule |
red | int | text / rule colour red 0-255 |
green | int | text / rule colour green 0-255 |
blue | int | text / rule colour blue 0-255 |
leftUri | string | if set, makes the left slot a link to this URI ("" = none) |
centerUri | string | if set, makes the centre slot a link to this URI ("" = none) |
rightUri | string | if set, makes the right slot a link to this URI ("" = none) |