IFL(3)

NAME

IFL - overview of Image Format Library

SYNOPSIS

The Image Format Library (IFL) is a library for opening, reading, writing and creating image files in a format independent manner. IFL consists of a library developed in C++. An interface library for C programmers is also provided. IFL includes support for the FIT, GIF, JFIF, Photo CD, PNG, PPM, SGI, and TIFF file formats. It also supports reading and writing raw image data in a fairly flexible manner. It is designed to be very easy to use with a straight-forward mechanism support user-defined file formats.

MAN PAGES

For detailed information refer to the index of IFL man pages.

GETTING STARTED

To open a file and read it into memory you can write C++ code like the following:
    #include <ifl/iflFile.h>

    // open the file named by 'filename'

    iflStatus sts;
    iflFile* file = iflFile::open(filename, O_RDONLY, &sts);
    if (sts != iflOKAY) { /* handle the error */ }

    // read the entire image (just the first plane in z if image has depth)
    // into a buffer of unsiged chars

    iflSize dims;
    file->getDimensions(dims);
    unsigned char* data = new unsigned char[dims.x*dims.y*dims.c];
    iflConfig cfg(iflUChar, iflInterleaved);
    sts = file->getTile(0, 0, 0, dims.x, dims.y, 1, data, &cfg);
    if (sts != iflOKAY) { /* handle error */ }

    // close the file
    file->close();
or equivalently in C you could write:
    #include <ifl/iflCdefs.h>

    /* open the file named by 'filename' */

    iflStatus sts;
    iflFile *file;
    iflSize dims;
    unsigned char *data;
    iflConfig* cfg;
    file = iflFileOpen(filename, O_RDONLY, &sts);
    if (sts != iflOKAY) { /* handle the error */ }

    /*
        read the entire image (just the first plane in z if image
        has depth) into a buffer of unsiged chars
    */

    iflFileGetDimensions(file, &dims);
    data = (unsigned char*)malloc(dims.x*dims.y*dims.c);
    cfg = iflConfigCreate(iflUChar, iflInterleaved, 0, NULL, 0, 0);
    sts = iflFileGetTile(file, 0, 0, 0, dims.x, dims.y, 1, data, cfg);
    if (sts != iflOKAY) { /* handle error */ }

    /* close the file */
    iflFileClose(file, 0);
This simple example opens a file in any image format supported by IFL. The open function returns a pointer to an iflFile object which is IFL's abstraction for accessing image files. This object is described further below and in the iflFile(3) man page. The file object is then used to read the image's data it into memory. The iflConfig object is used to specify that that data should be read in the file's orientation, but with the pixels forced to unsigned char format and interleaved ordering.
Creating and writing an image file is just as simple:
    // create a one-channel, unsigned char image file
    iflSize dims(width, height, 1);
    iflFileConfig fc(&dims, iflUChar);
    iflStatus sts;
    iflFile* file = iflFile::create(filename, NULL, &fc, NULL, &sts);
    if (sts != iflOKAY) { /* handle the create error */ }

    // write a tile of data to it
    sts = file->setTile(0, 0, 0, width, height, 1, data);
    if (sts != iflOKAY) { /* handle error */ }

    // make sure the data gets written out to disk (or you can close here)
    sts = file->flush();
    if (sts != iflOKAY) { /* handle error */ }
or equivalently in C you could write:
    iflFile *file;
    iflFileConfig *fc;
    iflStatus sts;
    iflSize dims;

    /* create a one-channel, unsigned char image file */
    dims.x = width;
    dims.y = height;
    dims.z = 1;
    dims.c = 1;
    fc = iflFileConfigCreate(&dims, iflUChar, 0, 0, 0, 0, NULL);
    file = iflFileCreate(filename, NULL, fc, NULL, &sts);
    if (sts != iflOKAY) { /* handle the create error */ }

    /* write a tile of data to it */
    sts = iflFileSetTile(file, 0, 0, 0, width, height, 1, data, NULL);
    if (sts != iflOKAY) { /* handle error */ }

    /* make sure the data gets written out to disk (or you can close here) */
    sts = iflFileFlush(file);
    if (sts != iflOKAY) { /* handle error */ }

