Cover Up

Cover Up

Adding full sized cover images to Word documents programatically with officer, officedown, and purrr

I needed to add full size (A4, portrait) images to the first page of my Word document ( there are 13, all 30+ pages, which I’m generating in RMarkdown, as per previous post).

I didn’t want to do this by hand, especially when I discovered that due to margins and page settings, each image would have to be resized to fit on the page. (I tried adding the full sized image to a blank Word document but it was too large, and resulting attempts to resize it did not work well. I did not want to do this multiple times).

Here was the plan:

  • get all the full size images my colleagues created and save them in a source folder
  • automate the process of creating resized copies, and save those in another folder
  • create a blank, one page, Word document for each image
  • loop through and add the resized images to the corresponding blank document
  • use {officer} to add these blank documents as my ‘cover’ for each report.

I saved all the original , full size images into a ‘resources’ folder inside my ‘img’ folder, then looped through them and resized them as below.

library(here)
library(purrr)
library(magick)

setwd(here("img", "resources"))
files <- dir()

# taking dimensions at 90%

files_read <- map(files, image_read)
files_resized <- map(files_read, ~ image_resize(.x,
                                geometry = geometry_size_percent(width = 90)))

outdir <- paste0(here("img","resized", files))
walk2(files_resized, outdir, ~ image_write(.x, path = .y))

The next bit was to create blank documents, and add the resized images.

I created 2 functions; create_covers and add_images

library(officer)
library(officedown)
library(here)
library(magrittr)

create_covers <- function(areas) {

  # get list of resized images to insert into blank doc
  areas <- dir(here("img","resized"), full.names = TRUE)

  outnames <- gsub(".png", ".docx", areas)
  
# save these to a 'covers' folder outside the main 'img' folder

  outnames <- gsub("img/resized","covers",outnames)

  # read the blank source doc
  temp <- read_docx(here("covers","blank_cover.docx"))

  # write out the blank files
  walk(outnames,~ print(temp, .x))

}

add_images <- function(outnames, images,  width = 9.3,
                       height = 13.15625,
                       position_at = "after") {

  for (i in seq_along(outnames)) {

    read_docx(outnames[i]) %>%
      cursor_begin() %>%
      body_remove() %>%
      body_add_img(., images[i],
                   width = 9.3, # was 9.5 @92%
                   height = 13.15625, # was 13.4375 @ 92%
                   pos = position_at)  %>%
      print(.,outnames[i])

  }

}

With those functions in place, here’s how I created the covers and added the images:

areas <- dir(here("img","resized"), full.names = TRUE)

# create the blank covers - takes some time
create_covers(areas)

# replace the file extension
outnames <- gsub(".png", ".docx", areas)

outnames <- gsub("img/resized","covers", outnames)

images <- dir(here("img","resized"), full.names = TRUE)

# for loops FTW
add_images(outnames, images)

The final step was to add this to my Rmd file

cover_page_margin <- officer::page_mar(bottom = 0.00787402, # .02 cm
                                       top  = 0.00787402,
                                       right = 0.015748, #.04 cm
                                       left = 0.015748,
                                       header = 0,
                                       footer = 0,
                                       gutter = 0.00393701) # .01 cm


cover_section <- officer::prop_section(page_margins = cover_page_margin,
                                       page_size = (page_size(orient = "portrait")),
                                       type = "continuous")


And also :


officer::block_pour_docx(here("covers",eval(paste0(params$HSCP,".docx"))))
officer::block_section(cover_section)

This set the margins for the cover ( I had to have some space assigned), then created the section properties for the cover.
The block_pour_docx inserted the relevant cover page, and the block_section applied the cover section layout. This has to be placed after the content, as opposed to before it, as you may have expected.

With all this in place, the front covers look good, with a fairly even border all round.

Doing this work involves constantly converting between inches, centimetres, and pixels - here are some links that will help:

https://www.a4-size.com/a4-size-in-pixels/

https://convertermaniacs.com/px-to-inch/convert-1263-pixels-to-inches.html


© 2016 - 2022. All rights reserved.