2021-05-17

My camera writes photos in the High Efficiency Image File Format (HEIF) but darktable doesnโ€™t yet support reading them. As a stopgap Iโ€™ve scripted a wrapper around darktable that converts them to a supported format.

To use it I right-click on a HEIF file and choose Open withโ€ฆ โ†’ darktable (HEIF). A progress bar displays while files are converted, then darktable opens.

HEIF adapter for darktable

To discourage long-term reliance upon interim files and reduce clutter in the photo store, the outputs are kept in /tmp and symlinked into the photo store. Temporary files needed during the conversion are written only to /dev/shm to avoid unnecessary writes to persistent storage.

#!/usr/bin/env bash
set -Eeuxo pipefail

# Parameters
heifs=( "$@" )

# Start progress bar
steps_per_heif='3'
total_steps="$(( steps_per_heif * "${#heifs[@]}" ))"
task() { echo "# $1" >&3; }
progress() { echo "$(( $1 * 100 / total_steps ))" >&3; }
exec 3> >(zenity --width 600 --progress --percentage=0 --auto-close)

# For each HEIF file
links=()
for i in "${!heifs[@]}"; do heif="${heifs[$i]}"
task "Extracting ${heif##*/}"
progress "$(( steps_per_heif * i ))"

# Ensure TIFF
tiff="/tmp/heif-darktable$heif.tif"
if [[ ! -f "$tiff" ]]; then
# Extract image
y4m="$(mktemp --tmpdir=/dev/shm --suffix=.y4m)"; trap 'rm -f "$y4m"' EXIT
heif-convert "$heif" "$y4m"

# Encode as TIFF
progress "$(( steps_per_heif * i + 1 ))"
working="$(mktemp -u --tmpdir=/dev/shm --suffix=.tif)"; trap 'rm -f "$working"' EXIT
ffmpeg -i "$y4m" -c:v 'ppm' -f 'image2pipe' - | convert ppm:- "$working" && rm "$y4m"

# Transfer metadata
progress "$(( steps_per_heif * i + 2 ))"
exiftool -overwrite_original -TagsFromFile "$heif" -Orientation= "$working"

mv "$working" "$tiff"
fi

# Ensure symlink
link="$heif.tif"
[[ -L "$link" ]] || ln -s "$tiff" "$link"

# Collect links
links+=("$link")
done

# Stop progress bar
exec 3>&-

# Become darktable
exec darktable "${links[@]}"