The code fragment above creates a one-channel file with the specified width and height and unsigned char data type. The rest of the attributes default to a format-preferred value. The file format will be inferred from the file name suffix. (It is also possible to explicitly give a format, and to inherit attributes from another iflFile.) This example then writes a tile of data to the file. It assumes the data buffer is the size and data type as the image created. It is also possible to do automatic conversion on the setTile() operation. Always be sure to flush or close the file when you are done writing data to it or the disk file may not be correctly written.

Be aware that IFL doesn't scale the data when converting data types, so you'd better be sure to pick a data type large enough to hold the range of data values in the image file; you can use the getScaleMinMax() and getStatMinMax() methods of iflFile to check the range of values. Also, IFL doesn't do any color model conversions; if you need that level of functionality you may want to use the ImageVision Library (IL) that is layered on top of IFL.

The following section on image attributes defines some of the terms just used such as orientation and dimension ordering.

Example source
If you install ifl_dev.sw.gifts, you can examine the source code provided in /usr/share/src/ifl/apps for more examples of using IFL.

IMAGE ATTRIBUTES

The Image Format Library characterizes images according to the common attributes described in the following sections.

Image size
Image have four dimensions: x, y, z, and c. The x and y dimensions are typically the width and height of the image although their interpretation is dependent upon the orientation of the image (described below).

The z dimension is generally interpreted as either depth for volume images or time for image sequences like movies; for 2D images the size of the z dimension is one.

The c dimension is the channel or component dimension; the size of the c dimension is the number of components in each pixel. The size of the c dimension must match the color model (see below) of the image. For example, an RGB image must have a c size of three and a greyscale image must have a c size of one. The only exception is the multi-spectral color model which can have any size for the c dimension. The image size is represented by the iflSize structure defined in <ifl/iflSize.h>.

Data type

The data type of an IFL image is the data type of the individual components of each pixel. All components of a pixel must have the same data type. The library supports nine data types: bit, signed byte, unsigned byte, signed short (16 bits), unsigned short, signed long (32 bits), unsigned long, float (32 bits) and double (64 bits). These data types are encoded by the iflDataType enum defined in <ifl/iflTypes.h>. Typically, if a format actually stores data in say 4 bits per component the IFL interface to the file will present the data as unsigned char with a scaling range of 0-15 (see below).

For a color palette image (see Color model section below), the image's data type refers to the type of its color index. The type of the color map values is determined by the file format and stored in an iflColormap.

Dimension order
This is the relative ordering of the image's x, y and channel dimensions. There are three orderings supported by IFL:

interleaved
channel dimension varies fastest, then x, then y, z last; thus all the components of each pixel are grouped together

sequential
x dimension varies fastest, then channels, then y, z last; all the components of a single row are grouped together (seldom used)

separate
x dimension varies fastest, then y, then channels, z last; the data is stored with each component isolated in a separate plane.

These orderings are encoded by the iflOrder enum defined in <ifl/iflTypes.h>.

Color model
The color model of an image defines the interpretation of the components of its pixels. There are 11 color models supported by IFL: greyscale, inverted greyscale (minimum is white, maximum is black), greyscale plus alpha, color palette (indicies mapped through a color map), RGB triplets, RGB plus alpha, HSV, CMY, CMYK, YCC and multi-spectral. There are also component reversed versions of RGB and RGBA but their use is deprecated (they are for backward compatibility with older SGI systems). These color models are encoded by the iflColorModel enum defined in <ifl/iflTypes.h>.

Orientation
The orientation of an image defines the spatial interpretation of its x and y dimensions. It is defined in terms of the location of the origin of the image (one of the four corners) and the direction of the x and y dimension (whether x runs horizontally or vertically). The combination of these two factors yields the eight orientations supported by IFL:
upper-left
origin in upper-left corner, x dimension is horizontal (y is vertical)

upper-right
origin in upper-right corner, x dimension is horizontal

lower-left
origin in lower-left corner, x dimension is horizontal

lower-right
origin in lower-right corner, x dimension is horizontal

left-upper
origin in upper-left corner, x dimension is vertical (y is horizontal)

right-upper
origin in upper-right corner, x dimension is vertical

right-lower
origin in lower-right corner, x dimension is vertical

left-lower
origin in lower-left corner, x dimension is vertical

These orientations are encoded by the iflOrientation enum defined in <ifl/iflTypes.h>.

