After an upgrade to GIMP 3.0.4, I discovered that the script I used to automatically create thumbnails of JPEG images no longer worked. Upgrades - I hate them.

Following some Google-mediated research, the following changes had to be made to the script:

  • there’s no last function (strangely, butlast is still present)

  • file-jpeg-save becomes file-jpeg-export with slightly different arguments

  • script-fu-register is now deprecated, so use script-fu-register-procedure instead

  • in script-fu-register-procedure SF-VALUE is replaced by SF-STRING/SF_ADJUSTMENT (among others)

The invocation of GIMP to run a script has also changed. See the header comments in the source below.

After these changes, the script is this:

;;;; Thumbnail (Keep Aspect Ratio) Gimp script
;;;;
;;;; To run this from the command prompt:
;;;; gimp -c -d -i --batch-interpreter plug-in-script-fu-eval
;;;;      -b '(script-fu-thumbnail-kar "file.jpg" thumb-width full-width)'
;;;;      --quit
;;;;
;;;; NB strbreakup and unbreakupstr are defined in:
;;;;    /usr/share/gimp/3.0/scripts/scriptfu-init/script-fu-compat.scm

(define (script-fu-thumbnail-kar filename t-width f-width)
  (let* ((img 0) (drw 0) (fileparts (strbreakup filename "."))
         (file-part (unbreakupstr (butlast fileparts) "."))
         (file-suffix (car (reverse fileparts))))
    ;; car needed here because gimp functions return values as lists
    (set! img (car (file-jpeg-load #:run-mode 1
                                   #:file filename #:file filename)))

    ;; set image resolution to 72dpi
    (gimp-image-set-resolution img 72 72)
    ;; determine original aspect ratio and preserve w.r.t width required
    (let* ((original-width  (car (gimp-image-get-width  img)))
           (original-height (car (gimp-image-get-height img)))
           (t-height (* original-height (/ t-width original-width)))
           (f-height (* original-height (/ f-width original-width))))
      ;; create 'full-size' image
      (gimp-image-scale img f-width f-height)
      ;; also flatten image to reduce byte storage even further
      (set! drw (car (gimp-image-flatten img)))
      ;; save at quality level of .75 (gimp default) - saves storage
      (file-jpeg-export #:run-mode 1
                        #:image img
                        #:file (string-append file-part "-f." file-suffix)
                        #:options -1
                        #:quality 0.75)
      ;; create thumbnail image
      (gimp-image-scale img t-width t-height)
      (file-jpeg-export #:run-mode 1
                        #:image img
                        #:file (string-append file-part "-t." file-suffix)
                        #:options -1
                        #:quality 0.75))
      (gimp-image-delete img)))

(script-fu-register-procedure "script-fu-thumbnail-kar"
                              "Thumbnail (KAR)..."
                              "Process Image"
                              "Mark Willson/Martin Bradley"
                              "2025-07-10"
                              SF-STRING "Image Name" ""
                              SF-ADJUSTMENT "Thumbnail Height"
                              '(192 0 512 8 8 0 SF-SPINNER)
                              SF-ADJUSTMENT "Full Height"
                              '(766 0 1024 8 8 0 SF-SPINNER))

Another issue was that some images were not orientated as the photographer intended. EXIF metadate is used to indicate this, which GIMP can display, but does not seem accessible via the API.

The solution was therefore composed of two parts:

  • Use of the exif program to determine if an image required rotation

  • a GIMP script to rotate an image as required

First, the GIMP script to rotate and image:

;;;; Rotate image
;;;;
;;;; To run this from the command prompt:
;;;; gimp -c -d -i --batch-interpreter plug-in-script-fu-eval
;;;;      -b '(script-fu-rotate "file.jpg" rotation)'
;;;;
;;;;      The rotation value is one of:
;;;;          0 =  90 degrees
;;;;          1 = 180 degrees
;;;;          2 = 270 degrees


(define (script-fu-rotate filename rotation)
  (let* ((img 0))
    (set! img (car (file-jpeg-load #:run-mode 1 #:file filename)))
    (gimp-image-rotate img rotation)
    (file-jpeg-export #:run-mode 1
                      #:image img
                      #:file filename
                      #:options -1
                      #:quality 0.75)
  (gimp-image-delete img)))

;; SF-ADJUSTMENT values
;;  (default min max UI-inc UI-inc no-of-decimal-places UI-device)
(script-fu-register-procedure "script-fu-rotate"
                              "Batch Rotation ..."
                              "Rotate Image"
                              "Mark Willson"
                              "2025-07-09<"
                              SF-STRING "Image Name" " "
                              SF-ADJUSTMENT "Rotation"
                              '(0 0 2 1 1 0 SF-SPINNER))

And then a bash script to pull the two parts together:

#!/bin/bash
#
#  SYNOPSIS
#     jpg-rotate.sh file [file ...]
#
#  DESCRIPTION
#     Script to rotate JPEG files to the correct orientation, based
#     on EXIF metadata. Uses exif to obtain the JEPG image orientation
#     and GIMP to rotate as required.

#  MODIFICATION HISTORY
#  Mnemonic    Rel Date      Who
#  jpg-rotate  1.0 20250709  MPW
#

for file in $*
do
    if [[ -r ${file} ]]; then
        if [[ ${file} == *.jpg ]]; then
            if [[ ${file} != *-f* && ${file} != *-t* ]]; then
                echo "..processing ${file}"
                orient=$(exif -t Orientation -m "${file}")
                case $orient in
                    Right-top)
                        rot=0
                        ;;
                    Left-top)
                        rot=2
                        ;;
                    *)
                        continue
                        ;;
                esac
                nice -n 19 gimp -c -d -i \
                     --batch-interpreter plug-in-script-fu-eval \
                     -b "(script-fu-rotate \"${file}\" ${rot})" \
                     --quit
            fi
        else
            echo "${0}: not a jpg file: ${file}"
        fi
    else
        echo "$0: unable to process file: ${file}"
    fi
done