Image I/O

This page describes the mechanism LightWave uses to move images to and from external files. The mechanism is defined in the lwimageio.h header file. The LWImageProtocol structure and the pixel type codes are used by the ImageLoader, ImageSaver, and AnimLoaderHandler classes.

The image protocol is used somewhat differently depending on which direction the image data is flowing. Loader plug-ins simply call the image protocol functions, but saver plug-ins provide these functions as callbacks that LightWave calls. Savers fill in the image protocol structure in their activation functions.

Because of the dual nature of the image protocol structure, there are places in the definitions where it's convenient to refer to the source and the destination of an image transfer. For loaders, the source is the plug-in and the destination is LightWave. For savers, the source is LightWave and the destination is the plug-in.

Image Protocol

Image data is transferred using calls to the functions in an LWImageProtocol. The lwimageio.h header file defines macros that loaders can use to slightly simplify calls to these functions. Both the functions and the corresponding macros are listed in the definitions.

   typedef struct st_LWImageProtocol {
      int   type;
      void *priv_data;
      int  (*done)     (void *, int);
      void (*setSize)  (void *, int w, int h);
      void (*setParam) (void *, LWImageParam, int, float);
      int  (*sendLine) (void *, int, const LWPixelID);
      void (*setMap)   (void *, int, const unsigned char[3]);
   } LWImageProtocol, *LWImageProtocolID;
The pixel type code, described below. This identifies the kind of data that will be sent in sendLine.
The first argument to the protocol functions. This is a pointer to data owned by the destination. Loaders just need to pass this along to the protocol functions (the macros hide this from you). Savers set this field to point to anything they like, typically a structure that holds data needed to process the save.
result = done( priv_data, error )
result = LWIP_DONE( protocol, error )
Called when there's no more image data to send. The incoming error code and the outgoing result can be any of the result codes defined below.
setSize( priv_data, width, height )
LWIP_SETSIZE( protocol, width, height )
Set the pixel dimensions of the image. The width and height are the number of pixels in a scanline and the number of scanlines, respectively. This is called before the first call to sendLine.
setParam( priv_data, paramid, intparam, floatparam )
LWIP_SETPARAM( protocol, paramid, intparam, floatparam )
Set other image parameters. In most cases, only one of the two parameter arguments will be used, while the other should be set to 0 by sources and ignored by destinations. The parameter ID can be one of the following.
The pixel aspect ratio, defined as width/height. This will most often be 1.0 (square pixels, the default), but D1 NTSC images, for example, use a pixel aspect of 0.9, meaning that each pixel is 0.9 times as wide as it is high.
The number of entries in the color table of an indexed-color image (an image of type LWIMTYP_INDEX8). Valid values are between 2 and 256.
The physical size of a pixel in millimeters. Savers can combine this with the pixel aspect to record a DPI setting for file formats that support it.
The playback rate in frames per second.
The black point of the image. The black point and white point define a nominal minimum and maximum intensity for an image. These are used, for example, when displaying the image on a device with limited dynamic range.
The white point of the image.
The nonlinearity of the intensity encoding in the image.

The only parameter that loaders are required to set is the LWIMPAR_NUMCOLS value for LWIMTYP_INDEX8 images.

result = sendLine( priv_data, y, scanline_pixels )
result = LWIP_SENDLINE( protocol, y, scanline_pixels )
Send one scanline from the image. Loaders must call setSize before the first call to sendLine. Scanlines are numbered from the top of the image, starting at 0. Loaders don't
have to send scanlines in a particular order, but savers will receive scanlines in top to bottom
order (or bottom to top if they specified the IMGF_REVERSE flag in their sendData call). A scanline begins with the leftmost pixel. The structure of the pixel data depends on the pixel type. Returns IPSTAT_OK or an error code.
setMap( priv_data, index, rgb )
LWIP_SETMAP( protocol, index, rgb )
Set the color of an entry in the color table of an indexed-color image. Loaders need to call setParam with a LWIMPAR_NUMCOLS parameter before calling setMap for the first time, but setMap may be called any time after that and before the first sendLine. The index identifies the color table entry, which is numbered from 0 to numcolors-1.

Pixel Data

The structure of the data in a scanline will vary, depending on the pixel type. Each scanline is an array of either unsigned bytes or floats. Bytes can contain any unsigned value between 0 and 255. The nominal range for float values is 0.0 to 1.0, but values outside that range may also appear.

Each pixel's data is contiguous--the scanline contains all of the channel values for the first pixel, followed by the values for the second, and so on. The lwimageio.h header file defines structures for many of the pixel types. You can use these to cast the void * argument in sendLine to a pointer of the appropriate type for the pixel data.

For each pixel type, the data is organized as follows.

Each scanline is an array of unsigned char in RGBRGB... order. The corresponding typedef is LWPixelRGB24.
Each scanline is an array of unsigned char, with one byte per grayscale pixel.
Each scanline is an array of unsigned char, with one byte per pixel containing color map indexes.
Each scanline is an array of float, with one float per pixel.
Each scanline is an array of float in RGBRGB... order. The corresponding typedef is LWPixelRGBFP.
Each scanline is an array of unsigned char in RGBARGBA... order and contains both RGB color and alpha channel values. The corresponding typedef is LWPixelRGBA32.
Each scanline is an array of float in RGBARGBA... order and contains both RGB color and alpha channel values. The corresponding typedef is LWPixelRGBAFP.

Error Handling

There are two ways that sources and destinations can notify each other of an error. The destination can return error codes from the sendLine and done functions, and the source can pass an error code to the destination's done function.

If a loader encounters an error while reading a file, it should stop sending data to LightWave and call done, setting the error argument to IPSTAT_FAILED. If a saver's done callback is called with a non-zero error argument, the saver should perform whatever cleanup it thinks is appropriate, which may include removing the partially saved file, and return the same error code from done.

If a saver encounters an error while writing a file, it should return IPSTAT_FAILED from its sendLine and done callbacks. Note that the first sendLine call is a saver's first opportunity to signal an error to LightWave, so its callbacks will continue to be called after the error is detected and until sendLine is called. It's a good idea for savers to include an error field in their priv_data so that their callbacks can respond appropriately until LightWave can be told that something's gone wrong.


See the ancounter animation loader and the iff image loader and saver samples.