| Type: | Package |
| Title: | Fast Multi-Page PDF Report Layout on the Graphics Device |
| Version: | 0.1.1 |
| Date: | 2026-07-21 |
| Maintainer: | Kyun-Seop Bae <k@acr.kr> |
| Description: | A lightweight, dependency-free engine to build multi-page PDF reports quickly on top of R's built-in graphics device ('pdf'/'cairo_pdf'). Content is placed by a measured flow layout: every text block reports its real width and height via 'strwidth'/'strheight', the vertical cursor advances by measured height, and pages break automatically. This eliminates the text-overlap of dead-reckoned coordinate reports (such as the 'nmw' NONMEM diagnostic reports) and replaces slow '.Rmd'/'knitr'/'LaTeX' pipelines for fixed report generation. Interactive AcroForm CRFs are out of scope and handled by the sibling 'pdfCRF' package. |
| Depends: | R (≥ 3.6.0) |
| Imports: | grDevices, graphics |
| Suggests: | tinytest, png, jpeg, knitr, rmarkdown |
| VignetteBuilder: | knitr |
| License: | GPL-3 |
| Encoding: | UTF-8 |
| Config/roxygen2/version: | 8.0.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-07-21 12:02:46 UTC; Kyun-SeopBae |
| Author: | Kyun-Seop Bae [aut, cre] |
| Repository: | CRAN |
| Date/Publication: | 2026-07-30 16:50:02 UTC |
An authorship block (prepared-by line + metadata)
Description
A compact block naming who prepared the document and when, plus optional affiliation and free-form lines. Purely visible text.
Usage
block_authorship(
author,
role = "Prepared by",
affiliation = NULL,
date = NULL,
extra = NULL,
size = 10
)
Arguments
author |
character, author name |
role |
character, e.g. "Prepared by" |
affiliation |
optional affiliation line |
date |
optional date string (character); no default is stamped |
extra |
optional character vector of extra lines |
size |
font size in points |
Value
A block object (a block_pre under the hood): a
list with components measure, draw, keep and
split that the flow engine understands. Pass it to
flow_run or flow_add to place it in the
document.
A model-development flow-diagram block
Description
Renders a tree of nodes (e.g. NONMEM model runs) as boxes connected parent-to-child. Each box is sized to its measured multi-line label; the tree is laid out tidily (children centred under parents) and scaled uniformly to fit the reserved band, so adding more models shrinks the diagram instead of overlapping it.
Usage
block_flow_diagram(
nodes,
height = 500,
size = 8,
box_pad = 4,
vgap = 34,
hgap = 14,
connect = TRUE,
box_col = "black",
line_col = "grey55"
)
Arguments
nodes |
a data.frame with columns |
height |
band height in points |
size |
maximum node font size in points (shrinks with the scale) |
box_pad |
padding inside boxes in points |
vgap, hgap |
vertical/horizontal gaps between nodes in points |
connect |
draw parent-child connectors |
box_col, line_col |
box border and connector colours |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
A block that embeds a raster image
Description
Places an image (a raster object, a numeric array/matrix, or a PNG/JPEG file path) into a band of the given height on the flowing page.
Usage
block_image(img, height, width = NULL, interpolate = TRUE)
Arguments
img |
a raster, array/matrix, or path to a PNG/JPEG file |
height |
band height in points |
width |
band width in points (default: full frame width) |
interpolate |
passed to |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
Keep a group of blocks together on one page (atomic)
Description
Keep a group of blocks together on one page (atomic)
Usage
block_keep(blocks, gap = 0)
Arguments
blocks |
a list of blocks |
gap |
inter-block gap inside the group |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place the whole group on one page; the constructor itself draws
nothing.
A wide-matrix block that groups columns to fit the page width
Description
Renders a matrix; if it is wider than the frame, the data columns are split
into groups that each fit (row labels repeated in every group), and the
groups are stacked vertically. This replaces hand-placed column loops such as
PrinTxt(row, i * 8, ...) that overflow the page for many columns.
Usage
block_matrix(
m,
size = 9,
family = "mono",
font = 1L,
leading = 1.3,
pad = 4,
gap = size * 0.8,
max_cols_per_group = NULL
)
Arguments
m |
a matrix (or data.frame) |
size |
font size in points |
family |
font family (monospace by default for aligned numbers) |
font |
face |
leading |
line-spacing factor |
pad |
horizontal cell padding in points |
gap |
vertical gap between column groups (points) |
max_cols_per_group |
optional cap on data columns per group |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
A word-wrapped paragraph block
Description
Wraps text to the frame width using measured widths, so it never
overflows horizontally, reports its true multi-line height, and splits across
pages line-by-line.
Usage
block_para(
text,
size = 10,
font = 1L,
family = "sans",
leading = 1.2,
align = c("left", "right", "center", "justify"),
indent = 0,
col = "black"
)
Arguments
text |
a character string (may contain explicit newlines) |
size |
font size in points |
font |
face: 1 plain, 2 bold, 3 italic, 4 bold-italic |
family |
font family ("sans"/"serif"/"mono" or a core-font name) |
leading |
line-spacing factor |
align |
"left", "right", "center", or "justify" (justify falls back to left in P0) |
indent |
left indent in points |
col |
text colour |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
A block that draws a base-R plot into a reserved region
Description
Evaluates a plotting expression (e.g. plot(...), hist(...),
qqnorm(...)) inside a band of the given height on the flowing page.
The plot is confined to the band and the text canvas is restored afterwards,
so plots sit inline with text and participate in pagination (a plot that does
not fit the remaining space moves to the next page). The expression is
captured unevaluated and run at draw time in the caller's environment.
Usage
block_plot(expr, height, width = NULL, mar = c(4, 4, 2, 1))
Arguments
expr |
a plotting expression (not evaluated until drawn) |
height |
band height in points |
width |
band width in points (default: full frame width) |
mar |
plot margins in lines, |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
A preformatted (monospace) block for capture.output() dumps
Description
Draws each element of lines as one physical line, and auto-shrinks the
font so the widest line fits the frame width (fixing the options(width)
wrap/overlap of dead-reckoned reports). Splits across pages line-by-line.
Usage
block_pre(
lines,
size = 9,
font = 1L,
family = "mono",
leading = 1.15,
col = "black"
)
Arguments
lines |
a character vector, one element per line |
size |
font size in points (upper bound; may shrink to fit width) |
font |
face |
family |
font family (defaults to monospace) |
leading |
line-spacing factor |
col |
text colour |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
A horizontal rule spanning the frame width
Description
A horizontal rule spanning the frame width
Usage
block_rule(color = "black", pad = 2, lwd = 1)
Arguments
color |
line colour |
pad |
vertical padding above/below the rule (points) |
lwd |
line width |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to draw the rule at the cursor; the constructor itself draws nothing.
A signature / approval block (visible lines + optional interactive fields)
Description
Draws one signing line per role with a caption beneath and, when
with_date, a dated line to the right. Each signing rectangle is
recorded on doc (in doc$sig) so sp_add_sig_fields
can place a clickable Acrobat signature field exactly over it after the PDF
is written.
Usage
block_signature(
roles = c("Performed by", "Reviewed by"),
with_date = TRUE,
size = 10,
caption_size = 8,
sig_height = 26,
sig_frac = 0.5,
date_frac = 0.22,
gap = 16,
field = TRUE
)
Arguments
roles |
character vector of signer roles (e.g. "Performed by") |
with_date |
add a dated line beside each signature |
size, caption_size |
text sizes in points |
sig_height |
height of the signing space in points |
sig_frac, date_frac |
signature/date line widths as fractions of the frame |
gap |
vertical gap between rows in points |
field |
record interactive-field rectangles on the document |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; when field = TRUE drawing also
records each signing rectangle in doc$sig for
sp_add_sig_fields.
A vertical spacer block
Description
A vertical spacer block
Usage
block_spacer(height)
Arguments
height |
height in points |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. When placed by flow_run or
flow_add it consumes height points of vertical
space without drawing anything.
A table block with measured column widths and automatic page splitting
Description
Renders a data.frame or matrix as a table: column widths are measured from
the content, numeric columns are right-aligned, the header repeats on every
page, and the body splits at row boundaries when it does not fit. If the
natural width exceeds the frame, the font is shrunk uniformly to fit (use
block_matrix to instead split a wide matrix into column groups).
Usage
block_table(
x,
size = 9,
family = "sans",
font = 1L,
header = TRUE,
leading = 1.3,
pad = 4,
rule = TRUE
)
Arguments
x |
a data.frame or matrix |
size |
font size in points (upper bound; may shrink to fit width) |
family |
font family |
font |
face |
header |
show the column-name header row |
leading |
line-spacing factor |
pad |
horizontal cell padding in points |
rule |
draw a rule under the header |
Value
A block object: a list with components measure,
draw, keep and split that the flow engine
understands. Pass it to flow_run or flow_add
to place it in the document; the constructor itself draws nothing.
Add a single block imperatively
Description
Add a single block imperatively
Usage
flow_add(doc, block, gap = 4)
Arguments
doc |
a document handle |
block |
a block, or NULL (no-op) |
gap |
inter-block gap in points |
Value
The document handle doc, invisibly (an environment, updated
in place). Called for its side effect of drawing block into the
PDF.
Run a sequence of blocks through the flow engine
Description
Measures each block, draws it if it fits, otherwise starts a new page
(splitting splittable blocks across the break). NULL entries are
dropped, so conditional blocks (if (cond) block_*()) are fine.
Usage
flow_run(doc, blocks, header = NULL, footer = NULL, gap = 4)
Arguments
doc |
a document handle |
blocks |
a list of blocks |
header, footer |
running header/footer block(s) for every page |
gap |
inter-block vertical gap in points |
Value
The document handle doc, invisibly. The handle is an
environment updated in place (pages are added and the cursor advances);
the function is called mainly for its side effect of drawing the blocks
into the PDF.
Set the content frame (and reset the cursor to its top)
Description
Set the content frame (and reset the cursor to its top)
Usage
frame_set(doc, top, bottom, left, right)
Arguments
doc |
a document handle |
top, bottom, left, right |
frame edges in points |
Value
The document handle doc, invisibly (an environment; the
frame and the cursor are updated in place). Called for this side effect.
Vertical space remaining in the current frame (points)
Description
Vertical space remaining in the current frame (points)
Usage
remaining(doc)
Arguments
doc |
a document handle |
Value
A single numeric value: the vertical space in points still available between the cursor and the bottom of the content frame.
Set the running header / footer
Description
Set the running header / footer
Usage
running_header(doc, blocks)
running_footer(doc, blocks)
Arguments
doc |
a document handle |
blocks |
a block or list of blocks |
Value
The document handle doc, invisibly (the running blocks are
stored on the handle in place). Called for its side effect: the header
(top margin) or footer (bottom margin) is re-drawn on every subsequent
page.
Add interactive Acrobat signature fields to a finished PDF
Description
Inserts empty AcroForm digital-signature (/Sig) fields into a base-R
pdf() document (such as one produced by simPDF) using a pure base-R
incremental update – no external tools or packages. The result can be signed
with one click in the free Adobe Acrobat Reader. Generalised from
NonCompart::addSigFieldNCA to accept fields on any page, e.g. the
rectangles recorded by block_signature in doc$sig.
Usage
sp_add_sig_fields(pdf, fields, out = pdf)
Arguments
pdf |
path to the input PDF |
fields |
a list of fields, each |
out |
output path (default: overwrite |
Value
The output file path out, invisibly (a character string).
Called for its side effect of writing the modified PDF, with the
signature fields appended as an incremental update.
Close the document (flush the PDF)
Description
Close the document (flush the PDF)
Usage
sp_close(doc)
Arguments
doc |
a document handle |
Value
No return value (invisible(NULL)); called for its side
effect of closing the graphics device, which writes and finalises the
PDF file.
Draw a full-page multi-panel figure (outside the flow engine)
Description
For per-subject / per-parameter diagnostic pages that are a whole page of
base-R graphics (a par(mfrow) grid), rather than a block within the
text flow. Starts a fresh page, sets mfrow/oma/mar, runs
the plotting expression, and counts one page. The expression should draw
exactly prod(mfrow) panels (pad with blank plot.new() if fewer)
so each call maps to one page.
Usage
sp_figure_page(
doc,
expr,
mfrow = c(1, 1),
oma = c(0, 0, 2, 0),
mar = c(4, 4, 2, 1)
)
Arguments
doc |
a document handle |
expr |
base-R plotting expression (not evaluated until drawn) |
mfrow |
panel grid, e.g. |
oma, mar |
outer/inner margins in lines |
Value
The document handle doc, invisibly (the page counter is
advanced in place). Called for its side effect of drawing one full page
of panels.
Line height (vertical advance) in points
Description
Line height (vertical advance) in points
Usage
sp_height(doc, size = doc$size, lines = 1, leading = 1.2)
Arguments
doc |
a simPDF document handle |
size |
font size in points |
lines |
number of lines |
leading |
line-spacing factor (line pitch = size * leading) |
Value
A single numeric value: the vertical space in points that
lines lines occupy at the given size and leading
(lines * size * leading).
Open a new simPDF document
Description
Opens a graphics-device PDF and returns a mutable document handle. Text is
laid out in PDF points with the origin at the bottom-left of the page. A
default content frame is set inside margin on all sides.
Usage
sp_new(
file,
paper = "A4",
margin = 25,
family = "Helvetica",
size = 10,
pointsize = 12,
cairo = FALSE,
onefile = TRUE
)
Arguments
file |
output PDF path |
paper |
"A4", "letter", or "A3" |
margin |
page margin in points |
family |
default font family |
size |
default font size in points |
pointsize |
device pointsize (cex base); leave at default |
cairo |
use |
onefile |
single multi-page file (TRUE) vs one file per page |
Value
A document handle: an environment holding the open graphics
device, page geometry, content frame, cursor position and running
header/footer state. It is mutable and is updated in place by the other
simPDF functions; pass it to them and finish with sp_close.
Return overlapping text bounding-box pairs recorded while tracing
Description
Return overlapping text bounding-box pairs recorded while tracing
Usage
sp_overlaps(doc, eps = 0.1)
Arguments
doc |
a document handle |
eps |
overlap tolerance in points |
Value
A data.frame with one row per overlapping pair of recorded
text bounding boxes and columns i, j (indices of the two
boxes in the trace) and page (the page they overlap on). It has
zero rows when nothing overlaps.
Start a new page
Description
Emits a new PDF page, resets the cursor to the frame top, and re-stamps the running header/footer.
Usage
sp_page(doc, redraw_running = TRUE)
Arguments
doc |
a document handle |
redraw_running |
redraw running header/footer on the new page |
Value
The document handle doc, invisibly (the page counter and
cursor are updated in place). Called for its side effect of emitting a
new PDF page.
Turn bounding-box tracing on for no-overlap checks
Description
Turn bounding-box tracing on for no-overlap checks
Usage
sp_trace(doc, on = TRUE)
Arguments
doc |
a document handle |
on |
logical |
Value
The document handle doc, invisibly (the tracing state is
toggled in place). Called for its side effect; the boxes recorded while
tracing are inspected with sp_overlaps.
Measure text width in points
Description
Returns the rendered width of text in PDF points, using the open
device's font metrics. Measured in inches and scaled by 72, so it does not
require an active plot page and never has a side effect on the document.
AFM-exact for the 14 core PDF fonts (identical to what the viewer draws).
Usage
sp_width(doc, text, size = doc$size, font = 1L, family = doc$family)
Arguments
doc |
a simPDF document handle from |
text |
character vector to measure |
size |
font size in points |
font |
integer face: 1 plain, 2 bold, 3 italic, 4 bold-italic |
family |
font family ("sans"/"serif"/"mono" or a core-font name) |
Value
A numeric vector of the same length as text: the rendered
width of each element in PDF points (1/72 inch).