1#' Convert to a PDF/LaTeX document 2#' 3#' Formats for converting from R Markdown to a PDF or LaTeX document. 4#' 5#' See the \href{https://bookdown.org/yihui/rmarkdown/pdf-document.html}{online 6#' documentation} for additional details on using the \code{pdf_document} 7#' format. 8#' 9#' Creating PDF output from R Markdown requires that LaTeX be installed. 10#' 11#' R Markdown documents can have optional metadata that is used to generate a 12#' document header that includes the title, author, and date. For more details 13#' see the documentation on R Markdown \link[=rmd_metadata]{metadata}. 14#' 15#' R Markdown documents also support citations. You can find more information on 16#' the markdown syntax for citations in the 17#' \href{https://pandoc.org/MANUAL.html#citations}{Bibliographies 18#' and Citations} article in the online documentation. 19#' 20#' Many aspects of the LaTeX template used to create PDF documents can be 21#' customized using metadata. For example: 22#' 23#' \tabular{l}{ 24#' \code{---} \cr 25#' \code{title: "Crop Analysis Q3 2013"} \cr 26#' \code{fontsize: 11pt} \cr 27#' \code{geometry: margin=1in} \cr 28#' \code{---} 29#' } 30#' 31#' Available metadata variables include: 32#' 33#' \describe{ 34#' \item{\code{lang}}{Document language code (e.g. "es", "fr", "pt-BR")} 35#' \item{\code{fontsize}}{Font size (e.g. 10pt, 11pt, 12pt)} 36#' \item{\code{documentclass}}{LaTeX document class (e.g. article)} 37#' \item{\code{classoption}}{Option for \code{documentclass} (e.g. oneside); may be repeated} 38#' \item{\code{geometry}}{Options for geometry class (e.g. margin=1in); may be repeated} 39#' \item{\code{mainfont, sansfont, monofont, mathfont}}{Document fonts (works only with xelatex and lualatex, see the \code{latex_engine} option)} 40#' \item{\code{linkcolor, urlcolor, citecolor}}{Color for internal, external, and citation links (red, green, magenta, cyan, blue, black)} 41#' \item{\code{linestretch}}{Options for line spacing (e.g. 1, 1.5, 3)} 42#' } 43#' @inheritParams html_document 44#' @param fig_crop Whether to crop PDF figures with the command 45#' \command{pdfcrop}. This requires the tools \command{pdfcrop} and 46#' \command{ghostscript} to be installed. By default, \code{fig_crop = TRUE} 47#' if these two tools are available. 48#' @param dev Graphics device to use for figure output (defaults to pdf) 49#' @param highlight Syntax highlighting style. Supported styles include 50#' "default", "tango", "pygments", "kate", "monochrome", "espresso", 51#' "zenburn", and "haddock". Pass \code{NULL} to prevent syntax highlighting. 52#' @param keep_tex Keep the intermediate tex file used in the conversion to PDF 53#' @param latex_engine LaTeX engine for producing PDF output. Options are 54#' "pdflatex", "lualatex", "xelatex" and "tectonic". 55#' @param citation_package The LaTeX package to process citations, \code{natbib} 56#' or \code{biblatex}. Use \code{default} if neither package is to be used, 57#' which means citations will be processed via the command 58#' \command{pandoc-citeproc}. 59#' @param template Pandoc template to use for rendering. Pass "default" to use 60#' the rmarkdown package default template; pass \code{NULL} to use pandoc's 61#' built-in template; pass a path to use a custom template that you've 62#' created. See the documentation on 63#' \href{https://pandoc.org/MANUAL.html}{pandoc online documentation} for 64#' details on creating custom templates. 65#' @param output_extensions Pandoc extensions to be added or removed from the 66#' output format, e.g., \code{"-smart"} means the output format will be 67#' \code{latex-smart}. 68#' @param extra_dependencies A LaTeX dependency \code{latex_dependency()}, a 69#' list of LaTeX dependencies, a character vector of LaTeX package names (e.g. 70#' \code{c("framed", "hyperref")}), or a named list of LaTeX package options 71#' with the names being package names (e.g. \code{list(hyperef = 72#' c("unicode=true", "breaklinks=true"), lmodern = NULL)}). It can be used to 73#' add custom LaTeX packages to the .tex header. 74#' @return R Markdown output format to pass to \code{\link{render}} 75#' @examples 76#' \dontrun{ 77#' library(rmarkdown) 78#' 79#' # simple invocation 80#' render("input.Rmd", pdf_document()) 81#' 82#' # specify an option for latex engine 83#' render("input.Rmd", pdf_document(latex_engine = "lualatex")) 84#' 85#' # add a table of contents and pass an option to pandoc 86#' render("input.Rmd", pdf_document(toc = TRUE, "--listings")) 87#' } 88#' @export 89pdf_document <- function(toc = FALSE, 90 toc_depth = 2, 91 number_sections = FALSE, 92 fig_width = 6.5, 93 fig_height = 4.5, 94 fig_crop = 'auto', 95 fig_caption = TRUE, 96 dev = 'pdf', 97 df_print = "default", 98 highlight = "default", 99 template = "default", 100 keep_tex = FALSE, 101 keep_md = FALSE, 102 latex_engine = "pdflatex", 103 citation_package = c("default", "natbib", "biblatex"), 104 includes = NULL, 105 md_extensions = NULL, 106 output_extensions = NULL, 107 pandoc_args = NULL, 108 extra_dependencies = NULL) { 109 110 # base pandoc options for all PDF output 111 args <- c("--self-contained") 112 113 # table of contents 114 args <- c(args, pandoc_toc_args(toc, toc_depth)) 115 116 append_in_header <- function(text, file = as_tmpfile(text)) { 117 includes_to_pandoc_args(includes(in_header = file)) 118 } 119 120 # template path and assets 121 if (!is.null(template) && !identical(template, "default")) { 122 args <- c(args, "--template", pandoc_path_arg(template)) 123 } 124 125 # numbered sections 126 if (number_sections) 127 args <- c(args, "--number-sections") 128 129 # highlighting 130 if (!is.null(highlight)) 131 highlight <- match.arg(highlight, highlighters()) 132 args <- c(args, pandoc_highlight_args(highlight)) 133 134 # latex engine 135 latex_engine <- match.arg(latex_engine, c("pdflatex", "lualatex", "xelatex", "tectonic")) 136 args <- c(args, pandoc_latex_engine_args(latex_engine)) 137 138 # citation package 139 args <- c(args, citation_package_arg(citation_package)) 140 141 # content includes 142 args <- c(args, includes_to_pandoc_args(includes)) 143 144 # make sure the graphics package is always loaded 145 if (identical(template, "default")) args <- c(args, "--variable", "graphics") 146 147 # args args 148 args <- c(args, pandoc_args) 149 150 saved_files_dir <- NULL 151 152 # Use filter to set pdf geometry defaults (while making sure we don't override 153 # any geometry settings already specified by the user) 154 pdf_pre_processor <- function(metadata, input_file, runtime, knit_meta, files_dir, 155 output_dir) { 156 157 # make sure --include-in-header from command line will not completely 158 # override header-includes in metadata but give the latter lower precedence: 159 # https://github.com/rstudio/rmarkdown/issues/1359 160 args <- append_in_header(process_header_includes(metadata)) 161 162 # use a geometry filter when we are using the "default" template 163 if (identical(template, "default")) { 164 # set the margin to 1 inch if no geometry options or document class specified 165 if (default_geometry(names(metadata), pandoc_args)) 166 args <- c(args, "--variable", "geometry:margin=1in") 167 # support subtitle for Pandoc < 2.6 168 if (("subtitle" %in% names(metadata)) && !pandoc_available("2.6")) args <- c( 169 args, append_in_header(file = pkg_file("rmd/latex/subtitle.tex")) 170 ) 171 } 172 173 if (length(extra_dependencies) || has_latex_dependencies(knit_meta)) { 174 extra_dependencies <- latex_dependencies(extra_dependencies) 175 all_dependencies <- append(extra_dependencies, flatten_latex_dependencies(knit_meta)) 176 args <- c(args, append_in_header(latex_dependencies_as_string(all_dependencies))) 177 } 178 args 179 } 180 181 182 pre_processor <- function(metadata, input_file, runtime, knit_meta, 183 files_dir, output_dir) { 184 # save files dir (for generating intermediates) 185 saved_files_dir <<- files_dir 186 187 pdf_pre_processor(metadata, input_file, runtime, knit_meta, files_dir, 188 output_dir) 189 } 190 191 intermediates_generator <- function(...) { 192 general_intermediates_generator(saved_files_dir, ...) 193 } 194 195 # return format 196 output_format( 197 knitr = knitr_options_pdf(fig_width, fig_height, fig_crop, dev), 198 pandoc = pandoc_options( 199 to = paste(c("latex", output_extensions), collapse = ""), 200 from = from_rmarkdown(fig_caption, md_extensions), 201 args = args, 202 latex_engine = latex_engine, 203 keep_tex = keep_tex, 204 lua_filters = pkg_file_lua(c("pagebreak.lua", "latex-div.lua")) 205 ), 206 clean_supporting = !keep_tex, 207 keep_md = keep_md, 208 df_print = df_print, 209 pre_processor = pre_processor, 210 intermediates_generator = intermediates_generator 211 ) 212} 213 214general_intermediates_generator <- function( 215 saved_files_dir, original_input, intermediates_dir 216) { 217 218 # copy all intermediates (pandoc will need to bundle them in the PDF) 219 intermediates <- copy_render_intermediates(original_input, intermediates_dir, FALSE) 220 221 # we need figures from the supporting files dir to be available during 222 # render as well; if we have a files directory, copy its contents 223 if (!is.null(saved_files_dir) && dir_exists(saved_files_dir)) { 224 file.copy(saved_files_dir, intermediates_dir, recursive = TRUE) 225 intermediates <- c(intermediates, list.files( 226 path = file.path(intermediates_dir, basename(saved_files_dir)), 227 all.files = TRUE, recursive = TRUE, full.names = TRUE)) 228 } 229 230 intermediates 231} 232 233patch_tex_output <- function(file) { 234 x <- read_utf8(file) 235 if (length(i <- which(x == '\\begin{document}')) == 0) return() 236 if (length(i <- grep('^\\\\date\\{', head(x, i[1]))) == 0) return() 237 238 i <- i[1] 239 # add \author{} if missing: https://github.com/jgm/pandoc/pull/5961 240 if (length(grep('^\\\\author\\{', head(x, i))) == 0) { 241 x <- append(x, '\\author{}', i - 1) 242 i <- i + 1 243 } 244 # reduce the vertical spacing in \date{} if no author is given 245 if (any(head(x, i) == '\\author{}')) { 246 x[i] <- paste0('\\date{\\vspace{-2.5em}', sub('^\\\\date\\{', '', x[i])) 247 } 248 write_utf8(x, file) 249} 250 251# patch output from Pandoc < 2.8: https://github.com/jgm/pandoc/issues/5801 252fix_horiz_rule <- function(file) { 253 if (pandoc_available('2.8')) return() 254 x <- read_utf8(file) 255 i <- x == '\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}' 256 if (any(i)) { 257 x[i] <- '\\begin{center}\\rule{0.5\\linewidth}{0.5pt}\\end{center}' 258 write_utf8(x, file) 259 } 260} 261 262process_header_includes <- function(x) { 263 x <- unlist(x[["header-includes"]]) 264 gsub('(^|\n)\\s*```\\{=latex\\}\n(.+?\n)```\\s*(\n|$)', '\\1\\2\\3', x) 265} 266 267citation_package_arg <- function(value) { 268 value <- value[1] 269 if (value == "none") { 270 warning("citation_package = 'none' was deprecated; please use 'default' instead.") 271 value <- "default" 272 } 273 value <- match.arg(value, c("default", "natbib", "biblatex")) 274 if (value != "default") paste0("--", value) 275} 276 277default_geometry <- function(meta_names, pandoc_args = NULL) { 278 !any(c('geometry', 'documentclass') %in% meta_names) && 279 length(grep('^(--(variable|metadata)=)?documentclass:', pandoc_args)) == 0 280} 281 282#' @param ... Arguments passed to \code{pdf_document()}. 283#' @rdname pdf_document 284#' @export 285latex_document <- function(...) { 286 merge_lists(pdf_document(..., keep_tex = TRUE), list(pandoc = list(ext = ".tex"))) 287} 288 289#' @rdname pdf_document 290#' @export 291latex_fragment <- function(...) { 292 latex_document(..., template = pkg_file("rmd/fragment/default.tex")) 293} 294