Callbacks
glu provides a callback system for page-level events. Callbacks are Lua functions that run at specific points during PDF generation — for example, drawing decorations or adding page numbers when a page is shipped out.
Registering a callback
Use frontend.add_callback() to register a named callback for an event:
local frontend = require("glu.frontend")
frontend.add_callback("pre_shipout", "page_frame", function(doc, page, pagenum)
-- draw a frame, add a page number, etc.
end)Each callback has a name (here "page_frame") that identifies it. Names must be unique per event — registering a callback with the same name replaces the previous one.
Events
| Event | When it fires | Arguments |
|---|---|---|
pre_shipout |
Before a page is written to the PDF | doc, page, pagenum |
pre_shipout arguments
| Argument | Type | Description |
|---|---|---|
doc |
Document | The current document (same as from frontend.new()) |
page |
Page | The page about to be shipped out |
pagenum |
number | The page number (1-based) |
The page object provides page.width and page.height as dimensions. Use page.width.pt to get the numeric value in points (for calculations or SVG generation).
Place content on the page with:
page:output_at(x, y, content)Callback ordering
By default, callbacks run in the order they were registered. The optional fourth argument to add_callback controls positioning:
-- Append (default)
frontend.add_callback("pre_shipout", "background", fn)
frontend.add_callback("pre_shipout", "background", fn, "back")
-- Prepend
frontend.add_callback("pre_shipout", "watermark", fn, "front")
-- Relative positioning
frontend.add_callback("pre_shipout", "border", fn, { after = "background" })
frontend.add_callback("pre_shipout", "header", fn, { before = "footer" })| Position | Description |
|---|---|
"back" (default) |
Append to the end of the callback list |
"front" |
Insert at the beginning |
{after = "name"} |
Insert after the named callback |
{before = "name"} |
Insert before the named callback |
If the referenced callback name does not exist, before/after falls back to appending.
Removing and listing callbacks
Remove a callback by name:
frontend.remove_callback("pre_shipout", "page_frame")List all registered callback names for an event (in execution order):
local names = frontend.list_callbacks("pre_shipout")
for _, name in ipairs(names) do
print(name)
endWhere to register callbacks
In Markdown mode, callbacks are typically registered in the companion Lua file. For example, if your document is report.md, put callback registrations in report.lua:
report.md ← your document
report.lua ← callback registrations (loaded automatically)In Lua script mode, register callbacks before creating pages.
Example: page frame with SVG
This example draws a decorative blue frame on every page:
local frontend = require("glu.frontend")
frontend.add_callback("pre_shipout", "page_frame", function(doc, page, pagenum)
local w = page.width.pt
local h = page.height.pt
local m = 36 -- 0.5in margin for the frame
local svg = string.format(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %g %g">' ..
'<rect x="%g" y="%g" width="%g" height="%g" ' ..
'fill="none" stroke="#336699" stroke-width="1.5" rx="4" ry="4"/>' ..
'</svg>',
w, h, m, m, w - 2*m, h - 2*m
)
local svgdoc = frontend.parse_svg_string(svg)
local svgnode = doc:create_svg_node(svgdoc, page.width, page.height)
page:output_at(0, page.height, svgnode)
end)The callback uses inline SVG to draw the frame. frontend.parse_svg_string() parses the SVG, and doc:create_svg_node() converts it to a node that can be placed on the page.
Example: page numbers
local frontend = require("glu.frontend")
frontend.add_callback("pre_shipout", "page_number", function(doc, page, pagenum)
local ff = doc:load_font_family("serif")
local txt = frontend.text({
font_family = ff,
font_size = "9pt",
color = "#666666",
})
txt:append(tostring(pagenum))
local vl = doc:format_paragraph(txt, "50pt", { alignment = "center" })
local x = (page.width - frontend.sp("50pt")) / 2
page:output_at(x, frontend.sp("1.5cm"), vl)
end)