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;
type
- The pixel type code, described below. This identifies the kind of data that will be sent
in
sendLine
. priv_data
- 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.
LWIMPAR_ASPECT
(float)- 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.
LWIMPAR_NUMCOLS
(int)- 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. LWIMPAR_PIXELWIDTH
(float)- 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.
LWIMPAR_FRAMESPERSECOND
(float)- The playback rate in frames per second.
LWIMPAR_BLACKPOINT
(float)- 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.
LWIMPAR_WHITEPOINT
(float)- The white point of the image.
LWIMPAR_GAMMA
(float)- The nonlinearity of the intensity encoding in the image.
The only parameter that loaders are required to set is the
LWIMPAR_NUMCOLS
value forLWIMTYP_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 tosendLine
. 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 theIMGF_REVERSE
flag in theirsendData
call). A scanline begins with the leftmost pixel. The structure of the pixel data depends on the pixel type. ReturnsIPSTAT_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 aLWIMPAR_NUMCOLS
parameter before callingsetMap
for the first time, butsetMap
may be called any time after that and before the firstsendLine
. The index identifies the color table entry, which is numbered from 0 tonumcolors-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.
LWIMTYP_RGB24
- Each scanline is an array of
unsigned char
inRGBRGB...
order. The corresponding typedef isLWPixelRGB24
. LWIMTYP_GREY8
- Each scanline is an array of
unsigned char
, with one byte per grayscale pixel. LWIMTYP_INDEX8
- Each scanline is an array of
unsigned char
, with one byte per pixel containing color map indexes. LWIMTYP_GREYFP
- Each scanline is an array of
float
, with one float per pixel. LWIMTYP_RGBFP
- Each scanline is an array of
float
inRGBRGB...
order. The corresponding typedef isLWPixelRGBFP
. LWIMTYP_RGBA32
- Each scanline is an array of
unsigned char
inRGBARGBA...
order and contains both RGB color and alpha channel values. The corresponding typedef isLWPixelRGBA32
. LWIMTYP_RGBAFP
- Each scanline is an array of
float
inRGBARGBA...
order and contains both RGB color and alpha channel values. The corresponding typedef isLWPixelRGBAFP
.
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.
Example
See the ancounter animation loader and the iff image loader and saver samples.