Search code examples
rshinyms-wordofficer

How to make a border around an image in Word with officer


I want to create a Word file with a text paragraph on the left and an image of a leaflet-map on the right.

So far I can do it, but I would also like to make a border around the whole leaflet image.

The border in my example is only half the size of the image and thus it seems like only the left side has borders.

How can I make the border as big as the image?

library(shiny)
library(officer)
library(leaflet)
library(mapview)

ui <- fluidPage(
  leafletOutput("leafletmap"),
  downloadLink("downloadWord", "Download Word Docx")
)

getLeafletMap <- function() {
  leaflet() %>%
    addTiles() %>% 
    addPopups(-93.65, 42.0285, "Here is the <b>Department of Statistics</b>, ISU")
}

server <- function(input, output, session) {
  output$leafletmap <- renderLeaflet({
    getLeafletMap()
  })

  output$downloadWord <- downloadHandler(
    filename = 'Report.docx',
    content = function(file) {
      ## Map #########################
      map <- getLeafletMap()
      mapshot(x = map, file=paste0(getwd(), "/map.png"),
              remove_controls = c("layersControl"))

      ## Title & Texts #########################
      subtitle <- "Report Map"
      str5 <- "Lorem ipsum dolor sit amet, ligula iaculis mollis lacus consectetur, urna vitae potenti tortor!
      Sit commodo, venenatis leo at et. Ligula ac pulvinar sollicitudin gravida, lobortis lectus ligula et.
      Nisl tristique est erat lectus. Sodales egestas amet ac, ultricies nulla eu, risus blandit."

      ## Styles #########################
      text_style_title <- fp_text(font.size = 20, bold = FALSE, font.family = "Arial", color = "#808080")
      text_style <- fp_text(font.size = 10, bold = FALSE, font.family = "Arial")
      par_style <- fp_par(text.align = "justify")

      ## Make Word Docs #########################
      doc <- read_docx() %>%
        body_add_fpar(fpar(ftext("Report with Map", prop = text_style_title), fp_p = par_style)) %>%
        body_add_par("", style = "Normal") %>% # blank paragraph
        body_end_section_continuous() %>%

        body_add_fpar(fpar(ftext(str5, prop = text_style), fp_p = par_style)) %>%
        body_add_fpar(fpar(external_img(src = paste0(getwd(), "/map.png"), height = 3, width = 4.52),
                           fp_p = fp_par(text.align = "right", padding.top = 6,
                                         border = fp_border(width = 1, color = "red")))) %>%
        body_end_section_columns(widths = c(1.5,2), sep = FALSE, space = 0.2) %>%
        print(doc, target = file)
    }
  )
}

shinyApp(ui, server)

Solution

  • I was able to do it with flextable, vline and hline. One disclaimer, since I wasn't able to use the hline for i=0, there is an empty line in the table for i=0.

    library(flextable)
    library(officer)
    
    inputFolder <- "test/"
    std_border = fp_border(color="orange")
    
    testtable <- data.frame("text" = c("",""), "image" = c("",""))
    
    testft <- flextable(testtable) %>%
      delete_part(part = "header") %>%
      theme_box() %>%
      compose(i = 2, j = 2, value= as_paragraph(as_image(src = paste(inputFolder, "smiley.png", sep = ""), width = 1, height = 1))) %>%
      compose(i = 2, j = 1, value = as_paragraph(as_chunk("Just some random text"))) %>%
      border_remove() %>%
      vline(i=2, j=1, border = std_border) %>%
      vline(i=2, j=2, border = std_border) %>%
      hline(i=1, j=2, border = std_border) %>%
      hline(i=2, j=2, border = std_border)
    

    This gives me the following:

    enter image description here

    Of course you can format the text, images and borders according your needs.

    EDIT:

    Of course the officer part is just:

    doc <- read_docx() %>%
    body_add_flextable(testft)