Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active August 15, 2023 01:53
Show Gist options
  • Save ernstki/495ff1a60509e0b771f0d65740de1a19 to your computer and use it in GitHub Desktop.
Save ernstki/495ff1a60509e0b771f0d65740de1a19 to your computer and use it in GitHub Desktop.
Convert many images to any ImageMagick-supported format in parallel
#!/bin/bash
# intended for use with https://github.com/erichs/composure
# requires ImageMagick's 'convert' and GNU Parallel
# source: https://gist.github.com/ernstki/495ff1a60509e0b771f0d65740de1a19/edit
convertto ()
{
author 'Kevin Ernst'
about 'Convert arguments to another image format based on extension'
example "$ convertto jpg *.heic"
example "$ convertto -geometry 200x200 png *.heic"
param "-* - any valid ImageMagick 'convert' command line option"
param '$* - image(s) to convert'
group 'graphics'
group 'util'
local endopts dryrun ext opts=() files=()
local -A formats
local cache=~/.cache/imagemagick_formats.lst
local now=$(date +%s)
local setx=$(builtin set +o | grep '\bxtrace\b')
# set TRACE=1 in the environment for execution tracing (for debugging)
# you can also just run this inside a subshell with 'func() ()'
# instead of 'func() {}', and not worry about setting 'set +x' when
# you're done, but I wanted to see if this was possible to do (it is)
(( TRACE )) && set -x
trap "$setx" RETURN
# cache ImageMagick's list of formats at most once per day; also not
# stricly necessary -- it doesn't take *that* long to run, but I wanted
# to figure out how to do it
if [[ ! -s $cache ]] || (( (now - $(date -r $cache +%s)) > 86400 )); then
mkdir -p ~/.cache
identify -list format \
| awk '/^ *[A-Z0-9*]+ /{gsub(/\*/,"",$1);if($1){print $1}}' \
> $cache
fi
# read in list of formats
while read fmt; do formats[$fmt]=1; done < $cache
while (( $# )); do
if (( endopts )); then
files+=("$1"); shift; continue
fi
case $1 in
-h|--help)
reference $FUNCNAME
return
;;
-n|--dry-run)
dryrun=1
;;
--)
endopts=1
;;
-*)
opts+=("$1")
;;
*)
if [[ -r $1 ]]; then
files+=("$1")
elif [[ ${opts[@]: -1} =~ ^- && ! $ext ]]; then
# probably an argument to a previous ImageMagick option
opts+=("$1")
# the output of `identify -list format` is upper-case, so
# upper-case the argument and see if it's a key in $formats
elif [[ ${formats[${1^^}]} && ! $ext ]]; then
ext=$1
else
echo "ERROR: Unexpected option or unsupported image format '$1'." >&2
return 1
fi
;;
esac
shift
done
if [[ ${#files[@]} -eq 0 ]]; then
echo "ERROR: No files specified for conversion." >&2
return 1
fi
parallel ${dryrun:+--dry-run }convert ${opts:+"${opts[@]}"} {} {.}.$ext ::: "${files[@]}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment