I am trying to assemble rtf with r2rtf package in R. But it doesn't support different page orientation. If there is other opportunity? I have multiple RTF files which already oriented correctly. They have different headers, footers ect. I just need to assemble them into 1 RTF file with correct orientation and page numbers.
I tried
assemble_rtf(
input = file,
output = output,
landscape = FALSE
)
file - stores paths to my temp separate RTFs output - path to output RTF
consider I have orientation specified for each separate file:
rtf_page(orientation = "landscape")
or
rtf_page(orientation = "portrait")
but in assembled RTF all pages were landscape
I'll use the example from r2rtf::assemble_rtf
since you haven't provided any. Before we start, here it is, creating a portrait & a landscape document and merging those:
library(r2rtf)
file <- replicate(2, tempfile(fileext = ".rtf"))
file1 <- head(iris) |>
rtf_body() |>
rtf_encode() |>
write_rtf(file[1])
file2 <- head(cars) |>
rtf_page(orientation = "landscape") |>
rtf_body() |>
rtf_encode() |>
write_rtf(file[2])
output <- tempfile(fileext = ".rtf")
assemble_rtf(
input = file,
output = output
)
This very example suffers from the same problem you have: it comes out as a landscape document. Aside, the landscape=
argument of assemble_rtf
v1.1.4 does nothing other than being the subject of some input validation, here's the entire source reference for it:
assemble_rtf <- function (input, output, landscape = FALSE) {
check_args(landscape, "logical", length = 1)
## ..... and nothing else??
}
Anyway, the major issue with the entire package is that they don't use sections which allow different page sizes & orientations, they only use properties that target the entire document at once. Here is a version of assemble_rtf
that makes this distinction, I've labelled the changes:
my_assemble_rtf <- function(input, output) {
input <- normalizePath(input)
n_input <- length(input)
missing_input <- input[!file.exists(input)]
if (length(missing_input) > 0) {
warning("Missing files: \n", paste(missing_input, collapse = "\n"))
input <- setdiff(input, missing_input)
}
rtf <- lapply(seq_along(input), \(i) {
## Change 1: use \LNDSCPSXN (landscape section)
## rather than \LANDSCAPE (whole document)
lines <- readLines(input[i]) |>
stringi::stri_replace_all_regex("\\landscape", "\\lndscpsxn")
## Change 2: use section-specific page sizes & margins
## after the first (which will still define the global default)
if (i > 1) {
lines <- stringi::stri_replace_all_regex(
lines,
"\\\\paper(w|h)(?=[^s])",
"\\\\pg$1sxn"
)
lines <- stringi::stri_replace_all_regex(
lines,
"\\\\marg(b|l|t|r)(?=[^s])",
"\\\\marg$1sxn"
)
}
return(lines)
})
n <- length(rtf)
start <- c(
1,
vapply(rtf[-1], \(x) max(grep("fcharset", rtf[[1]])) + 2, numeric(1))
)
end <- vapply(rtf, length, numeric(1))
end[-n] <- end[-n] - 1
for (i in seq_len(n)) {
rtf[[i]] <- rtf[[i]][start[i]:end[i]]
## Change 3: start a new *section* rather than a new *page*
## after each respective document
if (i < n) rtf[[i]] <- c(rtf[[i]], "\n\\pard\n\\sect\n")
}
rtf <- do.call(c, rtf)
r2rtf::write_rtf(rtf, output)
}
I should add that this solution is really quite bare-bones because r2rtf
apparently creates & assumes very basic RTF structure -- for example that there isn't anything but a fontmap in the header. Still, the principle applies and would require detailed knowledge of your actual RTF structure to further generalize.