Blame IlmImfUtil/README

Packit c2c737
The IlmImfUtil Library
Packit c2c737
----------------------
Packit c2c737
Packit c2c737
The IlmImfUtil library implements an in-memory image data structure, as
Packit c2c737
well as simple function calls for saving images in OpenEXR files, and for
Packit c2c737
constructing images from the contents of existing OpenEXR files.
Packit c2c737
Packit c2c737
The OpenEXR file format has a fairly large number of options for on-file
Packit c2c737
image storage, including arbitrary sets of channels, per-channel pixel
Packit c2c737
format selection, sub-sampled channels, multi-resolution images, deep
Packit c2c737
images, or storing images as tiles or scan lines.  While reading a simple
Packit c2c737
RGBA image does not require a lot of code, reading the contents of an
Packit c2c737
arbitrary OpenEXR file, and representing those contents in main memory
Packit c2c737
is not trivial.  The IlmImfUtil library simplifies those tasks.
Packit c2c737
Packit c2c737
Image, Image Level, Image Channel
Packit c2c737
---------------------------------
Packit c2c737
Packit c2c737
An image (class Image) is a container for a set of image levels (class
Packit c2c737
ImageLevel), and an image level is a container for a set of image channels
Packit c2c737
(class ImageChannel).  An image channel contains an array of pixel values.
Packit c2c737
Packit c2c737
For example:
Packit c2c737
Packit c2c737
    image --+-- level 0,0 --+-- channel "R" --- pixel data
Packit c2c737
            |               |
Packit c2c737
            |               +-- channel "G" --- pixel data
Packit c2c737
            |               |
Packit c2c737
            |               +-- channel "B" --- pixel data
Packit c2c737
            |
Packit c2c737
            +-- level 1,1 --+-- channel "R" --- pixel data
Packit c2c737
            |               |
Packit c2c737
            |               +-- channel "G" --- pixel data
Packit c2c737
            |               |
Packit c2c737
            |               +-- channel "B" --- pixel data
Packit c2c737
            |
Packit c2c737
            +-- level 2,2 --+-- channel "R" --- pixel data
Packit c2c737
                            |
Packit c2c737
                            +-- channel "G" --- pixel data
Packit c2c737
                            |
Packit c2c737
                            +-- channel "B" --- pixel data
Packit c2c737
Packit c2c737
An image has a level mode (enum LevelMode), which can be ONE_LEVEL,
Packit c2c737
MIPMAP_LEVELS or RIPMAP_LEVELS.  A ONE_LEVEL image contains only a single
Packit c2c737
level, but a multi-resolution image, that is, one with level mode set to
Packit c2c737
MIPMAP_LEVELS or RIPMAP_LEVELS, contains multiple levels.  The levels are
Packit c2c737
analogous to the levels in an OpenEXR file, as described in the "Technical
Packit c2c737
Introduction to OpenEXR" document.
Packit c2c737
Packit c2c737
Levels are indexed by a pairs of level numbers.  Level (0,0) contains the
Packit c2c737
highest-resolution version of the image; level (lx,ly) contains an image
Packit c2c737
whose resolution is reduced in x and y by a factor of 2^lx and 2^ly
Packit c2c737
respectively.  The level has a data window that indicates the range of
Packit c2c737
x and y for which pixel data are stored in the level.
Packit c2c737
Packit c2c737
All levels in an image have the same set of image channels.
Packit c2c737
Packit c2c737
An image channel has a name (e.g. "R", "Z", or "xVelocity"), a type (HALF,
Packit c2c737
FLOAT or UINT) and x and y sampling rates.  A channel stores samples for
Packit c2c737
a pixel if the pixel is inside the data window of the level to which the
Packit c2c737
channel belongs, and the x and y coordinates of the pixel are divisible by
Packit c2c737
the x and y sampling rates of the channel.
Packit c2c737
Packit c2c737
An image can be either flat or deep.  In a flat image each channel in each
Packit c2c737
level stores at most one value per pixel.  In a deep image each channel in
Packit c2c737
each level stores an arbitrary number of values per pixel.  As an exception,
Packit c2c737
each level of a deep image has a sample count channel with a single value
Packit c2c737
per pixel; this value determines how many values each of the other channels
Packit c2c737
in the same level has at the same pixel location.
Packit c2c737
Packit c2c737
The Image, ImageLevel and ImageChannel classes are abstact base classes.
Packit c2c737
Two sets of classes, one for flat images and one for deep images, are
Packit c2c737
derived from the base classes.  The FlatImageChannel and DeepImageChannel
Packit c2c737
classes, derived from ImageChannel, are themselves base classes for the
Packit c2c737
templates TypedFlatImageChannel<T> and TypedDeepImageChannel<T>:
Packit c2c737
Packit c2c737
    Image -> FlatImage
Packit c2c737
          -> DeepImage
Packit c2c737
Packit c2c737
    ImageLevel -> FlatImageLevel
Packit c2c737
               -> DeepImageLevel
