Adding Support for Custom (non-raw) Image Formats
Since version 1.6, ART provides the ability to add reading and writing support for additional (non-raw) image formats via a simple plugin mechanism.
Similarly to User Commands, the mechanism is based on interacting with external programs defined using configuration files, where an external handler is a program that converts to/from files in one of the supported formats (tiff, png or jpeg).
How to define custom image handlers
Image handlers are simple text files in the same syntax used by the arp
sidecar files (but with .txt
extension),
placed in the imageio
subdirectory directory of ART config folder (typically $HOME/.config/ART
on Linux and %LOCALAPPDATA%\ART
on Windows),
that must comply with the following specifications:
-
They must contain a single group of options, called
[ART ImageIO]
-
They must include the following mandatory definitions:
Extension
: the (case-insensitive) file extension of the image type handled.
-
and at least one of the following definitions:
-
ReadCommand
: the command used for loading images of the given type. The path can be either absolute or relative to the current directory; the command can also contain extra arguments (the input files will be appended to the list of arguments); The command will be called with the following arguments:input_file
: path to the image to readoutput_file
: path to the tiff file to generate.width_hint
: (optional), a hint about the desired image width. This can be used to optimize the reading, assuming that the image will be resized to be at mostwidth_hint
pixels wide. If absent or zero, then the image is needed at its maximum resolution. The command is free to ignore the hint and always return the fullsize image.height_hint
: (optional), analogous towidth_hint
above.
-
WriteCommand
: the command used for saving images of the given type. It will be called with the following arguments:input_file
: path to a 32-bit float tiff representation of the image to generate.output_file
: path to the file to generate.
-
-
Furthermore, they can also include the following optional definitions:
-
Format
: the format to use for the intermediate files used to communicate with ART. Possible values are:jpg
: JPEGpng
: 8-bit PNGpng16
: 16-bit PNGtiff
: 16-bit integer TIFFfloat
: 32-bit floating-point TIFF (default)
-
Label
: A short description of the image format to be used in the GUI for selecting the given output type. If absent, the uppercase version ofExtension
will be used. -
SaveFormat
: an alphanumeric unique identifier for the command used for save operations. By default, this is the same asExtension
. Having a separateSaveFormat
allows to define multiple savers for the same file extension, e.g. to support different saving modes. -
SaveProfile
: path to a (partial).arp
profile to be applied automatically before saving in the format being defined. This can be used e.g. to force a specific output profile when saving in the format being defined. If not absolute, the path will be interpreted relative to the directory containing the.txt
file.
-
NOTE: you should also add the appropriate extension to the preferences (in Preferences -> File Browser -> Parsed Extensions) in order for ART to show the pictures in the file browser.
Example
Here is a complete example of a handler for HEIC images that exploits libheif and Exiftool. The script works on Linux, and assumes that heif-thumbnailer
, heif-convert
, heif-enc
and exiftool
installed and in the $PATH
.
First, we define the following handler heic.txt
, putting in in $HOME/.config/ART/imageio
(create the directory if it doesn’t exist):
[ART ImageIO]
# the file extension of the type handled
Extension=heic
# communicate via 16-bit PNG files
Format=png16
# the command for loading
ReadCommand=./heif-io.sh load
# the command for saving
WriteCommand=./heif-io.sh save
# the label for the GUI
Label=HEIC (via libheif)
The bulk of the work is performed by the companion heif-io.sh
script, which will be put in the same directory ($HOME/.config/ART/imageio
):
#!/bin/sh
mode=$1
shift
if [ "$mode" = "load" ]; then
# loading: convert from the input to a png
# resize if hints are given
if [ "$4" != "" -a "$3" != "0" -a "$4" != "0" ]; then
heif-thumbnailer -s "$3x$4" "$1" "$2"
else
heif-convert -q 100 "$1" "$2"
fi
test -f "$2"
elif [ "$mode" = "save" ]; then
# saving: convert from 16-bit png to the output
heif-enc -o "$2" "$1"
if [ -f "$2" ]; then
# copy also the metadata with exiftool
exiftool -tagsFromFile "$1" -overwrite_original "$2"
fi
test -f "$2"
else
# unknown operating mode, exit with error
echo "Unknown operating mode \"$mode\"!"
exit 1
fi
Python Version
Here is the same example handler above written in Python, which might be more suitable for Windows users. It assumes that all the applications (Python, the libheif tools and exiftool) are in the %PATH%
(Windows binaries for libheif tools can be downloaded from here):
[ART ImageIO]
# the file extension of the type handled
Extension=heic
# communicate via 16-bit PNG files
Format=png16
# the command for loading
ReadCommand=python ./heif-io.py load
# the command for saving
WriteCommand=python ./heif-io.py save
# the label for the GUI
Label=HEIC (via libheif)
import os, subprocess, argparse
def getopts():
p = argparse.ArgumentParser()
p.add_argument("mode", choices=["load", "save"])
p.add_argument("input")
p.add_argument("output")
p.add_argument("maxwidth", type=int, nargs='?', default=0)
p.add_argument("maxheight", type=int, nargs='?', default=0)
return p.parse_args()
def main():
opts = getopts()
if opts.mode == "load":
if opts.maxwidth > 0 and opts.maxheight > 0:
subprocess.run([
"heif-thumbnailer",
"-s", "%sx%s" % (opts.maxwidth, opts.maxheight),
opts.input, opts.output], check=True)
else:
subprocess.run([
"heif-convert",
"-q", "100",
opts.input, opts.output], check=True)
else: # opts.mode == "save"
subprocess.run(["heif-enc", "-o", opts.output, opts.input], check=True)
subprocess.run(["exiftool", "-tagsFromFile", opts.input,
"-overwrite_original", opts.output])
if __name__ == "__main__":
main()
Another Example
Here is another example, using ImageMagick to perform the conversion. In this case, we can handle multiple custom formats with the same script, simply by defining multiple .txt
files with the proper parameter.
For example, here is one for WebP (let’s call it webp.txt
, and put it in $HOME/.config/imageio
):
[ART ImageIO]
Extension=webp
ReadCommand=./magick-io.sh load
WriteCommand=./magick-io.sh save
Label=WebP (via ImageMagick)
And here is another one for EXR (let’s call it exr.txt
):
[ART ImageIO]
Extension=exr
ReadCommand=./magick-io.sh load
WriteCommand=./magick-io.sh save
Label=EXR (via ImageMagick)
In both cases, we call the same magick-io.sh
script:
#!/bin/bash
mode=$1
shift
if [ "$mode" = "load" ]; then
# loading: convert from the input to a floating-point tiff file
# resize if hints are given
sz=""
if [ "$4" != "" -a "$3" != "0" -a "$4" != "0" ]; then
sz="-thumbnail $3x$4"
fi
magick convert "$1" $sz -colorspace sRGB -define quantum:format=floating-point -depth 32 -compress none "$2"
test -f "$2"
elif [ "$mode" = "save" ]; then
# saving: convert from floating-point tiff to the output
magick convert "$1" "$2"
if [ -f "$2" ]; then
# copy also the metadata with exiftool
exiftool -tagsFromFile "$1" -overwrite_original "$2"
fi
test -f "$2"
else
# unknown operating mode, exit with error
echo "Unknown operating mode \"$mode\"!"
exit 1
fi
(NOTE: this assumes that you have a version of ImageMagick that is properly configured to handle WebP and EXR, of course.)
A repository for custom image handlers
A collection of cross-platform image handlers is available in this repository.