Skip to content

OIIO 2.0 Porting Guide

Larry Gritz edited this page Dec 10, 2018 · 5 revisions

OpenImageIO 2.0 makes several (minor) non-backwards compatible API changes that will require some minor changes to client applications.

Required: ImageInput/Output::create() and open() now return unique_ptr<>

I will describe this for ImageInput, but the situation with ImageOutput is exactly the same.

The ImageInput::create() function returned a raw pointer to an ImageInput, which the caller was then responsible for eventually destroying.

Old (OIIO 1.x) code:

    ImageInput *in = ImageInput::open(filename);
    ...
    in->close();   // all done!
    ImageInput::destroy (in);   // correctly destroy it

It was equivalent to call ImageInput::create() and then separately open() the resulting ImageInput. The same guidelines apply to create() as to open().

Note also that a common mistake was to call delete in rather than ImageInput::destroy(in). That usually worked, and was harmless on Linux or OSX, but could be problematic on Windows systems where sometimes code that lives in different DLLs have different heaps and you should avoid an allocation and a free happening in different DLLs.

In OIIO 2.0, the create() function was changed to return a std::unique_ptr<ImageInput>, which makes resource management a lot easier. The new way is:

    auto in = ImageInput::open(filename);
    ...
    in->close();
    // in will automatically free when it goes out of scope!
    // Optional:   in.reset();

In OIIO 2.0, when in leaves scope, it will automatically release its resources. But if you really want to ensure that it happens right now, you can call in.reset().

If you have code that needs to work with both OIIO 1.8 and 2.0, you can use this idiom:

    auto in = ImageInput::open(filename);
    ...
    in->close();
#if OIIO_VERSION < 10903
    ImageInput::destroy(in);
#endif

The auto will catch the result of open() (or create()) regardless of it's a raw pointer or a unique_ptr. You only need to destroy() the raw pointer, which is the case if OIIO_VERSION < 10903. But if you are confident that your code will only need to support OIIO 2.0 or newer, then you don't need the #if or the destroy at all.

Possible break: ustring cast to int has been removed

You may or may not run into this, depending on whether you have apps that use the ustring class, and how you use it.

The ustring class previously had a operator int() that returned nonzero if the ustring had characters, 0 if empty. So you could do this:

ustring u;  // it hold something, or maybe nothing
if (u) {
    // u is not empty
}

This was well intentioned, but by being an int, it led to other problems where if you assigned to a char*, it could do the int cast and then interpret that int as a pointer, and it just gets worse from there. This possibility was theorized to create risk of unintentional bugs in code that used ustring, and as soon as we took away the operator int(), which will generate a compile-time error if you try to use it that way, indeed we found places in both OSL and USD that used it incorrectly and could never have worked properly (presumably those lines were on untested code paths or made bugs that nobody correctly diagnosed and fixed).

Anyway, long story short, the fix is to change

ustring u, v;
if (u) { ... }
if (!v) { ... }

to

if (!u.empty()) { ... }

if (v.empty()) { ... }

Python changes

Improve your C++ life with ImageBufAlgo

Clone this wiki locally