Skip to content

The command line interface#

The command line interface (cli) makes it possible to create documents without a Go installation. It is built on the risor language, a small and simple language, yet powerful enough to handle all necessary tasks.

Installation#

When you have a Go installation, just use go install github.com/boxesandglue/cli/bag@latest to get the binary bag.

You can also download the latest binaries at https://github.com/boxesandglue/cli/releases/latest. The ZIP files contain only a single binary, enough for using boxes and glue.

Sample document#

Start with bag myfile.rsr, where the file myfile.rsr looks like this:

now := time.now()

func setup_fonts(f) {
    ff := f.new_fontfamily("text")

    fs := frontend.new_fontsource({
        location: filepath.join("fonts","CrimsonPro-Regular.ttf"),
        features: ["kern","liga"],
        })

    ff.add_member({source: fs, weight: 400, style: "normal"})
    return ff
}

str := `The quick brown fox jumps
over the lazy dog with a very long line that should be wrapped
at some point. This is a test to see how the text is formatted
when it is too long to fit on one line. The quick brown fox jumps
over the lazy dog with a very long line that should be wrapped`

str = strings.join(strings.fields(str)," ")

f := frontend.new('out.pdf')
backend_doc := f.doc
backend_doc.language = frontend.get_language("en")

backend_doc.title = "A test document"

ff := setup_fonts(f)

p := f.doc.new_page()
para := frontend.new_text()
para.items = [str]
vlist := f.format_paragraph({
    text: para,
    width: bag.sp("225pt"),
    leading: bag.sp("14pt"),
    font_size: bag.sp("12pt"),
    family: ff,
})
p.output_at(bag.sp("1cm"), bag.sp("10cm"), vlist)
p.shipout()

f.doc.finish()

printf("finished in %.2fms\n",time.since(now) * 1000)

Attachments#

a:= f.doc.attachments.append({
    filename: "img/ocean.pdf",
    mimetype: "application/pdf",
    description: "Test attachment",
})

Viewer preferences#

f.doc.viewer_preferences = {NumCopies: "2", PrintScaling: "/None"}

Image inclusion#

imgfile := f.doc.load_imagefile("img/ocean.pdf")
imgNode := f.doc.create_image_node_from_imagefile(imgfile, 1, "/MediaBox")
imgNode.width = bag.sp("100pt")
imgNode.height = bag.sp("100pt")
vl := node.vpack(imgNode)
p.output_at(bag.sp("1cm"), bag.sp("290mm"), vl)

Set the PDF format:#

f.doc.format = "PDF/A-3b"

Where format is one of "", "PDF/A-3b", "PDF/X-3", "PDF/X-4" or "PDF/UA".

Set bleed / show cropmarks#

f.doc.bleed = bag.sp("3mm")
f.doc.show_cutmarks = true

Page height and width#

// the default:
f.doc.default_page_width = bag.sp("210mm")
f.doc.default_page_height = bag.sp("297mm")

Set creation date#

f.doc.creation_date = time.parse(time.RFC3339, "2023-08-01T12:00:00-04:00")

Debugging output#

f.doc.dump_output = true
...
f.doc.finish()
f.doc.output_xml_dump("out.xml")

The XML structure in out.xml represents the document.

Reference#

The backend document#

Get with

f := frontend.new('out.pdf')
doc := f.doc
Name R/W Parameters Description
attachments r - A list with attachments
author w string Set the author of the document
bleed w scaled point The amount of extra space on each side of the page
compresslevel w int (0-9) The zlib compression level.
create_image_node_from_imagefile() ? Turns an image object into a node
creation_date w time The creation date of the document
creator w string The document creator software
default_page_height w scaled point The default page height
default_page_width w scaled point The default page width
dump_output w bool Collect info for later XML output.
filename r - The file name of the PDF
finish() - Write all objects to the PDF file
format w string One of "", "PDF/A-3b", "PDF/X-3", "PDF/X-4", "PDF/UA"
keywords w string Comma separated list
language w string or language object Set the document's default language for hyphenation
load_imagefile() ? Load an image object (PNG, PDF, JPEG)
new_page() ? Create a new page
output_xml_dump() ? Creates an XML dump from the document (might be large!)
show_cutmarks w bool Show cropmarks
show_hyperlinks w bool Toggle hyperlink borders
subject w string The document's subject
suppressinfo w bool Set to true if you need a fixed document id and date
title w string The document's title
viewer_preferences w Map A key value-map from section 8.1 of the PDF 1.7 spec