Packit c2c737
Packit c2c737
Packit c2c737
    ImageChannel -> FlatImageChannel -> TypedFlatImageChannel<T>
Packit c2c737
                 -> DeepImageChannel -> TypedDeepImageChannel<T>
Packit c2c737
                 -> SampleCountChannel
Packit c2c737
Packit c2c737
Channel objects of type TypedFlatImageChannel<T> and TypedDeepImageChannel<T> 
Packit c2c737
contain pixel values of type T, where T is either half, float or unsigned int.
Packit c2c737
For convenience, the following typedefs are provided:
Packit c2c737
Packit c2c737
    typedef TypedFlatImageChannel<half>         FlatHalfChannel;
Packit c2c737
    typedef TypedFlatImageChannel<float>        FlatFloatChannel;
Packit c2c737
    typedef TypedFlatImageChannel<unsigned int> FlatUIntChannel;
Packit c2c737
Packit c2c737
    typedef TypedDeepImageChannel<half>         DeepHalfChannel;
Packit c2c737
    typedef TypedDeepImageChannel<float>        DeepFloatChannel;
Packit c2c737
    typedef TypedDeepImageChannel<unsigned int> DeepUIntChannel;
Packit c2c737
Packit c2c737
Packit c2c737
File I/O
Packit c2c737
--------
Packit c2c737
Packit c2c737
An Image object can be saved in an OpenEXR file with a single function call:
Packit c2c737
Packit c2c737
    saveImage ("foo.exr", myImage);
Packit c2c737
Packit c2c737
The saveImage() function automatically creates a flat or a deep image file,
Packit c2c737
depending on the type of the image.  All channels and all image levels will
Packit c2c737
be saved in the file.
Packit c2c737
Packit c2c737
Optionally an OpenEXR Header object can be passed to the saveImage() function;
Packit c2c737
this allows application code save custom attributes in the file, and to control
Packit c2c737
how the file will be compressed:
Packit c2c737
Packit c2c737
    Header myHeader;
Packit c2c737
    myHeader.compression() = PIZ_COMPRESSION;
Packit c2c737
    myHeader.pixelAspectRatio() = 1.5;
Packit c2c737
Packit c2c737
    saveImage ("foo.exr", myHeader, myImage);
Packit c2c737
Packit c2c737
Loading an image from an OpenEXR file also requires only one function call,
Packit c2c737
either
Packit c2c737
Packit c2c737
    Image* myImage = loadImage ("foo.exr");
Packit c2c737
Packit c2c737
or
Packit c2c737
Packit c2c737
    Header myHeader;
Packit c2c737
    Image* myImage = loadImage ("foo.exr", myHeader);
Packit c2c737
Packit c2c737
The application owns the image that is returned by the loadImage() call.
Packit c2c737
It is the application's responsibility to delete the Image object.
Packit c2c737
Packit c2c737
The IlmImfUtil library also provides versions of the saveImage() and
Packit c2c737
loadImage() functions that work only on flat images or only on deep images:
Packit c2c737
Packit c2c737
    saveFlatImage()
Packit c2c737
    saveFlatScanLineImage()
Packit c2c737
    saveFlatTiledImage()
Packit c2c737
    saveDeepImage()
Packit c2c737
    saveDeepScanLineImage()
Packit c2c737
    saveDeepTiledImage()
Packit c2c737
Packit c2c737
For details the the ImfFlatImageIO.h and ImfDeepImageIO.h header files.
Packit c2c737
Packit c2c737
Packit c2c737
Manipulating Images in Memory
Packit c2c737
-----------------------------
Packit c2c737
Packit c2c737
Creating a mip-mapped flat image with two channels:
Packit c2c737
Packit c2c737
    FlatImage fimg (Box2i (V2i (0, 0), V2i (255, 255)),    // data window
Packit c2c737
                    MIPMAP_LEVELS);                        // level mode
Packit c2c737
Packit c2c737
    fimg.insertChannel ("R", HALF);
Packit c2c737
    fimg.insertChannel ("Z", FLOAT);
Packit c2c737
Packit c2c737
Creating a single-level deep image:
Packit c2c737
Packit c2c737
    DeepImage dimg (Box2i (V2i (0, 0), V2i (255, 255)),    // data window
Packit c2c737
                    ONE_LEVEL);                            // level mode
Packit c2c737
Packit c2c737
    dimg.insertChannel ("R", HALF);
Packit c2c737
    dimg.insertChannel ("Z", FLOAT);
Packit c2c737
Packit c2c737
Reading and writing pixels in level (2,2) of the mip-mapped flat image
Packit c2c737
(note: a mip-mapped image contains only levels where the x and y level
Packit c2c737
numbers are equal.  For convenience, mip-map levels can be addressed
Packit c2c737
using a single level number):
Packit c2c737
Packit c2c737
    FlatImageLevel &level = fimg.level (2);
