HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Adding a New Image Format Using the HDK

Table Of Contents

Extending the Image Library

It is possible to create a DSO/DLL which extends the image formats recognized by Houdini. There are two classes that need to be written to implement a new image format. The sub class of the IMG_Format class describes the new format, while the sub class of the IMG_File class performs the I/O for the new format.

Defining a new format

The IMG_Format class specifies information about the format of the image. For example, whether the first scanline is at the bottom of the image or the top, or whether it's possible to randomly seek to a scanline. The format is also responsible for creating the IMG_File class to read/write the image. Only one IMG_Format is typically instantiated, while and IMG_File is allocated for each read/write of the image. The methods of interest for this class are:

Method Description
IMG_Format::createFile

This method is called to create the IMG_File class to read/write the image

IMG_Format::getFormatName

This method should return a simple string describing the image format. Typically, this name should not contain spaces (since it may be used as a command line option to some programs). For example "PRISMS" or "Wavefront".

IMG_Format::getFormatDescription

Provides a complete description of the format. For example, the TIFF description includes the version number of the TIFF library and the copyright.

IMG_Format::checkExtension

This method should check the filename passed to it to see if the extension on the file matches the expected extension of the format. There is a convenience method provided (matchExtensions) which can be used to check the filename for you. For example:

static const char *extensions = { ".pic", ".si", 0 }
return matchExtensions(filename, extensions);

IMG_Format::checkMagic

On cases where file extension matching fails (or is not available), the IMG library provides a mechanism for checking magic numbers. The first four bytes of a file are read and passed into the checkMagic() method. This is the only mechanism available for magic number checking.

IMG_Format::checkDevice

This method provides a higher priority check than the simple extension match. For example, the abekas driver checks for things like a60:filename. The filename may match a different format (i.e. the extension might be .rgb). So to this method allows you to do a high priority check on the filename to possibly override the implicit extension checking mechanism. This method should be used with care.

IMG_Format::getAllowedTypes IMG_Format::getMaxImages IMG_Format::getMaxResolution

These methods are used to validate the creation of the given file. If the format only supports a single image, the maximum images should be 1. If the resolution of the image is stored in a signed short, then the maximum resolution should be set to 32767 (see /usr/include/limits.h). The allowed types specifies the allowed types of data (i.e. char, short, int).

IMG_Format::isReadRandomAccess() IMG_Format::isWriteRandomAccess()

These methods should return 1 if it's possible to seek to a random scanline. For example, Wavefront RLA images can be stored with any scanline order, while PRISMS images cannot. Cineon images can be read in any scanline order (since there's no compression on the file), however, they must be written in the given order.

IMG_Format::isTopFirst

Should return 1 if the first scanline of the image is at the top of the image (i.e. JPEG), or 0 if the first scanline is at the bottom of the image (i.e. PRISMS).

IMG_Format::allowStreams

Some formats (i.e. TIFF/JPEG) require you to use the stdio.h FILE descriptors to read/write images. In this case, C++ streams cannot be used. This method should return 0 in these cases. If this method returns 0, then only the openFile method will be called in the IMG_File class.

IMG_Format::allowStdio

The IMG library can pass images around using stdin/stdout. Any format which seeks through the file (i.e. Wavefront/SGI) cannot be read or written using stdin or stdout. This method should return 0 in this case. The first image format which supports stdio found in the index file will be used as the format to pass images on stdin/stdout. Typically this is PRISMS format.

IMG_Format::getTags IMG_Format::getTagValues

These methods provide a mechanism to set parameters when creating an image. These tags can be used to specify the compression type of the image, or other information which is specific to the format.

IMG_Format::newIMGFormat This is a global function defined in the .so file (not a method of IMG_Format. It should simply construct an instance of the sub-class defined. For example:
void newIMGFormat(void *)
{
new IMG_MyFormat();
}

Writing the File I/O

The IMG_File base class is used for reading/writing a specific image format. At a minimum, there are only 5 methods needed. The methods of interest are:

Method

Description

IMG_File::open IMG_File::openFile

These methods are called when opening a file for reading. When the open method is called, the member data myIS will be a pointer to a valid istream class. This data should be used to read the image in. If the file can't handle C++ streams, then the openFile() method will be called. This method is passed the filename and it's the sub-class responsibility to open the file however it should. By default, this method will open an ifstream and assign it to the myIS member data. It then calls the open method. The open method typically reads the image header and is responsible for setting the stats to describe the file. The stats.

myStat.setResolution(header.width, header.height);
myStat.setColorModel(IMG_RGBA);
myStat.setDataType(IMG_UCHAR);
myStat.setImageCount(1);
return 1; // Now, we're ready to read scanlines

IMG_File::readScanline

This method is called once for each scanline in the image. Unless the format supports random access for reading, the scanline passed in will be 0 on the first call and myStat.getYres()-1 on the last call. For example, if reading JPEG images, the scanline will be 0, will represent the first scanline - at the top of the image. When reading PRISMS, 0 will represent the scanline at the bottom of the image. When reading Wavefront, 0 represents the scanline bottom of the image.

IMG_File::create IMG_File::createFile

This method is called to open an image for writing. These methods are passed an IMG_Stat class containing the statistics for the image. The resolution is specified in the stat class. As well, the information about scanlines data is also specified. If the format is incapable of supporting either the data type or the color model (i.e. JPEG only supports 8 bit unsigned char data and RGB information), it is possible to build a scanline data translator so that the writeScanline method gets the data in the format you expect. For example, with the JPEG format,

myStat = stat;
if (myStat.getColorModel() != IMG_RGB ||
myStat.getDataType() != IMG_UCHAR)
{
if (!setTranslator(IMG_UCHAR, IMG_RGB))
return 0; // Failure to open
}

IMG_File::writeScanline

The scanline passed into writeScanline has the same meaning as the scanline passed into readScanline. The writeScanline method is also passed in a pointer to void data. This represents the raw data for the scanline. This method is responsible for writing the data out. This is the place where compression or filtering of data should occur.

IMG_File::closeFile

This method is responsible for flushing any buffers, releasing allocated memory, closing any files. If the myIS/myOS streams are closed, they should be set to null pointers. It is possible in odd cases, that this method is called more than once, so when memory is released, the pointer to the memory should be set to a null pointer to ensure that the memory is not released twice. The same is true of file pointers etc.

Constructor

The constructor typically initializes all the member data

Destructor The destructor should contain simply one line of code.
IMG_MyFormat::~IMG_MyFormat() { close(); }
The close method is responsible for doing all the freeing of memory and closing of file descriptors. This is called from within the non-virtual close() method.

Example Source

A simple example of an image file extension can be found in IMG/IMG_Raw.C and IMG/IMG_Raw.h