Page#

Name R/W Parameters Description
height r/w scaled point Set the height of the page
width r/w scaled point Set the width of the page
output_at() ? Place object on page
shipout() scaled point, scaled point and vlist Place page in PDF

Nodes#

There are several types of nodes: node.disc, node.glue, node.glyph, node.hlist, node.image, node.kern, node.lang, node.penalty, node.rule, node.startstop and node.vlist.

You can create a new node with node.new(). The expected argument is a string, one of disc, glue, glyph, hlist, image, kern, lang, penalty, rule, startstop or vlist.

Package functions#

Name Parameters Description
node.new() string Create (and return ) a new node.
node.insert_after() node (head), node (cur), node (new) Insert the new node after cur in a list starting with head. The head is returned.
node.insert_before() node (head), node (cur), node (new) Insert the new node before cur in a list starting with head. The (perhaps new) head is returned.
node.copy_list() node (head) Create a deep copy of a list starting at head.

Disc node#

Field R/W Parameters Description
pre w node The node before the disc
post w node The node after the disc
replace w node The replacement
penalty w int The penalty for breaking at this point

Glue node#

Field R/W Parameters Description
subtype w string The subtype of the glue
width w scaled point The natural width of the glue
stretch w scaled point The stretchability of the glue
shrink w scaled point The shrinkability of the glue
stretchorder w int The order of infinity of stretching
shrinkorder w int The order of infinity of shrinking

Glyph node#

Field R/W Parameters Description
font w font object The font of the glyph
codepoint w int The codepoint of the glyph
components w string The components of the glyph
width w scaled point The width of the glyph
height w scaled point The height of the glyph
depth w scaled point The depth of the glyph
yoffset w scaled point The vertical offset of the glyph
hyphenate w bool Set the hyphenation flag for the glyph

Hlist node#

Field R/W Parameters Description
width w scaled point The width of the hlist
height w scaled point The height of the hlist
depth w scaled point The depth of the hlist
badness w int The badness of the hlist
glueset w float The ratio of the glue. Positive means stretching, negative shrinking.
gluesign w int 0 = normal, 1 = stretching, 2 = shrinking
glueorder w int The level of infinity
shift w scaled point The displacement perpendicular to the progressing direction. Not used.
valign w int The vertical alignment of the hlist
list w node The list itself

Image node#

Field R/W Parameters Description
width w scaled point Set the resulting width of the image
height w scaled point Set the resulting height of the image
image w image object The image object
page w int The page number of the image
used w bool Set to true if the image is written to the page

Kern node#

Field R/W Parameters Description
kern w scaled point The width of the kern

Lang node#

Field R/W Parameters Description
lang w Lang The language of the node

Penalty node#

Field R/W Parameters Description
penalty w int Set the penalty when breaking at this point
width w scaled point Set the width of the penalty

Rule node#

Field R/W Parameters Description
width w scaled point The width of the rule
height w scaled point The height of the rule
depth w scaled point The depth of the rule
pre w string The pdf instructions before the rule
post w string The pdf instructions after the rule
hide w bool Set to true if the rule is hidden

StartStop node#

Field R/W Parameters Description
action w ActionType The action type
startnode w StartStop The start node
position w PDFDataOutput The position of the node
shipout_callback w StartStopFunc The shipout callback
value w any The value of the node

Vlist node#

Field R/W Parameters Description
width w scaled point The width of the vlist
height w scaled point The height of the vlist
depth w scaled point The depth of the vlist
glueset w float The ratio of the glue. Positive means stretching, negative shrinking.
gluesign w int 0 = normal, 1 = stretching, 2 = shrinking
shift_x w scaled point The displacement perpendicular to the progressing direction.
list w node The list itself

Logging#

The logging is based on Go' standard library slog. It allows several log levels, a main message and a set of key/value pairs, where each key is a string. You have to provide an even number of arguments for the key/value pairs.

The commands for logging are bag.debug(), bag.info(), bag.warn() and bag.error(). Each of these follow the same schema:

bag.info("something happens", "key1", value1, "key2", value2, ...)

for example:

filename := "somefile.png"
bag.info("File loaded", "filename", filename)