A script to open a GIMP 2.9 XCF file and export a png

Anyone here familiar with writing scripts? My ability to write scripts is practically non-existent, but I want to write a script to run at the command line, that will

  • Open all XCF files in a folder and its subfolders, one xcf file at a time
  • Export a 16-bit png with the double extension “xcf.png”
  • Close the XCF file

The script needs to work with GIMP-2.9 files.

There are scripting engines supplied with GIMP, but my efforts to make sense of “what to do” have completely failed. But maybe it’s not necessary to use a GIMP scripting engine to simply open a GIMP file, export a 16-bit png, and then close the GIMP file.

I want to use the script to generate XCF ‘sidecar pngs’ that have the double extension “.xcf.png” as a workaround for the fact that digiKam can’t make thumbnails and can’t show previews for GIMP 2.9 XCF files.

1 Like

I haven’t done this in a long time, but maybe a place to start?

#!/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)"

} | /c/Program\ Files/GIMP\ 2.9/bin/gimp-2.9.exe -i -b -

This is obviously from a windows (cygwin) environment, adjust as necessary.

You can also probably just grab the appropriate portiosn to pass to the -b parameter for gimp on the console, and roll your own listing of all XCF in current and subdir (xargs?).

Maybe of academic interest, but the Gimp plugin BIMP works, although very slowly.

Using Gimp 2.9.7 - from 'buntu ppa
Some panasonic .rw2 files as a test.
Opened in Gimp using nUFRaw (yes, I did eventually get it compiled) and then saved to Gimp 2.9.7 (16 bit) xcf files.

In BIMP only 2 procedures to add - Change Format (to png) - Rename with a pattern (to insert the .xcf)

When finished the png does open in GIMP as 16 bit and as a check using Imagemagick

Monster file size.

Hi @patdavid - is that a script using one of the GIMP script-thingies, script-fu? Is that the right word? Anyway, I think invoking a GIMP script-thingy (python being the other one, unless there’s more than two) is probably going to be necessary.

I found this page:

from which I wrote this modified version, into which hopefully some “GIMP script thingies” (I really need to learn the vocabulary - sorry!) could be placed as indicated:

#!/bin/bash

directory="/hdd/old-edit/test-gimp-png-script"

