How to convert XCF to PNG using GIMP from the comm

2019-03-09 22:13发布

问题:

As part of my build process I need to convert a number of XCF (GIMP's native format) images into PNG format. I'm sure this should be possible using GIMP's batch mode, but I have forgotten all of the script-fu I used to know.

My input images have multiple layers, so I need the batch mode equivalent of "merge visible layers" followed by "save as PNG". Also note that I can't install anything in ~/.gimp*/scripts/ — I need a self-contained command-line, or a way to install scripts in my source tree.

Note that while this is similar to this question, I have the additional constraint that I need this to be done using GIMP. I tried the current version of ImageMagick and it mangles my test images.

回答1:

There are a few ways to go through this - my preferred method is always developing a GIMP-Python plug-in. Script-fu uses GIMP's built-in scheme implementation, which is extremely poor in handling I/O (such as listing files in a directory) - a task which is absolutely trivial in Python.

SO, since you said you don't want to save new scripts (you could do it because you can add new plug-in and scripts directories on edit->preferences->folder options so that you don't need to write on ~/.gimp*/plugins/)

Anyway, you can open the python console under filters, and paste this snippet in the interactive prompt.

import gimpfu
def convert(filename):
    img = pdb.gimp_file_load(filename, filename)
    new_name = filename.rsplit(".",1)[0] + ".png"
    layer = pdb.gimp_image_merge_visible_layers(img, gimpfu.CLIP_TO_IMAGE)

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

This small function will open any image, passed as a file path, flatten it, and save it as a png with the default settings, in the same directory.

Following the function, you can simply type:

from glob import glob
for filename in glob("*.xcf"):
    convert(filename)

On the interactive prompt to convert all .xcf files on the current directory to .png

(If you don't have gimp-python installed, it may be a separate package on your linux distribution, just install it using your favorite tool - for those under windows, and gimp-2.6, the instructions on this page have have to be followed - it should become easier on gimp 2.8)

Another way, altogether, applies if your images are sequentially numbered in their filenames, such as myimage_001.xcf, mymage_002.xcf and so on. If they are so arranged you could install GIMP-GAP (gimp animation package) which allows one to apply any filters or actions in such an image sequence.



回答2:

Before jsbueno posted his answer I had also tried asking on the #gimp IRC channel. I was directed to this thread on Gimptalk which contains the following code:

gimp -n -i -b - <<EOF
(let* ( (file's (cadr (file-glob "*.xcf" 1))) (filename "") (image 0) (layer 0) )
  (while (pair? file's) 
    (set! image (car (gimp-file-load RUN-NONINTERACTIVE (car file's) (car file's))))
    (set! layer (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE)))
    (set! filename (string-append (substring (car file's) 0 (- (string-length (car file's)) 4)) ".png"))
    (gimp-file-save RUN-NONINTERACTIVE image layer filename filename)
    (gimp-image-delete image)
    (set! file's (cdr file's))
    )
  (gimp-quit 0)
  )
EOF

This scriptfu globs for xcf files, and then for each file it loads the file, merges the visible layers, saves the result as a PNG, and "unloads" the image. Finally, it quits GIMP. The glob approach is used to avoid starting up GIMP for each image. It also side-steps the issue of getting parameters from the shell into gimp.

I'm posting this answer just in case someone needs a way to do this without the use of GIMP-Python (perhaps because it isn't installed).



回答3:

Here is my solution utilizing GIMP, GIMP's python-fu and bash. Note that GIMP's python-fu can only be run under a gimp process, not under plain python.

#!/bin/bash
set -e

while getopts df: OPTION "$@"; do
    case $OPTION in
    d)
        set -x
        ;;
    f)
        XCFFILE=${OPTARG}
        ;;
    esac
done

if [[ -z "$XCFFILE" ]]; then
    echo "usage: `basename $0` [-d] -f <xcfFile>"
    exit 1
fi

# Start gimp with python-fu batch-interpreter
gimp -i --batch-interpreter=python-fu-eval -b - << EOF
import gimpfu

def convert(filename):
    img = pdb.gimp_file_load(filename, filename)
    new_name = filename.rsplit(".",1)[0] + ".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)

convert('${XCFFILE}')

pdb.gimp_quit(1)
EOF


回答4:

Use xcftools

It's possible that this tool wasn't available (or in any case widely known) at the time this question was originally asked, but the xcf2png terminal command from the xcftools package does exactly what you ask and is very good. I use it for my thesis scripts and would be my go-to choice for this question.

From the documentation:

This is a set of fast command-line tools for extracting information from the Gimp's native file format XCF.
The tools are designed to allow efficient use of layered XCF files as sources in a build system that use 'make' and similar tools to manage automatic processing of the graphics.
These tools work independently of the Gimp engine and do not require the Gimp to even be installed.

"xcf2png" converts XCF files to PNG format, flattening layers if necessary. Transparency information can be kept in the image, or a background color can be specified on the command line.


(PS. I spotted xcftools mentioned in the comments just after I decided to post an answer about it, but I'm posting anyway as that comment was easy to miss (I saw it because I specifically checked for it) and I think xcftools deserves a proper answer's slot, as it really is the most appropriate answer at this point in time.)



回答5:

I know this is not strictly the correct answer but seeing as a I got directed here while searching.

I modified the example code here to create a workable plugin

http://registry.gimp.org/node/28124

There is a bit of code from another answer on this page

#!/usr/bin/env python

from gimpfu import *
import os



def batch_convert_xcf_to_png(img, layer, inputFolder, outputFolder):
    ''' Convert the xcf images in a directory to png.

    Parameters:
    img : image The current image (unused).
    layer : layer The layer of the image that is selected (unused).
    inputFolder : string The folder of the images that must be modified.
    outputFolder : string The folder in which save the modified images.
    '''
    # Iterate the folder
    for file in os.listdir(inputFolder):
        try:
            # Build the full file paths.
            inputPath = inputFolder + "\\" + file

            new_name = file.rsplit(".",1)[0] + ".png"
            outputPath = outputFolder + "\\" + new_name

            # Open the file if is a XCF image.
            image = None
            if(file.lower().endswith(('.xcf'))):
                image = pdb.gimp_xcf_load(1,inputPath, inputPath)


            # Verify if the file is an image.
            if(image != None):

                #layer = pdb.gimp_image_merge_visible_layers(image, gimpfu.CLIP_TO_IMAGE)
                layer = pdb.gimp_image_merge_visible_layers(image, 1)

                # Save the image.
                pdb.file_png_save(image, image.layers[0], outputPath, outputPath, 0, 9, 0, 0, 0, 0, 0)

        except Exception as err:
            gimp.message("Unexpected error: " + str(err))   




'''                
    img = pdb.gimp_file_load(filename, filename)
    new_name = filename.rsplit(".",1)[0] + ".png"
    layer = pdb.gimp_image_merge_visible_layers(img, gimpfu.CLIP_TO_IMAGE)

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


register(
        "batch_convert_xcf_to_png",
        "convert chris",
        "convert ",
        "Chris O'Halloran",
        "Chris O'Halloran",
        "2014",
        "<Image>/Filters/Test/Batch batch_convert_xcf_to_png",
        "*",
        [
            (PF_DIRNAME, "inputFolder", "Input directory", ""),
            (PF_DIRNAME, "outputFolder", "Output directory", ""),            
        ],
        [],
        batch_convert_xcf_to_png)



main()