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:
1<- fs::dir_ls(images, glob="*.png")
img_files 2cat("::: {layout-ncol=3}\n",
3::glue("![]({img_files})\n\n\n"),
glue":::",
4sep = ""
)
- 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 withcat()
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 avoidimage-10.png
appearing beforeimage-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 usingglue::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
based on this stackover flow question↩︎
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
@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}
}