Tincture.PDF.Object (Tincture v0.1.0)

Copy Markdown View Source

Primitives for writing PDF object syntax.

These are the leaf encoders shared by everything that emits PDF: numbers, strings and names. They were previously private to Tincture.PDF.Serialize, which meant the font-embedding code and the page-structure code could only reach them by living in the same 3,500-line module.

Two string encodings matter here:

  • :pdf_text — a document string such as a title, bookmark label or link URL. ASCII is written as a literal (...) with the reserved bytes escaped; anything else becomes a UTF-16BE hex string with a byte order mark, which is how the PDF specification carries non-Latin-1 text.
  • :identity_h — text drawn with a composite (Type0) font, where the bytes are glyph indices rather than characters and must be written as hex with no byte order mark.

Summary

Functions

Encode text without delimiters, reporting which form was produced.

Escape one byte for inclusion in a literal PDF string.

Encode text as a PDF string, wrapped in its delimiters.

Format a number for PDF output.

Reduce name to characters legal in a PDF name object.

Returns true when text contains anything outside 7-bit ASCII, and therefore cannot be written as a literal PDF string.

Functions

encode_text(text, atom)

@spec encode_text(String.t(), :pdf_text | :identity_h) ::
  {:literal, String.t()} | {:hex, String.t()}

Encode text without delimiters, reporting which form was produced.

escape_byte(byte)

@spec escape_byte(integer()) :: String.t()

Escape one byte for inclusion in a literal PDF string.

Parentheses and the backslash are the reserved characters; anything outside printable ASCII is written as a three-digit octal escape.

format_text(text, mode \\ :pdf_text)

@spec format_text(String.t(), :pdf_text | :identity_h) :: String.t()

Encode text as a PDF string, wrapped in its delimiters.

See the module documentation for the difference between the two modes.

num(value)

@spec num(number()) :: String.t()

Format a number for PDF output.

Floats are written with up to ten decimals and no trailing zeros, so coordinates stay readable and byte-stable across runs.

sanitize_name(name)

@spec sanitize_name(String.t()) :: String.t()

Reduce name to characters legal in a PDF name object.

Falls back to a placeholder rather than emitting an empty name, which would produce a structurally invalid document.

unicode_text?(text)

@spec unicode_text?(String.t()) :: boolean()

Returns true when text contains anything outside 7-bit ASCII, and therefore cannot be written as a literal PDF string.