blob: ebad3d3c2f8339ec7c9537a9c358d53358ac669d [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`.
Hao Zhu73cf3732018-05-11 17:50:05 -040021#'
22#' @export
23save_kable <- function(x, file,
Hao Zhu7039ecf2019-01-06 17:51:21 -050024 bs_theme = "simplex", self_contained = TRUE,
25 extra_dependencies = NULL, ...,
26 latex_header_includes = NULL, keep_tex = FALSE) {
Hao Zhud8516932019-01-06 18:56:47 -050027 if (!is.null(attr(x, "format")) && attr(x, "format") == "latex") {
Hao Zhu7039ecf2019-01-06 17:51:21 -050028 return(save_kable_latex(x, file, latex_header_includes, keep_tex))
Hao Zhu7f8b6842018-10-23 17:41:13 -040029 }
Hao Zhu7039ecf2019-01-06 17:51:21 -050030 return(save_kable_html(x, file, bs_theme, self_contained,
31 extra_dependencies, ...))
Hao Zhu7f8b6842018-10-23 17:41:13 -040032}
33
Hao Zhu7039ecf2019-01-06 17:51:21 -050034save_kable_html <- function(x, file, bs_theme, self_contained,
35 extra_dependencies, ...) {
36 dependencies <- list(
Hao Zhu73cf3732018-05-11 17:50:05 -040037 rmarkdown::html_dependency_jquery(),
38 rmarkdown::html_dependency_bootstrap(theme = bs_theme),
39 html_dependency_kePrint()
40 )
Hao Zhu7039ecf2019-01-06 17:51:21 -050041 if (!is.null(extra_dependencies)) {
42 dependencies <- append(dependencies, extra_dependencies)
43 }
44
Hao Zhu46a42a12019-01-22 00:11:11 -050045 html_header <- htmltools::tags$head(dependencies)
Hao Zhu73cf3732018-05-11 17:50:05 -040046 html_table <- htmltools::HTML(as.character(x))
47 html_result <- htmltools::tagList(html_header, html_table)
Hao Zhu7f8b6842018-10-23 17:41:13 -040048
49 # Use webshot if necessary
50 if (tools::file_ext(file) %in% c("png", "jpg", "jpeg", "pdf")) {
51 file_html <- paste0(tools::file_path_sans_ext(file), ".html")
Hao Zhuf1873a42019-01-07 15:57:01 -050052 file.create(file_html)
53 file_html <- normalizePath(file_html)
54 file <- paste0(tools::file_path_sans_ext(file_html), ".",
55 tools::file_ext(file))
Hao Zhu7f8b6842018-10-23 17:41:13 -040056 htmltools::save_html(html_result, file = file_html)
57 webshot::webshot(file_html, file, ...)
Hao Zhu7039ecf2019-01-06 17:51:21 -050058 if (tools::file_ext(file) == "pdf") {
59 message("Note that HTML color may not be displayed on PDF properly.")
60 }
Hao Zhu7f8b6842018-10-23 17:41:13 -040061 unlink(file_html)
Hao Zhuf1873a42019-01-07 15:57:01 -050062 unlink(file.path(dirname(file_html), "lib"), recursive = TRUE)
63 if (requireNamespace("magick", quietly = TRUE)) {
64 img_rework <- magick::image_read(file)
65 img_rework <- magick::image_trim(img_rework)
66 img_info <- magick::image_info(img_rework)
67 magick::image_write(img_rework, file)
68 attr(file, "info") <- img_info
69 } else {
70 message("save_kable will have the best result with magick installed. ")
71 }
Hao Zhu7f8b6842018-10-23 17:41:13 -040072 } else {
Hao Zhuf1873a42019-01-07 15:57:01 -050073 file.create(file)
74 file <- normalizePath(file)
Hao Zhu7f8b6842018-10-23 17:41:13 -040075 htmltools::save_html(html_result, file = file)
76 if (self_contained) {
Hao Zhu46a42a12019-01-22 00:11:11 -050077 remove_html_doc(file)
Hao Zhu7f8b6842018-10-23 17:41:13 -040078 rmarkdown::pandoc_self_contained_html(file, file)
Hao Zhu46a42a12019-01-22 00:11:11 -050079 unlink(file.path(dirname(file), "lib"), recursive = TRUE)
Hao Zhu7f8b6842018-10-23 17:41:13 -040080 }
Hao Zhu73cf3732018-05-11 17:50:05 -040081 }
Hao Zhud8516932019-01-06 18:56:47 -050082
Hao Zhuf1873a42019-01-07 15:57:01 -050083 return(invisible(file))
Hao Zhu73cf3732018-05-11 17:50:05 -040084}
Hao Zhu7f8b6842018-10-23 17:41:13 -040085
Hao Zhu46a42a12019-01-22 00:11:11 -050086remove_html_doc <- function(x){
87 out <- paste(readLines(x)[-1], collapse = "\n")
88 writeLines(out, x)
89}
90
Hao Zhu7039ecf2019-01-06 17:51:21 -050091save_kable_latex <- function(x, file, latex_header_includes, keep_tex) {
92 temp_tex <- c(
93 "\\documentclass[border=1mm, preview]{standalone}",
94 "\\usepackage[active,tightpage]{preview}",
95 "\\usepackage{varwidth}",
96 "\\usepackage{amssymb, amsmath}",
97 "\\usepackage{ifxetex,ifluatex}",
98 "\\usepackage{fixltx2e}",
99 "\\usepackage{polyglossia}",
Hao Zhu7039ecf2019-01-06 17:51:21 -0500100 latex_pkg_list(),
101 "\\usepackage{graphicx}",
Hao Zhu7039ecf2019-01-06 17:51:21 -0500102 "\\usepackage{xltxtra,xunicode}",
103 latex_header_includes,
104 "\\begin{document}",
105 solve_enc(x),
106 "\\end{document}"
107 )
108 temp_tex <- paste(temp_tex, collapse = "\n")
Hao Zhu7f8b6842018-10-23 17:41:13 -0400109
Hao Zhud8516932019-01-06 18:56:47 -0500110 temp_tex_file <- paste0(tools::file_path_sans_ext(file), ".tex")
Hao Zhu7039ecf2019-01-06 17:51:21 -0500111 writeLines(temp_tex, temp_tex_file, useBytes = T)
Hao Zhuf1873a42019-01-07 15:57:01 -0500112 temp_tex_file <- normalizePath(temp_tex_file)
113 file_no_ext <- tools::file_path_sans_ext(temp_tex_file)
114
115 owd <- setwd(dirname(temp_tex_file))
116
Hao Zhu8902df82019-01-07 16:27:32 -0500117 system(paste0("xelatex -interaction=batchmode ", temp_tex_file))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500118 if (!keep_tex) {
Hao Zhuf1873a42019-01-07 15:57:01 -0500119 temp_file_delete <- paste0(file_no_ext, c(".tex", ".aux", ".log"))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500120 unlink(temp_file_delete)
121 }
122
Hao Zhuf1873a42019-01-07 15:57:01 -0500123 table_img_info <- NULL
Hao Zhud8516932019-01-06 18:56:47 -0500124 if (tools::file_ext(file) != "pdf") {
125 table_img_pdf <- try(
Hao Zhuf1873a42019-01-07 15:57:01 -0500126 magick::image_read(paste0(file_no_ext, ".pdf"),
Hao Zhud8516932019-01-06 18:56:47 -0500127 density = 300), silent = T)
128 if (class(table_img_pdf) == "try-error") {
129 stop("We hit an error when trying to use magick to read the generated ",
Hao Zhu53e59612019-01-15 12:16:06 -0600130 "PDF file. You may check your magick installation and try to ",
131 "use magick::image_read to read the PDF file manually. It's also ",
132 "possible that you didn't have ghostscript installed.")
Hao Zhud8516932019-01-06 18:56:47 -0500133 }
Hao Zhuf1873a42019-01-07 15:57:01 -0500134 unlink(paste0(file_no_ext, ".pdf"))
Hao Zhud8516932019-01-06 18:56:47 -0500135 table_img <- magick::image_convert(table_img_pdf,
136 tools::file_ext(file))
Hao Zhuf1873a42019-01-07 15:57:01 -0500137 table_img_info <- magick::image_info(table_img)
138 magick::image_write(table_img,
139 paste0(file_no_ext, ".", tools::file_ext(file)))
Hao Zhu7039ecf2019-01-06 17:51:21 -0500140 }
Hao Zhu7039ecf2019-01-06 17:51:21 -0500141
Hao Zhuf1873a42019-01-07 15:57:01 -0500142 setwd(owd)
143
144 out <- paste0(file_no_ext, ".", tools::file_ext(file))
145 attr(out, "info") <- table_img_info
146 return(invisible(out))
Hao Zhu7f8b6842018-10-23 17:41:13 -0400147}