OpenImageIO/oiio — pull request #437 by lgritz (2012-09-28 23:57:12+00:00)
Title: Deep images, OpenEXR 2.0

Part 2 of the changes to support OpenEXR 2.0: "deep" images.

(This patch also incorporates https://github.com/OpenImageIO/oiio/pull/435, which has not yet been reviewed. Do them separately or together, I don't care.)

"Deep" images are those that can store more than one sample per pixel. In fact, potentially different numbers for each pixel. OpenEXR 2.0 allows this. This breaks some of OIIO's assumptions in ways that required me to add some new API calls, and generally to make a much larger patch than most features we add. But conceptually, it's not all that tricky.

1. Alter the core APIs to support "deep" reading and writing:
* 'bool deep' field in ImageSpec, indicating a deep image.
* DeepData helper class for holding the sample counts, pointers, and data block, passed from/to the read_* and write_* deep functions.
* ImageInput: read_native_deep_scanlines and read_native_deep_tiles, which should be overloaded by any format reader supporting deep images, and read_native_deep_image (implemented in terms of the others).
* ImageOutput: write_deep_scanlines and write_deep_tiles, which should be overloaded by any format writer supporting deep images, and write_deep_image (implemented in terms of the others).
2. Very rudimentary ImageBuf support for deep data.
A DeepData field has been added internally to ImageBuf. Deep images loaded as ImageBufs will read directly into there, bypassing the traditional pixel storage (or ImageCache) used by non-deep ImageBufs. ImageBuf::Iterator (and ConstIterator) have been modified to be deep-safe, and to be able to access the deep data. You can also access through the ImageBuf directly. Quite a bit of other ImageBuf functionality doesn't work (and isn't meaningful) with deep data, beware.
3. A small number of ImageBufAlgo functions have been modified to work properly with deep ImageBuf's: computePixelStats(), compare().
4. OpenEXR reader/writer support for deep images. (Only if built against OpenEXR >= 2.0.)
5. Some basic utility support for deep images: iinfo and oiiotool can safely load deep images and print information about them, with -a, -v, --hash, --stats working. idiff works with deep images. Almost nothing else is expected to work with deep images at this time. Some more functionality will be added over time, but most image operations aren't very meaningful for deep images, they are kind of their own beast.

AND... like I said, this also was built upon, and thus incorporates, #435, to wit:

This set of changes works toward fully supporting OpenEXR 2.0's "multi-part" files (a partial implementation of multiple images in a single file).

Unfortunately, OpenEXR's library requires that the multi-part files declare the headers for all the parts upon opening the file. This is in contradiction to the way TIFF works, and therefore the way I had organized OIIO's APIs, to allow additional subimages to simply be appended one by one. So to accommodate this, I had to add a new API call to ImageOutput:

bool open (const std::string &name, int subimages, const ImageSpec *specs);

This lets you open with full information about the number and specification of subimages that you will be writing. A new supports("appendsubimage"), which returns true for TIFF, is used to indicate a format that can be output with the old appending method instead of requiring pre-declaration of the subimages.

I also changed oiiotool to use this new call in the appropriate way, and verified that all this stuff is working by adding a test that uses oiiotool to copy all the subimages of one of the new OpenEXR 2.0 test images. In the process, I changed the convention of the exr test images being stored in ../openexr-images-1.5.0 (which seems like a bad idea to have a specific version) to ../openexr-images. So beware that you may need to make a link on your end to ensure that the testsuite runs properly.

It was a much bigger pain to modify 'iconvert' to write multi-part OpenEXR files (or, more properly, to restructure it to use the new pre-declare flavor of the API), so I didn't do that at this time. That means that for now, please use oiiotool rather than iconvert if you anticipate needing to write multi-part OpenEXRs. I'm not sure if that's a serious limitation, if it is I can try to fix it, otherwise I'll get to it when I have a chance.

With this patch, OIIO will build with both OpenEXR 2.x as well as 1.x. Of course, if only 1.x is found at build time, the multi-part support won't be enabled. Also I've added top-level-Makefile OPENEXR_HOME=... and ILMBASE_HOME=... variables that let you override the location of those libraries.