Compression
The data in an image file may be compressed (depending on the format). Each format supported by IFL will automatically decompress the data read from the file when it is accessed through the iflFile methods getPage() and getTile(). Similarly, each format will compress data passed to the setPage() and setTile() methods before it is written out. The compressions are encoded in the iflCompression enum defined in <ifl/iflTypes.h>.

Page size
Some images are stored in a paged manner, others are stored in horizontal strips, others may not allow random access at all. Each file format encodes the underlying structure of its data with the page size attribute. The page size defines the dimensions of the natural chunks that an application can access with the getPage() and setPage() methods of iflFile. For arbitrarily paged images the x and y page size may be smaller than the image's x and y size, requiring multiple fixed-size pages to be tiled across the image. For strip oriented images the page width will be the same as the image width and the strips will be stacked vertically to cover the image. For images that can't support random access to pages of fixed size, the page size will be the same as the image size; i.e. there will only be one page.

The page size is defined by x, y, z and c dimensions as with the image size and follows the same rules with respect to the image's orientation. Data within each page is packed; there is no padding at the end of each line, even for bit data. Some file formats may indicate such padding by having the page size wider that the image size.

Display scaling range
Some image formats store a notion of the range of component values for purposes of scaling the data for display. This attribute may not be present in an image, in which case the application should assume the range is the full range of values than can be represented by the image's component data type. For images whose color model is iflRGBpalette this is the range of the entries on the color map, not the indices.

Statistical range
Some image formats store a notion of the statistical range of component values. This range should not be used for display scaling purposes, but may be useful in some image processing computations.

ICC profiles
Some image formats store an ICC (International Color Consortium) profile that can be used for color management.

THE IMAGE FILE ABSTRACTION

IFL's mechanism for accessing image files is through the iflFile class. This class is used as a base for deriving all of the file formats supported by IFL. It provides static methods to open existing image files and to create new ones. It provides methods to read and write image data, query all attributes and set some attributes. Format specific operations are supported through the getItem() and setItem() methods. Because of this base abstraction, IFL enables applications to be written that are image file format independent, yet still allows full access to unique attributes and capabilities of particular file formats. Refer to the iflFile(3) man page for more details.

THE IMAGE FORMAT ABSTRACTION

The Image Format Library uses the iflFormat object to represent a description of the capabilities of a particular image file format. The iflFormat class provides a number of functions that can be used to look up formats by format name, by a file's "magic" number, or by file name extension (e.g. ".gif"). There is also a method to iterate through all available formats ( useful for user interfaces, for instance, to generate a menu of available file formats).

The methods on an iflFormat allow the user to determine which values of the image attributes are supported by that format. There are also methods to query the preferred values of those attributes. See the iflFormat(3) man page for more details.

ADDING NEW IMAGE FILE FORMATS

To add support for a new image file format, you create a Dynamic Shared Object (DSO) or Dynamic Link Library (DLL) that implements the format, construct the appropriate database file for the new format and run /usr/lib/ifl/ifldbgen to generate the new ifl_database.

The DSO or DLL implements the file format I/O itself and the IFL interface abstraction. This is often done by using an already existing file format library and creating an IFL interface that makes calls into that library (see the iflJFIFFile.cxx and iflTIFFFile.cxx examples in ifl_dev.sw.gifts as examples of this). The IFL interface is implemented by deriving classes from iflFormat and iflFile for the format. Refer to the iflFile(3) and iflFormat(3) man pages for information on deriving your own classes.

IFL uses a text database file to determine what file formats are available for use with IFL. The database is normally located in the file /usr/lib/ifl/ifl_database but this may be overridden with the IFL_DATABASE environment variable.

The database is automatically generated by the /usr/lib/ifl/ifldbgen program when new file formats are added to the system. To add your own file formats you would typically create your own database file with your new entries and place that file in /usr/lib/ifl/database directory. Unlike previous versions of IFL, you should not include a "#include" directive for the /usr/lib/ifl/ifl_database in this new file. Doing so will result in conflict errors when ifldbgen is executed. After installing your new database in /usr/lib/ifl/database, simply run ifldbgen as root to generate the updated /usr/lib/ifl/ifl_database.

Building your DSO
There are two critical things that must be done when you build the DSO for your file format

  1. You must build your DSO using the C++ compiler so that the statically declared iflFormat derived object (see the iflFormat(3) man page for more info) will be automatically instantiated when the DSO is dynamically opened by IFL.
  2. The DSO version string must be 'sgi2.0' for IFL 1.1.1 to recognize it as a valid file format DSO.
