Metadata in Deep Texture Files

Metadata in Deep Texture Files

October, 2012

1   Introduction

PRMan 17.0 extends the deep texture format to support arbitrary metadata. These are lists of token/value pairs that may be attached to individual images within the file or attached to the entire file.


2   Access via librix

The new DeepMetadata class in the RixDeepTexture API provides access to a set of metadata fields. Call the GetMetadata() method on either a DeepFile or DeepImage object to get a pointer to an instance for accessing the associated metadata. Note that if the open file was produced using an older version of the deep texture APIs it may not support metadata. In that case, a null pointer will be returned.

To add a field, call the Set() method. Here's a simple example by which one might open a file and add chromaticity information to a deep compositing image:

RixDeepTexture::DeepFile *file;
dtex->OpenFile("image.dtx", "rb+", cache, &file);
RixDeepTexture::DeepImage *image;
file->GetImageByIndex(0, &image);
RixDeepTexture::DeepMetadata *meta = image->GetMetadata();
if (meta) {
    float chroma[] = {0.64f, 0.33f,
                      0.30f, 0.60f,
                      0.15f, 0.06f,
                      0.3127f, 0.3290f};
    meta->Set("float[8] chroma", chroma);
}
file->Close();

Metadata fields are represented as token/value pairs. The token is a string specifying the type and name of the field in the usual RenderMan style. Supported types are: float, int, point, color, vector, normal, hpoint, matrix, and string.

The associated data to write is given by the value pointer. In the case of string data, this should point to a set of char const * pointers that point to the strings themselves (i.e., argv style).

To remove a field, use the Set() method with a null pointer for the value.

Retrieving the metadata is fairly straightforward. The GetByName() method takes an unadorned name and sets a pair of token and value pointers on success. If there's no field with the given name, it returns k_ErrNOMETADATA instead:

char const *token;
void const *value;
if (meta->GetByName("chroma", &token, &value) != k_ErrNOMETADATA)
    memcpy(chroma, value, sizeof(chroma));

It is also possible to enumerate the metadata fields using a combination of the Count() and GetByIndex() methods. Note that these may not be in any particular order:

int count = meta->Count();
for (int index = 0; index < count; ++index) {
    char const *token;
    void const *value;
    meta->GetByIndex(index, &token, &value);
    // Do something with token/value
}

3   Access via libdtex

Similar additions have also been made to the traditional C API:

int DtexGetFileMetadata(DtexFile *f, DtexMetadata **result);
int DtexGetImageMetadata(DtexImage *i, DtexMetadata **result);
int DtexMetadataSet(DtexMetadata *meta,
                    char const *token, void const *value);
int DtexMetadataCount(DtexMetadata *meta);
int DtexMetadataGetByIndex(DtexMetadata *meta, int index,
                           char const **token, void const **value);
int DtexMetadataGetByName(DtexMetadata *meta, char const *name,
                          char const **token, void const **value);

4   Example: Displaying Metadata

Source code for a small example program has been provided as part of the librix distribution in the file RixDeepTextureMetadata.cpp. This program walks through a deep texture file and prints all of the metadata fields.


5   Standard Fields

As of 17.0, PRMan automatically adds the following fields to all deep data images to help determine how to use them:

string formattype
The particular type of data stored in this image - how the image should be interpreted. Normally one of "deepopacity", "areashadow", or "deepcomp".
int formatversion
A version number specific to the above formattype. Currently this is 1 for all three types. These may be incremented in the future if interpretation of the data changes in a non-backward compatible way.

When the renderer loads a newer (i.e., metadata-capable) deep image it will look for these and reject the image if it either doesn't recognize the formattype or the formatversion is too new.

To ensure that images generated by your own tools have these tags, the existing DeepFile::AddImage() or DtexAddImage() functions will try to infer the formattype from the image name and set the formatversion to the most current version for that type.

You can also explicitly give values for these through a new overload of DeepFile::AddImage() or through the new DtexAddImageEx() function.

Currently, we have just the two standard metadata fields noted above. We expect the list to grow with future releases, and for the deep shadow display driver to automatically add some of them. We also intend to support the injection of arbitrary fields via parameters on the Display line.


6   Type and Version Queries

In addition to the arbitrary metadata, we have also added functions for inspecting a file to determine whether it is a deep texture file. The librix and libdtex versions of these, respectively, are:

int RixDeepTexture::IsDeepFile(const char *name, DeepCache *, int *version);

and:

int DtexIsDeepFile(const char *name, DtexCache *cache, int *version);

If the file is a deep they will return k_ErrNOERR or DTEX_NOERR and set version (if non-null) to the file format version.

Note that these functions only inspect the file for the header, so they are much faster than attempting to fully load a file via RixDeepTexture::OpenFile() or DtexOpenFile().

If, however, you already have an open file then the format version may be determined via the new functions:

int DeepFile::FileVersion();
int DtexFileVersion(DtexFile *f);