### 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 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. `LWIMTYP_RGB24` Each scanline is an array of `unsigned char` in `RGBRGB...` order. The corresponding typedef is `LWPixelRGB24`. `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` in `RGBRGB...` order. The corresponding typedef is `LWPixelRGBFP`. `LWIMTYP_RGBA32` 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`. `LWIMTYP_RGBAFP` 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. Example See the ancounter animation loader and the iff image loader and saver samples.