| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 1 | #' Convert a LaTeX table to an image and place it in a rmarkdown document | 
|  | 2 | #' | 
|  | 3 | #' @description This is a LaTeX-only function. This function will render the | 
|  | 4 | #' raw LaTeX code (could be codes generated by other table packages like | 
|  | 5 | #' `xtable`) to generate a table, convert it to an image and put it back to a | 
|  | 6 | #' rmarkdown environment. It is a "better than nothing" solution to print high | 
|  | 7 | #' quality tables in rmarkdown Word document. By using this, you need to take | 
| Hao Zhu | 245931c | 2017-09-01 22:43:56 -0400 | [diff] [blame] | 8 | #' the responsibility of explaining to your collaborators why they can't make | 
| Hao Zhu | a9c43dc | 2017-09-04 23:00:39 -0400 | [diff] [blame] | 9 | #' edits to the tables in Word. | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 10 | #' | 
|  | 11 | #' Also, if a filename is provided, user has the option to "save" the table to | 
|  | 12 | #' an image file like `ggplot2::ggsave()`. | 
|  | 13 | #' | 
| Hao Zhu | 246b95c | 2017-09-14 14:29:48 -0400 | [diff] [blame] | 14 | #' Note that, if you are using this function on a Windows computer, you need | 
|  | 15 | #' to install Ghostscript before you can use this feature. It is essential for | 
|  | 16 | #' magick to read PDFs on Windows. Website for Ghostscript: https://ghostscript.com/ | 
|  | 17 | #' | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 18 | #' The idea of this function was coming from [this StackOverflow question](https://stackoverflow.com/questions/44711313/save-rmarkdowns-report-tables-and-figures-to-file). | 
|  | 19 | #' The approach was learned and adopted from the [texpreview](https://github.com/metrumresearchgroup/texPreview) | 
|  | 20 | #' package, which allows you to preview the results of TeX code in the Viewer panel. | 
|  | 21 | #' | 
|  | 22 | #' @param kable_input Raw LaTeX code to generate a table. It doesn't have to | 
|  | 23 | #' came from `kable` or `kableExtra`. | 
|  | 24 | #' @param filename Character String. If specified, the image will be saved under | 
|  | 25 | #' the specified (path &) name. You don't need to put file format like ".png" | 
|  | 26 | #' here. | 
|  | 27 | #' @param file_format Character String to specify image format, such as `png`, | 
|  | 28 | #' `jpeg`, `gif`, `tiff`, etc. Default is `png`. | 
|  | 29 | #' @param latex_header_includes A character vector of extra LaTeX header stuff. | 
|  | 30 | #' Each element is a row. You can have things like | 
|  | 31 | #' `c("\\usepackage{threeparttable}", "\\usepackage{icons}")` | 
|  | 32 | #' @param keep_pdf A T/F option to control if the mid-way standalone pdf should | 
|  | 33 | #' be kept. Default is `FALSE`. | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 34 | #' @param density Resolution to read the PDF file. Default value is 300, which | 
|  | 35 | #' should be sufficient in most cases. | 
| Salzer | 27eb90b | 2018-02-11 16:14:04 -0500 | [diff] [blame] | 36 | #' @param keep_tex A T/F option to control if the latex file that is initially created | 
|  | 37 | #' should be kept. Default is `FALSE`. | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 38 | #' | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 39 | #' @export | 
|  | 40 | kable_as_image <- function(kable_input, filename = NULL, | 
|  | 41 | file_format = "png", | 
|  | 42 | latex_header_includes = NULL, | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 43 | keep_pdf = FALSE, | 
| Salzer | 27eb90b | 2018-02-11 16:14:04 -0500 | [diff] [blame] | 44 | density = 300, | 
|  | 45 | keep_tex = FALSE) { | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 46 | if (!requireNamespace("magick", quietly = TRUE)) { | 
|  | 47 | stop('kable_as_image requires the magick package, which is not available ', | 
|  | 48 | 'on all platforms. Please get it installed ', | 
|  | 49 | 'via install.packages("magick"). If you are running on Windows, you ', | 
|  | 50 | 'also need to install Ghostscript. Please download it here:', | 
|  | 51 | 'https://ghostscript.com/') | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 52 | } else { | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 53 | temp_tex <- c( | 
|  | 54 | "\\documentclass[border=1mm, preview]{standalone}", | 
|  | 55 | "\\usepackage[active,tightpage]{preview}", | 
|  | 56 | "\\usepackage{varwidth}", | 
|  | 57 | "\\usepackage{amssymb, amsmath}", | 
|  | 58 | "\\usepackage{ifxetex,ifluatex}", | 
|  | 59 | "\\usepackage{fixltx2e}", | 
|  | 60 | "\\usepackage{polyglossia}", | 
|  | 61 | "\\setmainlanguage{$mainlang$}", | 
|  | 62 | latex_pkg_list(), | 
|  | 63 | "\\usepackage{graphicx}", | 
|  | 64 | "\\usepackage{mathspec}", | 
|  | 65 | "\\usepackage{xltxtra,xunicode}", | 
|  | 66 | latex_header_includes, | 
|  | 67 | "\\begin{document}", | 
| Hao Zhu | 3fc0e88 | 2018-04-03 16:06:41 -0400 | [diff] [blame] | 68 | solve_enc(kable_input), | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 69 | "\\end{document}" | 
|  | 70 | ) | 
|  | 71 | temp_tex <- paste(temp_tex, collapse = "\n") | 
|  | 72 | temp_file <- paste0("table_", format(Sys.time(), "%Y-%m-%d_%H%M%S")) | 
| Hao Zhu | b35f188 | 2017-10-10 16:34:16 -0400 | [diff] [blame] | 73 | writeLines(temp_tex, paste0(temp_file, ".tex")) | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 74 | system(paste0("xelatex -interaction=batchmode ", temp_file, ".tex")) | 
|  | 75 | temp_file_delete <- paste0(temp_file, c(".tex", ".aux", ".log")) | 
| Salzer | 27eb90b | 2018-02-11 16:14:04 -0500 | [diff] [blame] | 76 | if(!keep_tex) { | 
|  | 77 | unlink(temp_file_delete) | 
|  | 78 | } | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 79 |  | 
| Hao Zhu | 4840bc9 | 2017-09-15 15:55:05 -0400 | [diff] [blame] | 80 | table_img_pdf <- try(magick::image_read(paste0(temp_file, ".pdf"), | 
|  | 81 | density = density), | 
|  | 82 | silent = T) | 
|  | 83 | if (class(table_img_pdf) == "try-error") { | 
|  | 84 | stop("Ghostscript is required to read PDF on windows. ", | 
|  | 85 | "Please download it here: https://ghostscript.com/") | 
|  | 86 | } | 
|  | 87 | if (!keep_pdf) { | 
|  | 88 | unlink(paste0(temp_file, ".pdf")) | 
|  | 89 | } | 
|  | 90 | table_img <- magick::image_convert(table_img_pdf, file_format) | 
|  | 91 | if (!is.null(filename)) { | 
|  | 92 | temp_img <- paste0(filename, ".", file_format) | 
|  | 93 | } else { | 
|  | 94 | temp_img <- tempfile(fileext = paste0(".", file_format)) | 
|  | 95 | } | 
|  | 96 | magick::image_write(table_img, temp_img) | 
|  | 97 |  | 
|  | 98 | include_graphics(temp_img) | 
|  | 99 | } | 
| Hao Zhu | 2a64dc6 | 2017-08-28 10:57:57 -0400 | [diff] [blame] | 100 | } |