Command-line (bash/GIMP) mass conversion from XCF to JPG

This post was written by eli on July 31, 2009
Posted Under: Software, gimp

The purpose

I use GIMP a lot. I store the images in the native file format, XCF. Now I’m stuck with a lot of files I can’t see outside GIMP, but I don’t want to save those files as anything else, because I’ll lose all the layer data. Solution: Batch conversion to JPEG as a simple bash script to run from the command line.

The idea is to make a JPEG copy of the image as it’s seen when it’s opened with GIMP. For that reason, I’ve chosen to flatten the image by visible layers only, and to crop it to image size.

The script

It looks like LISP and it looks like bash. In fact, they’re mixed.

#!/bin/bash
{
cat <<EOF
(define (convert-xcf-to-jpeg filename outfile)
  (let* (
	 (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
	 (drawable (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE)))
	 )
    (file-jpeg-save RUN-NONINTERACTIVE image drawable outfile outfile .9 0 0 0 " " 0 1 0 1)
    (gimp-image-delete image) ; ... or the memory will explode
    )
  )

(gimp-message-set-handler 1) ; Messages to standard output
EOF

for i in *.xcf; do
  echo "(gimp-message \"$i\")"
  echo "(convert-xcf-to-jpeg \"$i\" \"${i%%.xcf}.jpg\")"
done

echo "(gimp-quit 0)"
} | gimp -i -b -

To try it out, simply execute the script from a directory containing several .xcf files. Be sure not have any .jpg files you care about in the same directory, because the outputs are with the same file names, just with the .jpg extension (old files are overwritten with no warning).

You will get kind-of-warning messages while the script is iterating, indicating which file is being processed. This is normal.

The concept of this script is simple. An ad-hoc LISP script is generated in the Bash block, which is enclosed by curly brackets. First we define the function, which converts one file. The bash script then creates calls to this function, by means of the (Bash) for-loop. All this is then fed into GIMP through standard input (piping).

Some LISP notes

I’m not really into LISP. So I ran into some trouble. These are my notes, so I won’t go through it again:

First, there’s the Script-Fu console, which was, well, sort-of helpful. The internal functions’ API can be found there as well.

As a LISP novice, I didn’t know the difference between “let” and “let*”. It turns out, that let* allows the use of previous assignments in the following ones, so this is what you get in the Script-Fu console:

> (let ( (x 2) (y x)) y)
Error: eval: unbound variable: x 

> (let* ( (x 2) (y x)) y)
2

It’s also worth to note, that the GIMP interpreter does not remember functions across different -b command-line arguments:

# First statement succeeds, second fails.
gimp -i -b '(define (myfun x y) (- x y))' -b '(myfun 2 3)'

# This works, because it's two statements in one execution (yuck!)
gimp -i -b '(define (myfun x y) (- x y)) (myfun 2 3)'

Reader Comments

thanks so much, needed this. You rock dude!

#1 
Written By Benjamin on October 13th, 2009 @ 19:57

Thank you. A few slight modifications and I’m converting pnm files. Many thanks.

#2 
Written By David on December 14th, 2009 @ 03:27

./mass-convert.sh: line 5: syntax error near unexpected token `convert-xcf-to-jpeg’
./mass-convert.sh: line 5: `(define (convert-xcf-to-jpeg filename outfile)’

#3 
Written By bib on January 26th, 2010 @ 07:07

There are two weird things about your problem:

1. The offending line is within a “cat << EOF”, which means that bash shouldn’t parse these lines, but send them as is to gimp (to which the cat is piped)
2. convert-xcf-to-jpeg appears in line 4, not 5

It looks like you’re running another shell than bash. Or that you’ve modified the script significantly.

#4 
Written By eli on January 26th, 2010 @ 12:52

Thanks a lot!
(worked for me in Ubuntu Karmic Koala)

#5 
Written By Pedro on March 19th, 2010 @ 13:42

Thanks a lot!
Trying to alter the script for png saving but can’t get it to work.
Tried to replace all jpeg to png in the script and can’t find anything jpeg specific or missing from png save.
Any ideas?

#6 
Written By David on May 19th, 2010 @ 13:26

file-png-save takes completely different parameters. Open the script-fu console, click “Browse…” and type “png” in the text window. You’ll find file-png-save listed there. Have a look on the parameter list. Compare with file-jpeg-save and alter as necessary.

#7 
Written By eli on May 19th, 2010 @ 13:32

Hi. Thx for this post. It’s great. This is bash script which sends lisp commands to GIMP ( if I’m not wrong). Is it possible to make lisp sript which sends bash commands ?

TIA

#8 
Written By Adam on September 5th, 2010 @ 22:18

I’m not so good with lisp, as one can learn from the post itself.

A quick Google brought me to the run-shell-command function, but I don’t know if it’s included in GIMP or if this remark is even relevant. Hope someone pops up with a better answer…

#9 
Written By eli on September 5th, 2010 @ 22:26

Add a Comment

required, use real name
required, will not be published
optional, your blog address