blob: 2f91fd40b081a47feedc6d23db074b2571517ec2 [file] [log] [blame]
Hao Zhu73cf3732018-05-11 17:50:05 -04001#' Save kable to files
2#'
3#' @param x A piece of HTML code for tables, usually generated by kable and
4#' kableExtra
Hao Zhu7f8b6842018-10-23 17:41:13 -04005#' @param file save to files. If the input table is in HTML and the output file
6#' ends with `.png`, `.pdf` and `.jpeg`, `webshot` will be used to do the
Hao Zhu7039ecf2019-01-06 17:51:21 -05007#' conversion.
Hao Zhu73cf3732018-05-11 17:50:05 -04008#' @param bs_theme Which Bootstrap theme to use
9#' @param self_contained Will the files be self-contained?
Hao Zhu7039ecf2019-01-06 17:51:21 -050010#' @param extra_dependencies Additional HTML dependencies. For example,
11#' `list(`
12#' @param ... Additional variables being passed to `webshot::webshot`. This
13#' is for HTML only.
14#' @param latex_header_includes A character vector of extra LaTeX header stuff.
15#' Each element is a row. You can have things like
16#' `c("\\\\usepackage{threeparttable}", "\\\\usepackage{icons}")` You could
17#' probably add your language package here if you use non-English text in your
18#' table, such as `\\\\usepackage[magyar]{babel}`.
19#' @param keep_tex A T/F option to control if the latex file that is initially created
20#' should be kept. Default is `FALSE`.
Jiaxiang Lie4b24f22019-04-05 13:38:11 +080021#' @examples
22#' \dontrun{
23#' library(kableExtra)
Hao Zhu73cf3732018-05-11 17:50:05 -040024#'
Jiaxiang Lie4b24f22019-04-05 13:38:11 +080025#' kable(mtcars[1:5, ], "html") %>%
26#' kable_styling("striped") %>%
27#' row_spec(1, color = "red") %>%
28#' save_kable("inst/test.pdf")
29#' }
Hao Zhu73cf3732018-05-11 17:50:05 -040030#' @export
31save_kable <- function(x, file,
Hao Zhu7039ecf2019-01-06 17:51:21 -050032 bs_theme = "simplex", self_contained = TRUE,
33 extra_dependencies = NULL, ...,
34 latex_header_includes = NULL, keep_tex = FALSE) {
Hao Zhud8516932019-01-06 18:56:47 -050035 if (!is.null(attr(x, "format")) && attr(x, "format") == "latex") {
Hao Zhu7039ecf2019-01-06 17:51:21 -050036 return(save_kable_latex(x, file, latex_header_includes, keep_tex))
Hao Zhu7f8b6842018-10-23 17:41:13 -040037 }
Hao Zhu7039ecf2019-01-06 17:51:21 -050038 return(save_kable_html(x, file, bs_theme, self_contained,
39 extra_dependencies, ...))
Hao Zhu7f8b6842018-10-23 17:41:13 -040040}
41
Hao Zhu7039ecf2019-01-06 17:51:21 -050042save_kable_html <- function(x, file, bs_theme, self_contained,
43 extra_dependencies, ...) {
44 dependencies <- list(
Hao Zhu73cf3732018-05-11 17:50:05 -040045 rmarkdown::html_dependency_jquery(),
46 rmarkdown::html_dependency_bootstrap(theme = bs_theme),
47 html_dependency_kePrint()
48 )
Hao Zhu7039ecf2019-01-06 17:51:21 -050049 if (!is.null(extra_dependencies)) {
50 dependencies <- append(dependencies, extra_dependencies)
51 }
52
Hao Zhu46a42a12019-01-22 00:11:11 -050053 html_header <- htmltools::tags$head(dependencies)
Hao Zhu73cf3732018-05-11 17:50:05 -040054 html_table <- htmltools::HTML(as.character(x))
55 html_result <- htmltools::tagList(html_header, html_table)
Hao Zhu7f8b6842018-10-23 17:41:13 -040056
ghaarsma8e786ad2019-02-16 21:28:01 -060057
58 # Check if we are generating an image and use webshot to do that
Hao Zhu7f8b6842018-10-23 17:41:13 -040059 if (tools::file_ext(file) %in% c("png", "jpg", "jpeg", "pdf")) {
ghaarsma8e786ad2019-02-16 21:28:01 -060060 file_temp_html <- tempfile(pattern = tools::file_path_sans_ext(file), tmpdir = '.', fileext = ".html")
61
62 file.create(file_temp_html)
63 file_temp_html <- normalizePath(file_temp_html)
64 file.create(file)
65 file <- normalizePath(file)
66
67 # Generate a random temp lib directory. The sub is to remove any back or forward slash at the beginning of the temp_dir
68 temp_dir <- sub(pattern = '^[\\\\/]{1,2}', replacement = '', tempfile(pattern = 'lib', tmpdir = '' , fileext = ''))
69 htmltools::save_html(html_result, file = file_temp_html, libdir = temp_dir)
70
71 result <- webshot::webshot(file_temp_html, file, ...)
72 if (is.null(result)) {
73 # A webshot could not be created. Delete newly created files and issue msg
74 file.remove(file)
75 file.remove(file_temp_html)
76 message('save_kable could not create image with webshot package. Please check for any webshot messages')
Hao Zhuf1873a42019-01-07 15:57:01 -050077 } else {
ghaarsma8e786ad2019-02-16 21:28:01 -060078 if (tools::file_ext(file) == "pdf") {
79 message("Note that HTML color may not be displayed on PDF properly.")
80 }
81 # Remove temp html file and temp lib directory
82 file.remove(file_temp_html)
83 unlink(file.path(dirname(file_temp_html), temp_dir), recursive = TRUE)
84
85 if (requireNamespace("magick", quietly = TRUE)) {
86 img_rework <- magick::image_read(file)
87 img_rework <- magick::image_trim(img_rework)
88 img_info <- magick::image_info(img_rework)
89 magick::image_write(img_rework, file)
90 attr(file, "info") <- img_info
91 } else {
92 message("save_kable will have the best result with magick installed. ")
93 }
Hao Zhuf1873a42019-01-07 15:57:01 -050094 }
ghaarsma8e786ad2019-02-16 21:28:01 -060095
Hao Zhu7f8b6842018-10-23 17:41:13 -040096 } else {
Hao Zhuf1873a42019-01-07 15:57:01 -050097 file.create(file)
98 file <- normalizePath(file)
ghaarsma8e786ad2019-02-16 21:28:01 -060099
Hao Zhu7f8b6842018-10-23 17:41:13 -0400100 if (self_contained) {
ghaarsma8e786ad2019-02-16 21:28:01 -0600101 # Generate a random temp lib directory. The sub is to remove any back or forward slash at the beginning of the temp_dir
102 temp_dir <- sub(pattern = '^[\\\\/]{1,2}', replacement = '', tempfile(pattern = 'lib', tmpdir = '' , fileext = ''))
103 htmltools::save_html(html_result, file = file, libdir = temp_dir)
104 #remove_html_doc(file)
Hao Zhu7f8b6842018-10-23 17:41:13 -0400105 rmarkdown::pandoc_self_contained_html(file, file)
ghaarsma8e786ad2019-02-16 21:28:01 -0600106 unlink(file.path(dirname(file), temp_dir), recursive = TRUE)
107 } else {
108 # Simply use the htmltools::save_html to write out the files. Dependencies go to the standard lib folder
109 htmltools::save_html(html_result, file = file)
Hao Zhu7f8b6842018-10-23 17:41:13 -0400110 }
Hao Zhu73cf3732018-05-11 17:50:05 -0400111 }
Hao Zhud8516932019-01-06 18:56:47 -0500112
Hao Zhuf1873a42019-01-07 15:57:01 -0500113 return(invisible(file))
Hao Zhu73cf3732018-05-11 17:50:05 -0400114}
Hao Zhu7f8b6842018-10-23 17:41:13 -0400115
Hao Zhu46a42a12019-01-22 00:11:11 -0500116remove_html_doc <- function(x){
117 out <- paste(readLines(x)[-1], collapse = "\n")
118 writeLines(out, x)
119}
120
Hao Zhu7039ecf2019-01-06 17:51:21 -0500121save_kable_latex <- function(x, file, latex_header_includes, keep_tex) {
122 temp_tex <- c(
123 "\\documentclass[border=1mm, preview]{standalone}",
124 "\\usepackage[active,tightpage]{preview}",
125 "\\usepackage{varwidth}",
126 "\\usepackage{amssymb, amsmath}",
127 "\\usepackage{ifxetex,ifluatex}",
128 "\\usepackage{fixltx2e}",
129 "\\usepackage{polyglossia}",
Hao Zhu7039ecf2019-01-06 17:51:21 -0500130 latex_pkg_list(),
131 "\\usepackage{graphicx}",
Hao Zhu7039ecf2019-01-06 17:51:21 -0500132 "\\usepackage{xltxtra,xunicode}",
Hao Zhueac7b032020-08-19 14:07:03 -0400133 "\\usepackage{xcolor}",
Hao Zhu7039ecf2019-01-06 17:51:21 -0500134 latex_header_includes,
135 "\\begin{document}",
136 solve_enc(x),
137 "\\end{document}"
138 )
139 temp_tex <- paste(temp_tex, collapse = "\n")
Hao Zhu7f8b6842018-10-23 17:41:13 -0400140
Hao Zhud8516932019-01-06 18:56:47 -0500141 temp_tex_file <- paste0(tools::file_path_sans_ext(file), ".tex")
Hao Zhu7039ecf2019-01-06 17:51:21 -0500142 writeLines(temp_tex, temp_tex_file, useBytes = T)
Hao Zhuf1873a42019-01-07 15:57:01 -0500143 temp_tex_file <- normalizePath(temp_tex_file)
144 file_no_ext <- tools::file_path_sans_ext(temp_tex_file)
145
146 owd <- setwd(dirname(temp_tex_file))
147
AC Craft7cea5332020-04-19 16:01:07 -0400148 system(paste0('xelatex -interaction=batchmode "', temp_tex_file,'"'))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500149 if (!keep_tex) {
Hao Zhuf1873a42019-01-07 15:57:01 -0500150 temp_file_delete <- paste0(file_no_ext, c(".tex", ".aux", ".log"))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500151 unlink(temp_file_delete)
152 }
153
Hao Zhuf1873a42019-01-07 15:57:01 -0500154 table_img_info <- NULL
Hao Zhud8516932019-01-06 18:56:47 -0500155 if (tools::file_ext(file) != "pdf") {
156 table_img_pdf <- try(
Hao Zhuf1873a42019-01-07 15:57:01 -0500157 magick::image_read(paste0(file_no_ext, ".pdf"),
Hao Zhud8516932019-01-06 18:56:47 -0500158 density = 300), silent = T)
159 if (class(table_img_pdf) == "try-error") {
160 stop("We hit an error when trying to use magick to read the generated ",
Hao Zhu53e59612019-01-15 12:16:06 -0600161 "PDF file. You may check your magick installation and try to ",
162 "use magick::image_read to read the PDF file manually. It's also ",
163 "possible that you didn't have ghostscript installed.")
Hao Zhud8516932019-01-06 18:56:47 -0500164 }
Hao Zhuf1873a42019-01-07 15:57:01 -0500165 unlink(paste0(file_no_ext, ".pdf"))
Hao Zhud8516932019-01-06 18:56:47 -0500166 table_img <- magick::image_convert(table_img_pdf,
167 tools::file_ext(file))
Hao Zhuf1873a42019-01-07 15:57:01 -0500168 table_img_info <- magick::image_info(table_img)
169 magick::image_write(table_img,
170 paste0(file_no_ext, ".", tools::file_ext(file)))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500171 }
Hao Zhu7039ecf2019-01-06 17:51:21 -0500172
Hao Zhuf1873a42019-01-07 15:57:01 -0500173 setwd(owd)
174
175 out <- paste0(file_no_ext, ".", tools::file_ext(file))
176 attr(out, "info") <- table_img_info
177 return(invisible(out))
Hao Zhu7f8b6842018-10-23 17:41:13 -0400178}