---
date: 2023-10-31T05:32:00Z
---
How to embed an image in groff and set it to fill the page of a document?
The short answer:
\" cover.ms \" [page-width] is the page width, e.g. 14.8c .nr HM 0 .vs 0 .po 0 .ll [page-width] .PSPIC "image.ps" [page-width + 0.1c] # Groff command # Replace [page-size] with the paper size, e.g. a5 groff -P-p[page-size] -ms cover.ms -Tps | ps2pdf - output.pdf
Below is a longer answer.
Recently a brave townie (not me) volunteered to embark on a quest to produce the pdf layout of the tildetown zine while wielding the Grand Goblet of Groff. In a trivial gesture of support, a zine cover image was handed off to this heroe, along with an unsolicited suggestion for how said image might be embedded into the rest of the document, because shady merchants selling a mission know to throw in a freebie to sweeten the deal.
Actually, preparing a suggestion took more time than illustrating the cover pages. The only things yours truly knew about roff before this were that a few townies used it in some incarnation ([g|n|o|s|t]roff), and others to format man pages. 1% of the "why" and 0% of the "how". This note might be 0.001% of the "how", but maybe it will save someone else a bit of hassle.
A macro is a group of requests or instructions for formatting a document.
According to a groff cheatsheet, there are two macros for handling images.
1. PSPIC
This allows embedding a Postscript image, but only supports html/xhtml/ps/dvi output. This should be fine for a web version, but for a pdf, it would be an extra step to convert the html or ps back to pdf. If the original image is in another format, e.g. jpg, then it would have to first be converted to ps or eps.
# Install ghostscript for the ps2pdf utility # Optionally install [image|graphics]magick to convert to ps from another format $ doas apk add ghostscript # Using imagemagick # For graphicsmagick, use: gm convert [...] convert cover.jpg cover.ps # Example calling PSPIC inside a ms macro file $ echo '.PSPIC "cover.ps"' > cover.ms $ groff -P-pa5 -ms cover.ms | ps2pdf - output.pdf
The `-P-pa5` flag tells the postprocessor to set the paper size to A5. The default size is US Letter.
2. PDFPIC
This allows adding pdf pages, which in turn can contain images, alongside ones typeset with troff. Oddly, `gropdf` appears to be broken in the Alpine package for armv7 — the executable exists but doesn't run. The `not found` error commonly happens when there is a device architecture mismatch, e.g. trying to run a x86_64 binary on an armv7 device. Subsequently found it worked on a x86_64 box.
# Install poppler-utils if not already present, # otherwise it may throw an error like the following: # sh: pdfinfo: not found # pdfpic.tmac:cover.ms:1: error: retrieval of 'cover.pdf' image dimensions # failed; skipping $ doas apk add poppler-utils $ echo '.PDFPIC "cover.pdf" 14.8c 21.0c' > cover.ms $ groff -ms cover.ms -Tpdf > output.pdf groff: error: couldn't exec gropdf: No such file or directory pdfpic.tmac:cover.ms:1: error: use of PDFPIC requires GNU troff's unsafe mode (-U option) $ whereis gropdf gropdf: /usr/bin/gropdf $ /usr/bin/gropdf -ash: /usr/bin/gropdf: not found $ ls -la /usr/bin/gropdf -rwxr-xr-x 1 root root 82245 Jul 29 18:59 /usr/bin/gropdf
Unsafe mode? From the GNU Troff manual:
Operate in unsafe mode, which enables the open, opena, pi, pso, and sy requests. These requests are disabled by default because they allow an untrusted input document to write to arbitrary file names and run arbitrary commands.
Enabling this is probably a terrible idea if the pdf is from an unknown source. Not sure why it was necessary to implement the feature in a way that allows running arbitrary commands. It could be a legacy from a more innocent era. The choice of which to use may depend on trusting that townies are good and smart beings who will not arbitrarily spring a malware payload inside a pdf submission.
How about generating graphics with the troff family of tools? There is a `pic` preprocessor, but writing procedural source without some form of live preview is a pain. Fortunately, Xfig is a X drawing application that could export to a variety of formats including eps, ps and pic/tpic. Theoretically, it should be possible to draw an image with Xfig, save it as pic and insert the instructions into a troff file.
# Install Xfig, and fig2dev for .png and .pdf export $ doas apk add xfig fig2dev
In terms of feature set, the application is closer to Dia than Inkscape, more geared towards flow charts and schematic diagramming. It comes with a small library of objects for areas like electronic schematics, desktop app wireframes and origami(!) diagrams. There is a compound object feature which, like Inkscape's object group/ungroup, allows objects to be moved and scaled as if they were one large object.
A few limitations: it only supports a small set of fonts, mostly old and non-free, e.g. Times New Roman and Helvetica, and getting it to recognise the corresponding font files is a guessing game unless imported straight from Windows/Mac systems. Object rotation is locked to certain angles, could not activate free rotation. There does not seem to be any option to set the paper size from within the user interface, though it is easy to change it by opening the save file in a text editor and replacing the default Letter size with another preconfigured size from the table in the manual.
The rough edges: tooling windows overflow vertically with no scrollbars when the zoom setting is set higher than 1.0, which causes any buttons at the bottom to be inaccessible. Text input fields in the windows tend to get stuck, requiring several clicks inside the field and pressing backspace 2-3 times to change numerical values. Objects are often shifted or out of alignment in the exported file from the on-screen display. Grouping objects then moving the compound object does not preserve the original order of visibility of the objects. To get around it, each object's depth could be set to a different value before grouping. The default value is 50. A lower number makes an object appear in the foreground, and a higher number puts it further in the background.
It started to slow down considerably when using transform-type tools (edit, move, scale, remove, etc.) after ~20 objects, as it tried to display the nodes of each object for selection. One of the files had 99 objects. For some reason it struggled for minutes with each tool selection, and the window manager was also unresponsive for long stretches. Suspecting an iowait bottleneck from a system running on sdcard media. It consistently pegged 1 core (of 4 cores) whenever it happened and unblocked itself long enough for me to bring up htop to check, though it used little RAM. Ended up testing settings in a different buffer file and editing the file in a text editor to apply the changes.
The other setback was tpic export did not work for me following the tip on the unofficial groff cheatsheet page to paste the source between the `.PS`/`.PE` block. Groff treated the source as literal text when run from one device regardless of whether the content was from pic or tpic format. Maybe the groff command was missing the preprocessor flag `-pic` at the time. On another, groff did not recognise the colour assignment in the tpic syntax. Attempting to embed the pic file, such as `.PIC -C -I 0 "cover.pic" 14.8c 21.0c`, caused the groff command to hang and the output file was 0 bytes in size.
While it was fun trying out a new application, it became almost unusable for a drawing with even slight complexity. Wrapped up a cover in Xfig, but it was back to Inkscape for the next idea.
Embedding the image was easy, but having it fill the page took more searching. This is partly due to 1) unfamiliarity with the pipeline, how the options were grouped, which options were groff-specific, and 2) some of the options either had no examples or did not work as anticipated based on brief, often one-line descriptions. Eventually found a combination of options between the manpage of groff's implementation of memorandum macros (mm), the Troff User's Manual and the GNU Troff Manual in the case of manuscript macros (ms).
In an example file:
.nr HM 0 .vs 0 .po 0 .ll 14.8c .PSPIC "cover.ps" 14.9c
The first line sets the header margin to 0. `HM` is a ms register, and a similar effect can be obtained in mm by resetting the top of the page, overriding the default header: `.TP` In both cases, request must be set on the first line of the file without any comments above it, or it will not work. The next line, `.vs 0`, sets the vertical baseline spacing to 0 and in conjunction with `.TP`, affects the visible spacing between the top edge of the page and the first line of content. `.po` or page offset controls the left margin (there is no right margin setting), and is also set to 0. `.ll` stands for line length and in this case, spans the entire length of the page, 14.8 cm (an A5 page is 148 mm x 210 mm). Supported units include centimeters (c) and inches (i) among others. Then `.PSPIC` or `.PDFPIC` can be called with the image file.
The `14.9c` is not a typo — something about the way ps and pdf files are rendered results in a <0.5 mm gap on the right edge of the page. This also happens when images are exported from Inkscape with the exact document size and re-imported. The ps `%%DocumentMedia` field is set to A5, and the evince pdf viewer likewise reports the size as A5. As a workaround, setting the width 1 mm wider in `.PSPIC` closed the gap.
There is also a vertical margin option , as in `.vm 0 0`, found in vol. 2 of the Unix System V Documenters Workbench manual, which initially sounded like the most obvious parameter to adjust, but it did not work to remove vertical margins, only added to a baseline setting.
groff cheatsheet — graphics and photos using GNU troff
Embedding pictures or images (groff mailing list)
Convert a pdf file to Letter size using groff
Document control settings (Groff manual)
Placement of PSPICs (groff mailing list)
Xfig PRINT and EXPORT settings
Setting top margin in groff to zero using mm macros