Batch Image Processing with GIMP Python-Fu from the Command Line
Automate GIMP resizing and format conversion with Python-Fu scripts run in batch mode from the shell, including a working example, verification steps, and memory and API-version pitfalls.
16 Oct 2025, 10:59 UTC

The problem: resizing hundreds of images without clicking
You have a folder of product photos, screenshots, or scanned assets that all need the same treatment — resize to a fixed width, convert to a different format, maybe flatten transparency. Opening each file in the GIMP GUI is not viable past a dozen images. The useful takeaway: GIMP ships with a scripting interface (Python-Fu) and a batch mode (gimp -b) that lets you run a saved script over many files from a shell script or CI job, with no display interaction required.
This guide targets GIMP 2.10 on Linux. The Python-Fu API changed across major versions, so verify procedure names against your installed release before deploying a script widely.
Prerequisites
- GIMP 2.10 or later, installed with Python-Fu support. Check with
gimp --version. Some distribution packages split Python support into a separate package (for example,gimp-pythonon older Debian/Ubuntu releases). - Shell access where you can run
gimpdirectly. Batch mode still initializes GIMP's core, so the account needs read access to the input directory and write access to the output directory. - A test copy of your images. Never point a new batch script at the only copy of production assets.
To confirm the script interface is present, run gimp -i -b '(gimp-version)' -b '(gimp-quit 0)' in a terminal. It should exit without an error dialog. You can also list registered procedures with gimp --dump-procs (output is large; pipe it to a file) and grep for the functions you plan to call.
A working example: batch resize and convert to JPEG
Save the following as batch_resize.py. It registers a procedure that takes an input directory, an output directory, and a target width, then processes every PNG it finds.
#!/usr/bin/env python
from gimpfu import *
import os
def batch_resize(src_dir, dst_dir, target_width):
for name in os.listdir(src_dir):
if not name.lower().endswith(".png"):
continue
src = os.path.join(src_dir, name)
dst = os.path.join(dst_dir, os.path.splitext(name)[0] + ".jpg")
image = pdb.gimp_file_load(src, name)
drawable = pdb.gimp_image_get_active_drawable(image)
w = pdb.gimp_image_width(image)
h = pdb.gimp_image_height(image)
new_h = int(h * (float(target_width) / w))
pdb.gimp_image_scale(image, target_width, new_h)
pdb.gimp_image_flatten(image)
drawable = pdb.gimp_image_get_active_drawable(image)
pdb.file_jpeg_save(image, drawable, dst, name,
0.9, 0.0, 1, 1, "", 0, 1, 0, 0)
pdb.gimp_image_delete(image)
register(
"batch_resize",
"Resize PNGs and save as JPEG",
"Batch resize and convert",
"you", "you", "2026",
"Batch resize...",
"",
[
(PF_DIRNAME, "src_dir", "Source directory", "/tmp/in"),
(PF_DIRNAME, "dst_dir", "Output directory", "/tmp/out"),
(PF_INT, "target_width", "Target width (px)", 1200),
],
[],
batch_resize)
main()Key details in this script:
pdbis GIMP's Procedural Database — the registry of every operation the application exposes. Scripting means calling PDB procedures by name.gimp_image_flattenmerges layers onto a white background, which matters because JPEG has no alpha channel; skipping it can produce unexpected results on transparent PNGs.gimp_image_deletefrees the image from memory. Without it, long batches accumulate loaded images and RAM usage climbs until the process is killed — a real constraint on machines with limited memory.
Running it in batch mode
Install the script by copying it into GIMP's plug-ins directory — typically ~/.config/GIMP/2.10/plug-ins/ for a per-user install — and make it executable (chmod +x batch_resize.py). Then run, as the same user, from a shell:
gimp -i -b '(python-fu-batch-resize RUN-NONINTERACTIVE "/srv/images/in" "/srv/images/out" 1200)' -b '(gimp-quit 0)'The -i flag suppresses the GUI (useful on headless servers; GIMP still needs its core libraries, but not a display). The first -b expression calls your registered procedure — note that underscores in the Python function name become hyphens in the PDB name. The second -b quits GIMP so the shell command returns. Replace the paths and width with your own values.
Verifying the result
- Count outputs:
ls /srv/images/out | wc -lshould match the number of PNG inputs. - Check dimensions with
identify(ImageMagick) orfileon a sample of outputs — width should be exactly 1200 px, height scaled proportionally. - Confirm the format:
file out.jpgshould report JPEG image data. - Watch memory during a large run (
toporps -o rsson the gimp process). If usage grows steadily across files, check that every loaded image is deleted.
Limitations and recovery
Batch mode does not roll anything back — if your script overwrites files in place, the originals are gone. Always write to a separate output directory, and keep inputs read-only (chmod a-w on the source folder) as a cheap safeguard while developing the script.
Other constraints to plan around:
- API drift: procedure names and signatures differ between GIMP 2.8, 2.10, and 3.x. A script written for one release can fail silently or with an opaque PDB error on another. Test after every GIMP upgrade, and pin the GIMP version in CI environments.
- One bad file: a corrupt input can abort the whole batch. For large jobs, wrap per-file work in error handling or split the file list and process chunks, so a failure only costs one chunk.
- Startup overhead: each
gimp -binvocation loads GIMP's core. Process many files per invocation rather than one invocation per file.
If a run produces no output, re-run without -i and with --verbose to see console messages, or test the procedure interactively first via Filters > Script-Fu > Console inside the GUI, where PDB errors are easier to read.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.