An example command line to create a DSO for the TIFF format might be:
    % CC -mips3 -n32 -o libiflTIFF.so -set_version sgi2.0 -shared -all \
         iflTIFFFile.o -ltiff -lifl -lm
The DSO would then normally be installed in /usr/lib32 or some other directory that can be pointed to by the LD_LIBRARYN32_PATH environment variable. If you wish your file format to be useable with both -32 and -n32 executables then you will need to build the DSO for each object style and install them in the appropriate directories. See the ld(1) and rld(1) man pages for more details on DSO search paths.

Building your DLL
You must build your DLL using the Visual C++ 5.0 compiler.

Format of the database file
IFL database files are text files made up of a list of "format" declarations. A format declaration looks like this:

format formatname
match matchrule
description     "human-readable description of the format"
dso name of DSO file (only for Irix)
dll name of DLL file (only for WIN32)
access supported access modes
subsystem inst sub-system containing the DSO
suffixes comma-separated list of file name suffixes
The format declaration must come first and declares the name of an image file format. A format name is a one-word string and can be any legal C- language variable name. Each format declaration must have a unique name. All attribute declarations that follow a format declaration may appear in any order and apply to that format until the next format declaration is encountered in the database file. The match, description, dso and dll attribute declarations are required for every format.

The match declaration is a logical expression that determines whether a particular file is of the declared format. A match rule consists of a C-style logical expression made up of functions, comparison operators and parentheses. The following C-language operators may be used in a MATCH expression:
    &&  ||  ==  !=  <  >  <=  >= ( )
The == operator works for string comparisons as well as for numerical expressions

Numbers in a match expression may be expressed in decimal, octal, or hexadecimal notation. Octal numbers are expressed with a leading zero, such as 0732. Hexadecimal numbers are expressed with a leading `0x' such as 0xf03c. Decimal number are expressed normally, but may not have a leading zero.

The following expression functions are available:

char(n)
Returns the signed byte located at offset n in the file; range -128 to 127.

long(n)
Returns the signed long integer located at offset n in the file; range -2^31 to 2^31-1.

short(n)
Returns the signed short integer located at offset n in the file; range -32768 to 32767.

string(n,l)
Returns the l character long string located at offset n in the file.

uchar(n)
Returns the unsigned byte located at offset n in the file; range 0 to 255.

ulong(n)
Returns the unsigned long integer located at offset n in the file; range 0 to 2^32-1.

ushort(n)
Returns the unsigned short integer located at offset n in the file; range 0 to 65535.

Typical match declaration examples are:
    match short(0) == 0x01da || short(0) == 0xda01
or
    match long(0) == 0xffd8ffe0 && string(6,4) == "JFIF"
The description declaration is a human-readable description of the image format. Typical description declaration examples are:
    description "Kodak Photo CD image"
or
    description "TIFF image"
Descriptions should be relatively short as they are used as the labels for GUI components in some applications.

The dso declaration specifies that name of the DSO on Irix that contains the code to read and/or write the format. This name is typically specified without a directory path; instead, the environment variable, LD_LIBRARY_PATH, is used to locate the DSO at run-time.

The dll declaration specifies that name of the DLL on WIN32 that contains the code to read and/or write the format. This name is typically specified without a directory path; instead, the environment variable, PATH, is used to locate the DLL at run-time.

The optional access declaration determines what access modes are supported for the format. Possible values are: "readonly", "writeonly", or the default, "readwrite".

The optional subsystem declaration can be used to name the inst sub-system that should be installed to obtain support for the format. This name is included in error messages when the DSO or DLL for a format can not be opened.

The optional suffixes declaration lists a set of file name suffixes that will be used to determined what format a newly created file should use when the format is not specified in an iflFile::create() call. A typical suffixes rule would be:
    suffixes .jpg,.jpeg
Comments may be placed in a database file by using the '!' character. The comment extends to the end of the line.

Other files can be included in a database file using the "#include" directive. This directive uses the same syntax as the C preprocessor equivalent; the "#" must be the first character on a line and the filename must be enclosed in quotes or angle-brackets:
    #include "filename"
or
    #include <filename>
The filename must be an absolute pathname (i.e. it must start with a "/").

SEE ALSO

iflFile(3), iflFormat(3), iflSize(3), IFL(1), IL(1)