At Fathom Data we have been doing a lot of automated documentation and automated reporting. Although many of these documents are rendered to HTML, there’s an increasing demand for PDF documents. We’ve had to raise out game in that department. The {pagedown}
package has become invaluable. This is a short note showing how we tweak the page size and margins for PDF documents.
Output Format
The {pagedown}
package comes with a selection of formats baked in. Each format is implemented as a function, for example:
html_paged()
html_letter()
andhtml_resume()
.
These functions are wrappers around a call to the generic function html_format()
, which sets up the template, theme and CSS styling. The format is chosen via the output
argument in the YAML header.
To make things as flexible as possible, we’ll create our own output format, fmtdoc()
. We’ll come back to the details of that in a moment. Let’s first take a look at what a document using fmtdoc()
would look like. Here’s a super simple document, document.Rmd
, with a title and a single line of text.
---
title: "A test document"
output:
fmtdoc:
extra_css: "page-parts.css"
knit: pagedown::chrome_print
---
This is the document.
Next we’ll implement fmtdoc()
. It has one hard-coded style file, style.scss
, and an optional argument, extra_css
, which can be used to specify additional styling.
library(pagedown)
fmtdoc <- function(extra_css = NULL, ...) {
html_paged(
css = c("style.scss", extra_css),
template = "template.html",
...
)
}
chrome_print("document.Rmd", format = "pdf")
That script also invokes chrome_print()
, which will render the document to HTML and then print as PDF. The implementation of fmtdoc()
references two files, template.html
and style.scss
, we’ll put these together next.
Template
The template file specifies how the Markdown document is transformed into HTML. The template below is a massively stripped-down version of the paged.html
template which comes with the {pagedown}
package.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width">
<title>$pagetitle$</title>
$for(header-includes)$
$header-includes$
$endfor$
$for(css)$
<link rel="stylesheet" href="$css$" type="text/css" />
$endfor$
</head>
<body>
<div class="main">
$body$
</div>
</body>
</html>
Styling
There are two style files, style.scss
and page-parts.css
, of which only the former is important for the page layout. The latter just highlights various components of the page, making it easier to see the layout.
I used SCSS for the first style file, style.scss
, to enable variables which would be visible in media queries. Two SCSS variables are defined, page-width
and page-height
, which are used to set the size of the HTML page (via the :root
element) and the PDF page (via the print
media query). The specified width and height are for a landscape A5 page.
$page-width: 210mm;
$page-height: 148mm;
:root {
--pagedjs-width: $page-width;
--pagedjs-height: $page-height;
--pagedjs-margin-top: 30px;
--pagedjs-margin-bottom: 60px;
--pagedjs-margin-left: 40px;
--pagedjs-margin-right: 100px;
}
@media print {
@page {
size: $page-width $page-height;
}
}
The optional style file, page-parts.css
, just sets the background colour for the body of the page and puts outlines around the margin components.
.pagedjs_area {
background-color: lightgrey;
}
.pagedjs_margin {
border: 1px solid red;
visibility: visible !important;
}
Result
And this is what the resulting document looks like.
Let’s check the dimensions of the page.
identify -verbose document.pdf | grep "Print size"
Print size: 8.26389x5.83333
The units of measure are inches (imperial units in my metric world!). But we can convert them easily to millimetres.
units -t '8.26389 inch' 'mm'
units -t '5.83333 inch' 'mm'
209.90281
148.16658
Close enough to the 210 mm by 148 mm requested!
Obviously for any real document you’d want to drop the styling in page-parts.css
and do whatever is necessary to make your document look attractive. However, using this approach you’ll be able to create a PDF document of whatever size you need and also freely configure the margins.