Automating Image Manipulation in Emacs Dired Mode

I manage my images using emacs dired, specifically image-dired. I found myself repeatedly marking images in order to paste their filepaths into various shell scripts for further manipulation.

This article presents a convenient way to automate image manipulation tasks using a Bash script and Emacs Dired mode. It presents an approach to creating a Bash script that resizes images, applies padding and aspect ratio, and removes EXIF information. The script is then bound to a C-c C-x key in Emacs Dired mode, allowing users to easily apply these operations to multiple images with a single keystroke. The article also covers making the script executable and monitoring the output of the script using journalctl.

Image manipulation script

#~/bin/image_manipulation.sh
outdir="/tmp/$(date +%Y%m%d_%H%M%S)"  # Create a directory with the current date and time
mkdir $outdir

for arg in "$@"; do
    source="$arg"  # Store the source file path
    filename="${source##*/}"  # Extract the filename from the source file path
    outfile="$outdir/$filename"  # Specify the output file path
    tmpfile="$outdir/tmp_$filename"  # Specify the temporary file path
    logger "Source: $arg, outfile: $outfile, tmpfile: $tmpfile"  # Log the source, output, and temporary file paths

    convert "$source" -resize 1350x1350 "$tmpfile"  # Resize the image
    ~/Downloads/aspectpad -a 1.25 -m al -p white "$tmpfile" "$outfile"  # Apply padding and aspect ratio

    # Remove all EXIF information from the image except the Orientation tag
    exiftool -overwrite_original -all= -tagsfromfile @ -Orientation "$outfile"

    rm $tmpfile  # Remove the temporary file
done

# Save the outdir path in the Emacs killring for easy access
echo "$outdir" > /tmp/kill

exit

Make the script executable

sudo chmod +x ~/bin/image_manipulation.sh

Bind script to key in emacs dired mode

(defun my-dired-send-to-image_manipulation ()
  "Send marked files in Dired to ~/bin/image_manipulation.sh
  assure ~/bin is in $PATH)"
  (interactive)
  (let ((files (dired-get-marked-files)))
    (shell-command (concat "image_manipulation.sh " (mapconcat #'shell-quote-argument files " ")))
    (message "Sent to image_manipulation.sh: %s" files)))
(define-key dired-mode-map (kbd "C-c C-x") 'my-dired-send-to-foo)

Check script output in log

journalctl -f

Enhanced Image manipulation script

(defun instashit ()
  "Send marked files in Dired to ~/bin/image_manipulation_insta.sh
  assure ~/bin is in $PATH)"
  (interactive)
  (let ((files (dired-get-marked-files)))
    (shell-command (concat "image_manipulation_insta.sh " (mapconcat #'shell-quote-argument files " ")))
    (message "Sent to image_manipulation_insta.sh: %s" files)))
(define-key dired-mode-map (kbd "C-c C-b") 'instashit)
2e5d076c55a51b7d510718e943548ee6
~/bin/image_manipulation_insta.sh
outdir="/tmp/$(date +%Y%m%d_%H%M%S)"  # Create a directory with the current date and time
text="Vernissage Brigitta Leupin 2024"
mkdir $outdir

for arg in "$@"; do
    source="$arg"  # Store the source file path
    filename="${source##*/}"  # Extract the filename from the source file path
    outfile="$outdir/web_$filename"  # Specify the output file path
    outfile_insta="$outdir/insta_$filename"  # Specify the output file path
    tmpfile="$outdir/tmp_$filename"  # Specify the temporary file path
    tmpfile_insta="$outdir/tmp_$filename"  # Specify the temporary file path
    logger "Source: $arg, outfile: $outfile, tmpfile: $tmpfile"  # Log the source, output, and temporary file paths
    logger "$text"  # Log the source, output, and temporary file paths

    # Website
    cp "$source" "$outfile"
    jpegoptim --size=500k "$outfile" --quiet
    # Remove all EXIF information from the image except the Orientation tag
    exiftool -overwrite_original -all= -tagsfromfile @ -Orientation "$outfile"
    # Add new exifinfo
    exiftool -overwrite_original -Exif:ImageDescription="$text" -Description="$text" "$outfile"
    logger $(exiftool "$outfile" | grep "$text")  # Log the source, output, and temporary file paths

    # Insta
    # Resize the insta image
    convert "$source" -resize 1350x1350 "$tmpfile_insta"
    # Apply padding and aspect ratio
    ~/Downloads/aspectpad -a 1.25 -m al -p white "$tmpfile_insta" "$outfile_insta"
    # Insta Remove all EXIF information from the image except the Orientation tag
    exiftool -overwrite_original -all= -tagsfromfile @ -Orientation "$outfile_insta"
    rm "$tmpfile_insta"  # Remove the temporary file
done

# Save the outdir path in the Emacs killring for easy access
echo "$outdir" > /tmp/kill

exit