Packit c2c737
    FlatHalfChannel &R = level.typedChannel<half> ("R);
Packit c2c737
Packit c2c737
    half r1 = R.at (20, 15);    // read pixel (20,15), with bounds checking
Packit c2c737
                                // (exception for access outside data window)
Packit c2c737
Packit c2c737
    half r2 = R (17, 4);        // read pixel (17,4) without bounds checking
Packit c2c737
                                // faster, but crashes for access outside
Packit c2c737
                                // data window
Packit c2c737
Packit c2c737
    R.at (20, 15) = 2 * r1;     // change pixel value, with and
Packit c2c737
    R (17, 4) = 2 * r2;         // without bounds checking
Packit c2c737
Packit c2c737
Reading and writing pixels in the single-level deep image:
Packit c2c737
Packit c2c737
    DeepImageLevel &level = dimg.level();
Packit c2c737
    DeepHalfChannel &R = level.typedChannel<half> ("R);
Packit c2c737
Packit c2c737
    // with bounds checking
Packit c2c737
Packit c2c737
    unsigned int n1 = R.sampleCounts().at (20, 15);
Packit c2c737
    half r1;
Packit c2c737
Packit c2c737
    if (n1 > 0)
Packit c2c737
        r1 = R.at(20, 15)[n1 - 1];  // read the last sample in pixel (20,15)
Packit c2c737
Packit c2c737
    // without bounds checking
Packit c2c737
Packit c2c737
    unsigned int n2 = R.sampleCounts()(20, 15);
Packit c2c737
    half r2;
Packit c2c737
Packit c2c737
    if (n > 0)
Packit c2c737
        r2 = R(17, 4)[n2 - 1];     // read the last sample in pixel (17,4)
Packit c2c737
Packit c2c737
    // change the value of an existing sample
Packit c2c737
Packit c2c737
    if (n1 > 0)
Packit c2c737
        R(20,15)[n1 - 1] = r1 * 2;
Packit c2c737
Packit c2c737
    // append a new sample to a pixel and set the sample to 3.0
Packit c2c737
Packit c2c737
    R.sampleCounts().set (20, 15, n1 + 1);
Packit c2c737
    R.(20, 15)[n1] = 3.0;
Packit c2c737
Packit c2c737
In addition to functions for reading and writing individual pixels, there
Packit c2c737
are functions for accessing a whole row of pixels with a single function
Packit c2c737
call.  For details see the ImfFlatImageChannel.h, ImfDeepImageChannel.h
Packit c2c737
and ImfSampleCountChannel.h header files in the IlmImf library:
Packit c2c737
Packit c2c737
    T*                   TypedFlatImageChannel<T>::row (int r);
Packit c2c737
    const T*             TypedFlatImageChannel<T>::row (int r) const;
Packit c2c737
Packit c2c737
    T * const *          TypedDeepImageChannel<T>::row (int r);
Packit c2c737
    const T * const *    TypedDeepImageChannel<T>::row (int r) const;
Packit c2c737
    const unsigned int * SampleCountChannel::row (int r) const;
Packit c2c737
Packit c2c737
To change the number of samples in all pixels in one row of a deep image
Packit c2c737
level, use:
Packit c2c737
Packit c2c737
    void SampleCountChannel::set (int r, unsigned int newNumSamples[]);
Packit c2c737
Packit c2c737
Use an Edit object to temporarily make all sample counts in a deep image
Packit c2c737
level editable:
Packit c2c737
Packit c2c737
    class SampleCountChannel::Edit;
Packit c2c737
Packit c2c737
Miscellaneous Functions:
Packit c2c737
------------------------
Packit c2c737
Packit c2c737
Change the data window and the level mode of an image (pixel data are not
Packit c2c737
preserved across the call):
Packit c2c737
Packit c2c737
    void Image::resize (const Box2i &dataWindow, LevelMode levelMode);
Packit c2c737
Packit c2c737
Shift the data window in x and y; shift the pixels along with the data window:
Packit c2c737
Packit c2c737
    void Image::shiftPixels (int dx, int dy);
Packit c2c737
Packit c2c737
Erase a channel, rename a channel, rename multiple channels at the same time:
Packit c2c737
Packit c2c737
    void Image::eraseChannel (const string &name);
Packit c2c737
    void Image::renameChannel (const string &oldName, const string &newName);
Packit c2c737
    void Image::renameChannels (const RenamingMap &oldToNewNames);
Packit c2c737
Packit c2c737
Missing Functionality:
Packit c2c737
----------------------
Packit c2c737
Packit c2c737
At this point, the IlmImfUtil library cannot read or write multi-part
Packit c2c737
files.  A future version of the library should probably define a new class
Packit c2c737
MultiPartImage that contains a set of regular images.  The library should
Packit c2c737
also define corresponding loadMultiPartImage() and saveMultiPartImage()
Packit c2c737
functions.
Packit c2c737
Packit c2c737
Sample Code
Packit c2c737
-----------
Packit c2c737
Packit c2c737
See the exrsave, exrmakescanlines, exrclip utilities.
Packit c2c737
Packit c2c737