browsefolders () {
  for i in "$1"/*; 
  do
    extension=`echo "$i" | cut -d'.' -f2`

    if     [ -f "$i" ]; then        

        if [ $extension == "xcf" ]; then
            echo "$i"

#
# Here is where the command to open a file with GIMP, export a png, 
# and close GIMP would go. This probably needs to use a GIMP script
# of some sort.
#
# Or maybe it would be better to start GIMP once, before the loop,
# and then open each file in turn, export the png, and close the file,
# and then close GIMP after the loop.
#

        fi

    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

The above script works very nicely to print out the full paths to the xcf files in a folder with subfolders. I have no idea how to put a GIMP script in place of the comments describing what the script should do. The code sample you give looks like it’s the right sort of code, but I am clueless how to figure out what it’s doing - the language just looks odd to me - is there a link to some documentation?

Hi @rich2005 I suspect BIMP might not be useable, but maybe if it could be somehow automatically opened and fed the appropriate procedures?

You are right, regardless of how they are made, the resulting png files can be pretty big. I suppose they could be resized using imagemagick as part of the script, to some user-specified size.

WRT to speed of execution, this probably would be a script to run overnight. And maybe it would need to be further refined to not export a new png unless the xcf file had been modified since the last png was exported.

WRT to imagemagick, imagemagick can make pngs from xcf files by using xcftools, which afaik doesn’t support GIMP-2.9.

I forgot where I originally got that script from, but the general idea is that it defines the script-fu required to do what you want, and passes it to the gimp command line -b interpreter to do what you want (hence all that nutty lisp-y stuff in the bash file).

Honestly, it’s akin to saying:

gimp -i -b "(SCRIPT-FU STUFF HERE)"

@patdavid Always wondered: does script-fu come from foobar? Makes me think of kung fu!

Well, Tiny-Fu, from Tiny-Scheme, from scheme/lisp background, iirc. :slight_smile:

Hmm, well, I’ve made some progress. Now the script will open and export “blah.xcf” as “blah.xcf.png”. :slight_smile: But if run again it will also open and export “blah.xcf.png” as “blah.xcf.xcf.png”. :frowning: The problem is obvious (“extension=echo "$i" | cut -d'.' -f2”). I’m working on a solution.

If you are running this on Linux you might get rid of the big script and use a simple call to find:

find . -iname \*xcf -exec ls -l {} \;

Replace ls -l with your call to GIMP, the {} gets replaced with the filename.

2 Likes

Hi @houz - I considered trying to use find. I didn’t know about replacing {} with the filename, so thanks! However, even with this bit of information, it’s not clear to me where/how to replace part of the script with “find”.

Below is a revised script that does seem to work, and it’s no slower than one would expect - large GIMP xcf files take a long time to have the png exported, regardless of whether one is using a script or working through the UI, except that with the script there’s no waiting for the image to finish loading, so the script is actually faster.

Some comments/questions:

  • There still needs to be code that only makes the “xcf.png sidecar” if the xcf file has been modified since the last time the png was exported.

  • GIMP is being closed and restarted for every file. How would I move GIMP up in the script so that it’s only started once? Or maybe given how GIMP loves to hold onto memory in RAM, maybe it’s actually a good idea to restart it after every image? The start/close parts of the script don’t take nearly as much time as exporting the pngs.

  • As noted in the script comments, I used some python code that I found on stackexchange. The copyright according to stackexchange is “user contributions licensed under cc by-sa 3.0 with attribution required. rev 2017.10.26.27576”.

  • There seems to be an error in GIMP’s python-eval.py file: “plug-in ‘python-eval.py’ aborted before sending its procedure return values”. Or else maybe something in the script is causing the error message.

  • Looking at Pat’s script, I’m sure a script to export pngs could be a lot smaller, but probably not any faster.

  • Of course setting up the prefix is different for every GIMP-2.9 installation, and frankly I’m not sure this is even necessary.

  • Probably this won’t run “as is” except on Linux.

    #!/bin/bash

    # Establish the prefix where GIMP-2.9 is installed
    PREFIX=$HOME/code/gimpdefault/install
    export PATH=$PREFIX/bin:$PATH
    export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
    export XDG_DATA_DIRS=$PREFIX/share:$XDG_DATA_DIRS
    export XDG_CACHE_HOME=/home/elle/.cache
    export ACLOCAL_FLAGS="-I $PREFIX/share/aclocal"
    export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH
    export GIO_EXTRA_MODULES=/usr/lib/gio/modules
    export SRC_DIR=$HOME/code/gimpdefault/build
    GEGL_USE_OPENCL=no
    export GEGL_USE_OPENCL
    GIMP_COLOR_TRANSFORM_DISABLE_BABL=yes
    export GIMP_COLOR_TRANSFORM_DISABLE_BABL

    directory="/home/elle/gimp-script"

    browsefolders () {
      for i in "$1"/*; 
      do
        filename="$i"
        #echo $filename
        extension=`echo ${filename##*.}`
        #echo $extension

        if     [ -f "$i" ]; then        

            if [ $extension == "xcf" ]; then
                echo "$i"
    #

    # modified from
    # https://stackoverflow.com/questions/5794640/how-to-convert-xcf-to-png-using-gimp-from-the-command-line
    # by user "Flow": https://stackoverflow.com/users/194894/flow


    # Start gimp with python-fu batch-interpreter
    /home/elle/code/gimpdefault/install/bin/gimp-2.9 -i -d -f -s --batch-interpreter=python-fu-eval -b - << EOF
    import gimpfu

    def export(filename):
        img = pdb.gimp_file_load(filename, filename)
        new_name = filename.rsplit(".",1)[0] + ".xcf.png"
        layer = pdb.gimp_image_merge_visible_layers(img, 1)

        pdb.gimp_file_save(img, layer, new_name, new_name)
        pdb.gimp_image_delete(img)

    export('$i')

    pdb.gimp_quit(1)
    EOF
    echo "(gimp-quit 0)"
           fi

        elif [ -d "$i" ]; then  
        browsefolders "$i"
        fi
      done
    }
    browsefolders  "$directory"

I want to something that allow me export all what this opened without saving it in xcf (aka Export All)

Hi @bazza - I’m not sure what you are asking about - by “Export All” do you mean export all the individual layers in an xcf file, perhaps as individual pngs?

Already I resolved it, but it was to export all file in original format