Programmatically embed (and layout) a whole folder of images in Quarto document

How to use ‘asis’ output from R code chunks to generate inline image links for an entire directory of images, AND arrange them using Quarto’s custom figure layout syntax

quarto
how-to
markdown
listings
Author

Cynthia Huang

Published

January 29, 2024

Modified

November 9, 2024

The Task

Say you have a folder of images you want to include in a custom figure layout within a Quarto document. Here’s what such folder might look like:

layout-folder-images/
├── index.qmd
└── images/
    ├── image-001.png
    ├── image-002.png

Let’s say we want to include the image-00*.png images side-by-side. The Quarto markdown for this might look like:

index.qmd
::: {layout-ncol=2}
!()[images/image-001.png]

!()[images/image-002.png]

:::

Code chunk magic

Writing out markdown is fine for a few images, but it could get quickly get tedious (e.g. a whole folder). Instead, why not use an R code chunk1 to generate the markdown:

```{r}
#| output: asis
img_files <- fs::dir_ls("images", glob="*.png")
cat("::: {layout-ncol=2}\n",
    glue::glue("![]({img_files})\n\n\n"),
    ":::",
    sep = ""
)
```

Example Output

Here’s some example output2 using some sketchnotes I drew many years ago:

Code Explanation

And finally, an explanation of how the code works:

1img_files <- fs::dir_ls(images, glob="*.png")
2cat("::: {layout-ncol=3}\n",
3    glue::glue("![]({img_files})\n\n\n"),
    ":::",
4    sep = ""
)
1
Get paths to all the image files in the images/ folder.
2
Use cat() to output the starting fence for the custom figure layout div.
3
Use glue() to generate the inline image links for each image separated by new lines (required for custom layouts). Output the links with cat() and close the figure div.
4
Set cat() to output each markdown component without any additional whitespace.

Notes and Extension Ideas

  • If your images have a natural order to them (as mine do in the example above), make sure your file names reflect this ordering. I think dir_ls() sorts alphabetically by default, so make sure to pad your numbering if you’ve got more than 9 files (i.e. to avoid image-10.png appearing before image-9.png).
  • Quarto allows you to specify custom layouts with non-equal columns/rows. See Figures in the official Quarto Guide for more.
  • My example doesn’t support captions (i.e. the [] element is empty). You could easily rectify this by storing both file names and their captions in the same table, and using glue::glue_data() to generate a string from an expression like: "![{caption}]({img_path})". See this documentation from the {glue} package for more details.

I wrote this code in order to bulk embed written notes I wrote at a few conferences last year into Quarto websites. I’ll be writing about how I use Quarto as a personal knowledge management tool/scrapbook/research compendium in an upcoming blog post. Stay tuned!

Footnotes

  1. based on this stackover flow question↩︎

  2. Note to future me: the example images come from a pdf (also in the source folder). This is the zsh command I used to extract each page as separate images using imagemagick: convert -quality 100 -density 200 ${filename}.pdf image-%02d.png↩︎

Citation

BibTeX citation:
@online{huang2024,
  author = {Huang, Cynthia},
  title = {Programmatically Embed (and Layout) a Whole Folder of Images
    in a {Quarto} Document},
  date = {2024-01-29},
  url = {https://www.cynthiahqy.com/posts/layout-folder-images/},
  langid = {en}
}
For attribution, please cite this work as:
Huang, Cynthia. 2024. “Programmatically Embed (and Layout) a Whole Folder of Images in a Quarto Document.” January 29, 2024. https://www.cynthiahqy.com/posts/layout-folder-images/.