Blame IlmImfUtil/README

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