Add Markdown Images Using Vim
I have recently been working on workflow for this blog, and one of the initial stumbling blocks was adding images.
The solution I now have in place works as follows:
- Press
<Leader>I
to be presented with a pop-up dialogue (usingzenity
) to select the folder containing images to be included. - After selecting the folder,
sxiv
pops up with a gallery of the images wherem
marks an image, andq
quits (and confirms). - With the selection of images, they are now optimised into a sub-folder of the blog post.
- Finally, links to the newly optimised images are added in to the content of markdown.
1. Selecting a folder
This first script takes an optional argument which is the start folder for the selection. This could be ~/Pictures
, which would likely be a good default for image path selections, although it also makes this script more generic to simply have it default to the home folder.
Source: select-path.sh
#!/usr/bin/env bash
START_PATH="${1:-$HOME}"
zenity --file-selection --directory --filename="$START_PATH"
2. Selecting images in a folder
This second script takes a required argument, which is a path. It doesn’t care where this path comes from, but in the case of the example in this post, it is the path as selected by the user from the script above.
Source: select-images-in-path.sh
#!/usr/bin/env bash
test -d "$1" || exitWithError "User selected folder does not exist"
# Select with `m` and confirm with `q`
sxiv -f -N "Select image(s)" -o -t "$1"
3. Optimise the images
This next script takes an image file, and a destination path, and will both optimise the image and also strip out any exif
information for it, placing it in the specified destination.
Source: image-optimise-to.sh
#!/usr/bin/env bash
# $0 "target/path" "source/path/file_name"
mkdir -p "$1"
test -d "$1" || exit 1
test -f "$2" || exit 1
SOURCE_IMAGE="$2"
TARGET_PATH="$1"
TARGET_IMAGE="$TARGET_PATH/$(basename "$2")"
# Args: Source Image, Target Image
convert "$SOURCE_IMAGE" -quiet -resize 2000x800^ -gravity center -extent 2000x800 -strip -interlace Plane -gaussian-blur 0.05 -quality 85% "$TARGET_IMAGE"
4. Putting it all together and outputting to Vim
This final script calls each ofthe previous scripts, and only takes a single argument which is the destination folder for the selected, optimised images.
Source: blog-images-import-to.sh
#!/usr/bin/env bash
# Get user selected images, optimise to target and return markdown segment
exitWithError () {
echo "$@" && exit 1
}
test -n "$1" || exitWithError "Target folder not specified"
mkdir -p "$1"
test -d "$1" || exitWithError "Target folder could not be created"
TARGET_FOLDER="$1"
SELECTED_IMAGES="$(select-images-in-path.sh "$(select-path.sh "$HOME/Pictures")")"
test -n "$SELECTED_IMAGES" || exitWithError "No images selected in path"
for SOURCE_IMAGE in $SELECTED_IMAGES; do
# Source image path must be relative - readlink -f %
ABSOLUTE_TARGET_DIR="$(readlink -f "$TARGET_FOLDER")"
SOURCE_FILE="$(basename "$SOURCE_IMAGE")"
# Echo images ready for Vim
image-optimise-to.sh "$ABSOLUTE_TARGET_DIR" "$SOURCE_IMAGE" && \
echo "![$SOURCE_FILE]($TARGET_FOLDER/$SOURCE_FILE)"
done
And finally, this is the snippet of code I use in Vim. It calls blog-images-import-to.sh
with an argument being the current markdown file, without the .md
extension. You will also notice that it also changes the current path to the path of the markdown file, so links work relative to the current file with images placed in the sub-folder.
function! ImportBlogImages(currentFile, currentPath)
echom "Select a folder and image(s) to include in this post"
exec 'cd ' . a:currentPath
silent execute 'r!blog-images-import-to.sh ' . a:currentFile[:-4]
endfunction
" List contents of a path matching the filename (without .md) - pipe through
nmap <Leader>I :call ImportBlogImages(expand("%"), expand("%:p:h"))<CR>
Conclusion
You will notice that each of the parts of the process are separate scripts, each with its own purpose. This is deliberate, and allows any of the scripts to be rewritten, perhaps to use different applications or libraries, or used in combination with different scripts for different purposes.
The part that inserts the mark-up is specific to markdown and its use for the blog, so each of the scripts are pulled together into a single script blog-images-import-to.sh
, and is simply called via the function in Vim.