Image I/O API Helper Classes

Data Type Descriptions: TypeDesc

There are two kinds of data that are important to OpenImageIO:

  • Internal data is in the memory of the computer, used by an application program.

  • Native file data is what is stored in an image file itself (i.e., on the “other side” of the abstraction layer that OpenImageIO provides).

Both internal and file data is stored in a particular data format that describes the numerical encoding of the values. OpenImageIO understands several types of data encodings, and there is a special class, TypeDesc, that allows their enumeration and is described in the header file OpenImageIO/typedesc.h. A TypeDesc describes a base data format type, aggregation into simple vector and matrix types, and an array length (if it’s an array).

The remainder of this section describes the C++ API for TypeDesc. See Section~ref{sec:pythontypedesc} for the corresponding Python bindings.

struct OIIO::TypeDesc

A TypeDesc describes simple data types.

It frequently comes up (in my experience, with renderers and image handling programs) that you want a way to describe data that is passed through APIs through blind pointers. These are some simple classes that provide a simple type descriptor system. This is not meant to be comprehensive for example, there is no provision for structs, unions, pointers, const, or ‘nested’ type definitions. Just simple integer and floating point, common aggregates such as 3-points, and reasonably-lengthed arrays thereof.

Public Types

enum BASETYPE

BASETYPE is a simple enum describing the base data types that correspond (mostly) to the C/C++ built-in types.

Values:

enumerator UNKNOWN

unknown type

enumerator NONE

void/no type

enumerator UINT8

8-bit unsigned int values ranging from 0..255, (C/C++ unsigned char).

enumerator UCHAR
enumerator INT8

8-bit int values ranging from -128..127, (C/C++ char).

enumerator CHAR
enumerator UINT16

16-bit int values ranging from 0..65535, (C/C++ unsigned short).

enumerator USHORT
enumerator INT16

16-bit int values ranging from -32768..32767, (C/C++ short).

enumerator SHORT
enumerator UINT32

32-bit unsigned int values (C/C++ unsigned int).

enumerator UINT
enumerator INT32

signed 32-bit int values (C/C++ int).

enumerator INT
enumerator UINT64

64-bit unsigned int values (C/C++ unsigned long long on most architectures).

enumerator ULONGLONG
enumerator INT64

signed 64-bit int values (C/C++ long long on most architectures).

enumerator LONGLONG
enumerator HALF

16-bit IEEE floating point values (OpenEXR half).

enumerator FLOAT

32-bit IEEE floating point values, (C/C++ float).

enumerator DOUBLE

64-bit IEEE floating point values, (C/C++ double).

enumerator STRING

Character string.

enumerator PTR

A pointer value.

enumerator LASTBASE
enum AGGREGATE

AGGREGATE describes whether our TypeDesc is a simple scalar of one of the BASETYPE’s, or one of several simple aggregates.

Note that aggregates and arrays are different. A TypeDesc(FLOAT,3) is an array of three floats, a TypeDesc(FLOAT,VEC3) is a single 3-component vector comprised of floats, and TypeDesc(FLOAT,3,VEC3) is an array of 3 vectors, each of which is comprised of 3 floats.

Values:

enumerator SCALAR

A single scalar value (such as a raw int or float in C). This is the default.

enumerator VEC2

2 values representing a 2D vector.

enumerator VEC3

3 values representing a 3D vector.

enumerator VEC4

4 values representing a 4D vector.

enumerator MATRIX33

9 values representing a 3x3 matrix.

enumerator MATRIX44

16 values representing a 4x4 matrix.

enum VECSEMANTICS

VECSEMANTICS gives hints about what the data represent (for example, if a spatial vector quantity should transform as a point, direction vector, or surface normal).

Values:

enumerator NOXFORM

No semantic hints.

enumerator NOSEMANTICS

No semantic hints.

enumerator COLOR

Color.

enumerator POINT

Point: a spatial location.

enumerator VECTOR

Vector: a spatial direction.

enumerator NORMAL

Normal: a surface normal.

enumerator TIMECODE

indicates an int[2] representing the standard 4-byte encoding of an SMPTE timecode.

enumerator KEYCODE

indicates an int[7] representing the standard 28-byte encoding of an SMPTE keycode.

enumerator RATIONAL

A VEC2 representing a rational number val[0] / val[1]

enumerator BOX

A VEC2[2] or VEC3[2] that represents a 2D or 3D bounds (min/max)

Public Functions

inline constexpr TypeDesc(BASETYPE btype = UNKNOWN, AGGREGATE agg = SCALAR, VECSEMANTICS semantics = NOSEMANTICS, int arraylen = 0) noexcept

Construct from a BASETYPE and optional aggregateness, semantics, and arrayness.

inline constexpr TypeDesc(BASETYPE btype, int arraylen) noexcept

Construct an array of a non-aggregate BASETYPE.

inline constexpr TypeDesc(BASETYPE btype, AGGREGATE agg, int arraylen) noexcept

Construct an array from BASETYPE, AGGREGATE, and array length, with unspecified (or moot) semantic hints.

TypeDesc(string_view typestring)

Construct from a string (e.g., “float[3]”). If no valid type could be assembled, set base to UNKNOWN.

Examples:

TypeDesc("int") == TypeDesc(TypeDesc::INT)            // C++ int32_t
TypeDesc("float") == TypeDesc(TypeDesc::FLOAT)        // C++ float
TypeDesc("uint16") == TypeDesc(TypeDesc::UINT16)      // C++ uint16_t
TypeDesc("float[4]") == TypeDesc(TypeDesc::FLOAT, 4)  // array
TypeDesc("point") == TypeDesc(TypeDesc::FLOAT,
                              TypeDesc::VEC3, TypeDesc::POINT)

inline constexpr TypeDesc(const TypeDesc &t) noexcept

Copy constructor.

const char *c_str() const

Return the name, for printing and whatnot. For example, “float”, “int[5]”, “normal”

inline constexpr size_t numelements() const noexcept

Return the number of elements: 1 if not an array, or the array length. Invalid to call this for arrays of undetermined size.

inline constexpr size_t basevalues() const noexcept

Return the number of basetype values: the aggregate count multiplied by the array length (or 1 if not an array). Invalid to call this for arrays of undetermined size.

inline constexpr bool is_array() const noexcept

Does this TypeDesc describe an array?

inline constexpr bool is_unsized_array() const noexcept

Does this TypeDesc describe an array, but whose length is not specified?

inline constexpr bool is_sized_array() const noexcept

Does this TypeDesc describe an array, whose length is specified?

inline size_t size() const noexcept

Return the size, in bytes, of this type.

inline constexpr TypeDesc elementtype() const noexcept

Return the type of one element, i.e., strip out the array-ness.

inline size_t elementsize() const noexcept

Return the size, in bytes, of one element of this type (that is, ignoring whether it’s an array).

inline constexpr TypeDesc scalartype() const

Return just the underlying C scalar type, i.e., strip out the array-ness and the aggregateness.

size_t basesize() const noexcept

Return the base type size, i.e., stripped of both array-ness and aggregateness.

bool is_floating_point() const noexcept

True if it’s a floating-point type (versus a fundamentally integral type or something else like a string).

bool is_signed() const noexcept

True if it’s a signed type that allows for negative values.

inline constexpr bool is_unknown() const noexcept

Shortcut: is it UNKNOWN?

inline constexpr operator bool() const noexcept

if (typedesc) is the same as asking whether it’s not UNKNOWN.

size_t fromstring(string_view typestring)

Set *this to the type described in the string. Return the length of the part of the string that describes the type. If no valid type could be assembled, return 0 and do not modify *this.

inline constexpr bool operator==(const TypeDesc &t) const noexcept

Compare two TypeDesc values for equality.

inline constexpr bool operator!=(const TypeDesc &t) const noexcept

Compare two TypeDesc values for inequality.

inline constexpr bool equivalent(const TypeDesc &b) const noexcept

Member version of equivalent.

inline constexpr bool is_vec2(BASETYPE b = FLOAT) const noexcept

Is this a 2-vector aggregate (of the given type, float by default)?

inline constexpr bool is_vec3(BASETYPE b = FLOAT) const noexcept

Is this a 3-vector aggregate (of the given type, float by default)?

inline constexpr bool is_vec4(BASETYPE b = FLOAT) const noexcept

Is this a 4-vector aggregate (of the given type, float by default)?

inline constexpr bool is_box2(BASETYPE b = FLOAT) const noexcept

Is this an array of aggregates that represents a 2D bounding box?

inline constexpr bool is_box3(BASETYPE b = FLOAT) const noexcept

Is this an array of aggregates that represents a 3D bounding box?

inline void unarray(void) noexcept

Demote the type to a non-array

bool operator<(const TypeDesc &x) const noexcept

Test for lexicographic ‘less’, comes in handy for lots of STL containers and algorithms.

Public Members

unsigned char basetype

C data type at the heart of our type.

unsigned char aggregate

What kind of AGGREGATE is it?

unsigned char vecsemantics

Hint: What does the aggregate represent?

unsigned char reserved

Reserved for future expansion.

int arraylen

Array length, 0 = not array, -1 = unsized.

Public Static Functions

static BASETYPE basetype_merge(TypeDesc a, TypeDesc b)

Given base data types of a and b, return a basetype that is a best guess for one that can handle both without any loss of range or precision.

Friends

inline friend friend constexpr bool operator== (const TypeDesc &t, BASETYPE b) noexcept

Compare a TypeDesc to a basetype (it’s the same if it has the same base type and is not an aggregate or an array).

inline friend friend constexpr bool operator!= (const TypeDesc &t, BASETYPE b) noexcept

Compare a TypeDesc to a basetype (it’s the same if it has the same base type and is not an aggregate or an array).

inline friend friend constexpr bool equivalent (const TypeDesc &a, const TypeDesc &b) noexcept

TypeDesc’s are equivalent if they are equal, or if their only inequality is differing vector semantics.

A number of static constexpr TypeDesc aliases for common types exist in the outer OpenImageIO scope:

TypeUnknown TypeFloat TypeColor TypePoint TypeVector TypeNormal
TypeMatrix33 TypeMatrix44 TypeMatrix TypeHalf
TypeInt TypeUInt TypeInt32 TypeUInt32 TypeInt64 TypeUInt64
TypeInt16 TypeUInt16 TypeInt8 TypeUInt8
TypeFloat2 TypeVector2 TypeVector2i TypeFloat4
TypeString TypeTimeCode TypeKeyCode
TypeBox2 TypeBox2i TypeBox3 TypeBox3i
TypeRational TypePointer

The only types commonly used to store pixel values in image files are scalars of UINT8, UINT16, float, and half (the last only used by OpenEXR, to the best of our knowledge).

Note that the TypeDesc (which is also used for applications other than images) can describe many types not used by OpenImageIO. Please ignore this extra complexity; only the above simple types are understood by OpenImageIO as pixel storage data types, though a few others, including string and MATRIX44 aggregates, are occasionally used for metadata for certain image file formats (see sec-imageoutput-metadata Sections sec-imageoutput-metadata, sec-imageinput-metadata, and the documentation of individual ImageIO plugins for details).

Non-owning string views: string_view

class OIIO::string_view

A string_view is a non-owning, non-copying, non-allocating reference to a sequence of characters. It encapsulates both a character pointer and a length.

A function that takes a string input (but does not need to alter the string in place) may use a string_view parameter and accept input that is any of char* (C string), string literal (constant char array), a std::string (C++ string), or OIIO ustring. For all of these cases, no extra allocations are performed, and no extra copies of the string contents are performed (as they would be, for example, if the function took a const std::string& argument but was passed a char* or string literal).

Furthermore, a function that returns a copy or a substring of one of its inputs (for example, a substr()-like function) may return a string_view rather than a std::string, and thus generate its return value without any allocation or copying. Upon assignment to a std::string or ustring, it will properly auto-convert.

There are two important caveats to using this class:

  1. The string_view merely refers to characters owned by another string, so the string_view may not be used outside the lifetime of the string it refers to. Thus, string_view is great for parameter passing, but it’s not a good idea to use a string_view to store strings in a data structure (unless you are really sure you know what you’re doing).

  2. Because the run of characters that the string_view refers to may not be 0-terminated, it is important to distinguish between the data() method, which returns the pointer to the characters, and the c_str() method, which is guaranteed to return a valid C string that is 0-terminated. Thus, if you want to pass the contents of a string_view to a function that expects a 0-terminated string (say, fopen), you must call fopen(my_string_view.c_str()). Note that the usual case is that the string_view does refer to a 0-terminated string, and in that case c_str() returns the same thing as data() without any extra expense; but in the rare case that it is not 0-terminated, c_str() will incur extra expense to internally allocate a valid C string.

Public Functions

inline constexpr string_view() noexcept

Default ctr.

inline string_view(const string_view &copy) noexcept

Copy ctr.

inline string_view(const charT *chars, size_t len)

Construct from char* and length.

inline string_view(const charT *chars)

Construct from char*, use strlen to determine length.

inline string_view(const std::string &str) noexcept

Construct from std::string. Remember that a string_view doesn’t have its own copy of the characters, so don’t use the string_view after the original string has been destroyed or altered.

inline std::string str() const

Convert a string_view to a std::string.

const char *c_str() const

Explicitly request a 0-terminated string. USUALLY, this turns out to be just data(), with no significant added expense (because most uses of string_view are simple wrappers of C strings, C++ std::string, or ustring all of which are 0-terminated). But in the more rare case that the string_view represents a non-0-terminated substring, it will force an allocation and copy underneath.

Caveats:

  1. This is NOT going to be part of the C++17 std::string_view, so it’s probably best to avoid this method if you want to have 100% drop-in compatibility with std::string_view.

  2. It is NOT SAFE to use c_str() on a string_view whose last char is the end of an allocation because that next char may only coincidentally be a ‘\0’, which will cause c_str() to return the string start (thinking it’s a valid C string, so why not just return its address?), if there’s any chance that the subsequent char could change from 0 to non-zero during the use of the result of c_str(), and thus break the assumption that it’s a valid C str.

inline operator std::string() const

Convert a string_view to a std::string.

inline constexpr bool empty() const noexcept

Is the string_view empty, containing no characters?

inline const charT &operator[](size_type pos) const

Element access of an individual character (beware: no bounds checking!).

inline const charT &at(size_t pos) const

Element access with bounds checking and exception if out of bounds.

inline size_type find(string_view s, size_t pos = 0) const noexcept

Find the first occurrence of substring s in *this, starting at position pos.

inline size_type find(charT c, size_t pos = 0) const noexcept

Find the first occurrence of character c in *this, starting at position pos.

inline size_type rfind(string_view s, size_t pos = npos) const noexcept

Find the last occurrence of substring s *this, but only those occurrences earlier than position pos.

inline size_type rfind(charT c, size_t pos = npos) const noexcept

Find the last occurrence of character c in *this, but only those occurrences earlier than position pos.


Efficient unique strings: ustring

class OIIO::ustring

A ustring is an alternative to char* or std::string for storing strings, in which the character sequence is unique (allowing many speed advantages for assignment, equality testing, and inequality testing).

The implementation is that behind the scenes there is a hash set of allocated strings, so the characters of each string are unique. A ustring itself is a pointer to the characters of one of these canonical strings. Therefore, assignment and equality testing is just a single 32- or 64-bit int operation, the only mutex is when a ustring is created from raw characters, and the only malloc is the first time each canonical ustring is created.

The internal table also contains a std::string version and the length of the string, so converting a ustring to a std::string (via ustring::string()) or querying the number of characters (via ustring::size() or ustring::length()) is extremely inexpensive, and does not involve creation/allocation of a new std::string or a call to strlen.

We try very hard to completely mimic the API of std::string, including all the constructors, comparisons, iterations, etc. Of course, the charaters of a ustring are non-modifiable, so we do not replicate any of the non-const methods of std::string. But in most other ways it looks and acts like a std::string and so most templated algorthms that would work on a “const std::string &” will also work on a ustring.

Usage guidelines:

Compared to standard strings, ustrings have several advantages:

  • Each individual ustring is very small in fact, we guarantee that a ustring is the same size and memory layout as an ordinary char*.

  • Storage is frugal, since there is only one allocated copy of each unique character sequence, throughout the lifetime of the program.

  • Assignment from one ustring to another is just copy of the pointer; no allocation, no character copying, no reference counting.

  • Equality testing (do the strings contain the same characters) is a single operation, the comparison of the pointer.

  • Memory allocation only occurs when a new ustring is constructed from raw characters the FIRST time subsequent constructions of the same string just finds it in the canonical string set, but doesn’t need to allocate new storage. Destruction of a ustring is trivial, there is no de-allocation because the canonical version stays in the set. Also, therefore, no user code mistake can lead to memory leaks.

But there are some problems, too. Canonical strings are never freed from the table. So in some sense all the strings “leak”, but they only leak one copy for each unique string that the program ever comes across. Also, creation of unique strings from raw characters is more expensive than for standard strings, due to hashing, table queries, and other overhead.

On the whole, ustrings are a really great string representation

  • if you tend to have (relatively) few unique strings, but many copies of those strings;

  • if the creation of strings from raw characters is relatively rare compared to copying or comparing to existing strings;

  • if you tend to make the same strings over and over again, and if it’s relatively rare that a single unique character sequence is used only once in the entire lifetime of the program;

  • if your most common string operations are assignment and equality testing and you want them to be as fast as possible;

  • if you are doing relatively little character-by-character assembly of strings, string concatenation, or other “string manipulation” (other than equality testing).

ustrings are not so hot

  • if your program tends to have very few copies of each character sequence over the entire lifetime of the program;

  • if your program tends to generate a huge variety of unique strings over its lifetime, each of which is used only a short time and then discarded, never to be needed again;

  • if you don’t need to do a lot of string assignment or equality testing, but lots of more complex string manipulation.

Public Functions

inline ustring(void) noexcept

Default ctr for ustring make an empty string.

inline explicit ustring(const char *str)

Construct a ustring from a null-terminated C string (char *).

inline explicit ustring(string_view str)

Construct a ustring from a string_view, which can be auto-converted from either a null-terminated C string (char *) or a C++ std::string.

inline ustring(const char *str, size_type pos, size_type n)

Construct a ustring from at most n characters of str, starting at position pos.

inline ustring(const char *str, size_type n)

Construct a ustring from the first n characters of str.

inline ustring(size_type n, char c)

Construct a ustring from n copies of character c.

inline ustring(const std::string &str, size_type pos, size_type n = npos)

Construct a ustring from an indexed substring of a std::string.

inline ustring(const ustring &str) noexcept

Copy construct a ustring from another ustring.

inline ustring(const ustring &str, size_type pos, size_type n = npos)

Construct a ustring from an indexed substring of a ustring.

inline ~ustring() noexcept

ustring destructor.

inline operator string_view() const noexcept

Conversion to string_view.

inline explicit operator std::string() const noexcept

Conversion to std::string (explicit only!).

inline const ustring &assign(const ustring &str)

Assign a ustring to *this.

inline const ustring &assign(const ustring &str, size_type pos, size_type n = npos)

Assign a substring of a ustring to *this.

inline const ustring &assign(const std::string &str)

Assign a std::string to *this.

inline const ustring &assign(const std::string &str, size_type pos, size_type n = npos)

Assign a substring of a std::string to *this.

inline const ustring &assign(const char *str)

Assign a null-terminated C string (char*) to *this.

inline const ustring &assign(const char *str, size_type n)

Assign the first n characters of str to *this.

inline const ustring &assign(size_type n, char c)

Assign n copies of c to *this.

inline const ustring &assign(string_view str)

Assign a string_view to *this.

inline const ustring &operator=(const ustring &str)

Assign a ustring to another ustring.

inline const ustring &operator=(const char *str)

Assign a null-terminated C string (char *) to a ustring.

inline const ustring &operator=(const std::string &str)

Assign a C++ std::string to a ustring.

inline const ustring &operator=(string_view str)

Assign a string_view to a ustring.

inline const ustring &operator=(char c)

Assign a single char to a ustring.

inline const char *c_str() const noexcept

Return a C string representation of a ustring.

inline const char *data() const noexcept

Return a C string representation of a ustring.

inline const std::string &string() const noexcept

Return a C++ std::string representation of a ustring.

inline void clear(void) noexcept

Reset to an empty string.

inline size_t length(void) const noexcept

Return the number of characters in the string.

inline size_t hash(void) const noexcept

Return a hashed version of the string.

inline size_t size(void) const noexcept

Return the number of characters in the string.

inline bool empty(void) const noexcept

Is the string empty i.e., is it nullptr or does it point to an empty string?

inline const_iterator begin() const noexcept

Return a const_iterator that references the first character of the string.

inline const_iterator end() const noexcept

Return a const_iterator that references the end of a traversal of the characters of the string.

inline const_reverse_iterator rbegin() const noexcept

Return a const_reverse_iterator that references the last character of the string.

inline const_reverse_iterator rend() const noexcept

Return a const_reverse_iterator that references the end of a reverse traversal of the characters of the string.

inline const_reference operator[](size_type pos) const noexcept

Return a reference to the character at the given position. Note that it’s up to the caller to be sure pos is within the size of the string.

inline size_type copy(char *s, size_type n, size_type pos = 0) const

Dump into character array s the characters of this ustring, beginning with position pos and copying at most n characters.

inline ustring substr(size_type pos = 0, size_type n = npos) const

Returns a substring of the ustring object consisting of n characters starting at position pos.

inline int compare(string_view str) const noexcept

Return 0 if *this is lexicographically equal to str, -1 if *this is lexicographically earlier than str, 1 if *this is lexicographically after str.

inline int compare(const char *str) const noexcept

Return 0 if *this is lexicographically equal to str, -1 if *this is lexicographically earlier than str, 1 if *this is lexicographically after str.

inline bool operator==(const ustring &str) const noexcept

Test two ustrings for equality are they comprised of the same sequence of characters. Note that because ustrings are unique, this is a trivial pointer comparison, not a char-by-char loop as would be the case with a char* or a std::string.

inline bool operator!=(const ustring &str) const noexcept

Test two ustrings for inequality are they comprised of different sequences of characters. Note that because ustrings are unique, this is a trivial pointer comparison, not a char-by-char loop as would be the case with a char* or a std::string.

inline bool operator==(const std::string &x) const noexcept

Test a ustring (*this) for lexicographic equality with std::string x.

inline bool operator==(string_view x) const noexcept

Test a ustring (*this) for lexicographic equality with string_view x.

inline bool operator==(const char *x) const noexcept

Test a ustring (this) for lexicographic equality with char x.

inline bool operator!=(const std::string &x) const noexcept

Test a ustring (*this) for lexicographic inequality with std::string x.

inline bool operator!=(string_view x) const noexcept

Test a ustring (*this) for lexicographic inequality with string_view x.

inline bool operator!=(const char *x) const noexcept

Test a ustring (this) for lexicographic inequality with char x.

inline bool operator<(const ustring &x) const noexcept

Test for lexicographic ‘less’, comes in handy for lots of STL containers and algorithms.

Public Static Functions

template<typename ...Args>
static inline ustring sprintf(const char *fmt, const Args&... args)

Construct a ustring in a printf-like fashion. In other words, something like: ustring s = ustring::sprintf(“blah %d %g”, (int)foo, (float)bar); The argument list is fully typesafe. The formatting of the string will always use the classic “C” locale conventions (in particular, ‘.’ as decimal separator for float values).

template<typename ...Args>
static inline ustring fmtformat(const char *fmt, const Args&... args)

Construct a ustring in a fmt::format-like fashion. In other words, something like: ustring s = ustring::fmtformat(“blah {} {}”, (int)foo, (float)bar); The argument list is fully typesafe. The formatting of the string will always use the classic “C” locale conventions (in particular, ‘.’ as decimal separator for float values).

template<typename ...Args>
static inline ustring format(const char *fmt, const Args&... args)

NOTE: Semi-DEPRECATED! This will someday switch to behave like fmt::format (or future std::format) but for now, it is back compatible and equivalent to sprintf.

static ustring concat(string_view s, string_view t)

Concatenate two strings, returning a ustring, implemented carefully to not perform any redundant copies or allocations. This is semantically equivalent to ustring::sprintf("%s%s", s, t), but is more efficient.

static std::string getstats(bool verbose = true)

Return the statistics output as a string.

static size_t memory()

Return the amount of memory consumed by the ustring table.

static size_t total_ustrings()

Return the total number of ustrings in the internal table.

static size_t hash_collisions(std::vector<ustring> *collisions = nullptr)

Return the total number ustrings that have the exact hash as another ustring. If collisions is passed, store all the colliding ustrings in the vector.

static const char *make_unique(string_view str)

Given a string_view, return a pointer to the unique version kept in the internal table (creating a new table entry if we haven’t seen this sequence of characters before). N.B.: this is equivalent to ustring(str).c_str(). It’s also the routine that is used directly by ustring’s internals to generate the canonical unique copy of the characters.

static inline bool is_unique(const char *str)

Is this character pointer a unique ustring representation of those characters? Useful for diagnostics and debugging.

static inline ustring from_unique(const char *unique)

Create a ustring from characters guaranteed to already be ustring-clean, without having to run through the hash yet again. Use with extreme caution!!!

Friends

inline friend friend int compare (const std::string &a, const ustring &b) noexcept

Return 0 if a is lexicographically equal to b, -1 if a is lexicographically earlier than b, 1 if a is lexicographically after b.

inline friend friend bool operator== (const std::string &a, const ustring &b) noexcept

Test for lexicographic equality between std::string a and ustring b.

inline friend friend bool operator== (string_view a, const ustring &b) noexcept

Test for lexicographic equality between string_view a and ustring b.

inline friend friend bool operator== (const char *a, const ustring &b) noexcept

Test for lexicographic equality between char* a and ustring b.

inline friend friend bool operator!= (const std::string &a, const ustring &b) noexcept

Test for lexicographic inequality between std::string a and ustring b.

inline friend friend bool operator!= (string_view a, const ustring &b) noexcept

Test for lexicographic inequality between string_view a and ustring b.

inline friend friend bool operator!= (const char *a, const ustring &b) noexcept

Test for lexicographic inequality between char* a and ustring b.

inline friend friend std::ostream & operator<< (std::ostream &out, const ustring &str)

Generic stream output of a ustring.

struct TableRep

Non-owning array views: span / cspan

template<typename T, oiio_span_size_type Extent = dynamic_extent>
class OIIO::span

span<T> is a non-owning, non-copying, non-allocating reference to a contiguous array of T objects known length. A ‘span` encapsulates both a pointer and a length, and thus is a safer way of passing pointers around (because the function called knows how long the array is). A function that might ordinarily take a T* and a length could instead just take a span<T>.

A span<T> is mutable (the values in the array may be modified). A non-mutable (i.e., read-only) reference would be span<const T>. Thus, a function that might ordinarily take a const T* and a length could instead take a span<const T>.

For convenience, we also define cspan<T> as equivalent to span<const T>.

A span may be initialized explicitly from a pointer and length, by initializing with a std::vector<T>, or by initalizing with a constant (treated as an array of length 1). For all of these cases, no extra allocations are performed, and no extra copies of the array contents are made.

Important caveat: The span merely refers to items owned by another array, so the span should not be used beyond the lifetime of the array it refers to. Thus, span is great for parameter passing, but it’s not a good idea to use a span to store values in a data structure (unless you are really sure you know what you’re doing).

Public Functions

inline constexpr span() noexcept

Default constructor the span points to nothing.

template<class U, oiio_span_size_type N>
inline constexpr span(const span<U, N> &copy) noexcept

Copy constructor (copies the span pointer and length, NOT the data).

constexpr span(const span &copy) noexcept = default

Copy constructor (copies the span pointer and length, NOT the data).

inline constexpr span(pointer data, size_type size) noexcept

Construct from T* and length.

inline constexpr span(pointer b, pointer e) noexcept

Construct from begin and end pointers.

inline constexpr span(T &data)

Construct from a single T&.

template<size_t N>
inline constexpr span(T (&data)[N])

Construct from a fixed-length C array. Template magic automatically finds the length from the declared type of the array.

template<class Allocator>
inline constexpr span(std::vector<T, Allocator> &v)

Construct from std::vector<T>.

template<class Allocator>
inline span(const std::vector<value_type, Allocator> &v)

Construct from const std::vector<T>. This turns const std::vector<T> into a span<const T> (the span isn’t const, but the data it points to will be).

template<size_t N>
inline constexpr span(std::array<value_type, N> &arr)

Construct from mutable element std::array.

template<size_t N>
inline constexpr span(const std::array<value_type, N> &arr)

Construct from read-only element std::array.

inline constexpr span(std::initializer_list<T> il)

Construct an span from an initializer_list.

inline span &operator=(const span &copy)

Assignment copies the pointer and length, not the data.

template<size_type Count>
inline constexpr span<element_type, Count> first() const

Subview containing the first Count elements of the span.

template<size_type Count>
inline constexpr span<element_type, Count> last() const

Subview containing the last Count elements of the span.

Additionally, there is a convenience template:

template<typename T>
using cspan = span<const T>

cspan<T> is a synonym for a non-mutable span<const T>.


Rectangular region of interest: ROI

struct OIIO::ROI

ROI is a small helper struct describing a rectangular region of interest in an image. The region is [xbegin,xend) x [begin,yend) x [zbegin,zend), with the “end” designators signifying one past the last pixel in each dimension, a la STL style.

ROI data members

The data members are:

int xbegin, xend, ybegin, yend, zbegin, zend;
int chbegin, chend;

These describe the spatial extent [xbegin,xend) x [ybegin,yend) x [zbegin,zend) And the channel extent: [chbegin,chend)]

Spatial size functions.

The width, height, and depth of the region.

inline constexpr int width() const noexcept

Height.

inline constexpr int height() const noexcept

Width.

inline constexpr int depth() const noexcept

Depth.

Public Functions

inline constexpr ROI() noexcept

Default constructor is an undefined region. Note that this is also interpreted as All().

inline constexpr ROI(int xbegin, int xend, int ybegin, int yend, int zbegin = 0, int zend = 1, int chbegin = 0, int chend = 10000) noexcept

Constructor with an explicitly defined region.

inline constexpr bool defined() const noexcept

Is a region defined?

inline constexpr int nchannels() const noexcept

Number of channels in the region. Beware this defaults to a huge number, and to be meaningful you must consider std::min (imagebuf.nchannels(), roi.nchannels()).

inline constexpr imagesize_t npixels() const noexcept

Total number of pixels in the region.

inline constexpr bool contains(int x, int y, int z = 0, int ch = 0) const noexcept

Test if the coordinate is within the ROI.

inline constexpr bool contains(const ROI &other) const noexcept

Test if another ROI is entirely within our ROI.

Public Static Functions

static inline constexpr ROI All() noexcept

All() is an alias for the default constructor, which indicates that it means “all” of the image, or no region restriction. For example, float myfunc (ImageBuf &buf, ROI roi = ROI::All()); Note that this is equivalent to: float myfunc (ImageBuf &buf, ROI roi = {});

Friends

inline friend friend constexpr bool operator== (const ROI &a, const ROI &b) noexcept

Test equality of two ROIs.

inline friend friend constexpr bool operator!= (const ROI &a, const ROI &b) noexcept

Test inequality of two ROIs.

inline friend friend std::ostream & operator<< (std::ostream &out, const ROI &roi)

Stream output of the range.

In addition, there are several related helper functions that involve ROI:

inline constexpr ROI OIIO::roi_union(const ROI &A, const ROI &B) noexcept

Union of two regions, the smallest region containing both.

inline constexpr ROI OIIO::roi_intersection(const ROI &A, const ROI &B) noexcept

Intersection of two regions.

ROI get_roi(const ImageSpec &spec)
ROI get_roi_full(const ImageSpec &spec)

Return the ROI describing spec’s pixel data window (the x, y, z, width, height, depth fields) or the full (display) window (the full_x, full_y, full_z, full_width, full_height, full_depth fields), respectively.

void set_roi(const ImageSpec &spec, const ROI &newroi)
void set_roi_full(const ImageSpec &spec, const ROI &newroi)

Alters the spec so to make its pixel data window or the full (display) window match newroi.

Image Specification: ImageSpec

An ImageSpec is a structure that describes the complete format specification of a single image. It contains:

  • The image resolution (number of pixels) and origin. This specifies what is often called the “pixel data window.”

  • The full size and offset of an abstract “full” or “display” window. Differing full and data windows can indicate that the pixels are a crop region or a larger image, or contain overscan pixels.

  • Whether the image is organized into tiles, and if so, the tile size.

  • The native data format of the pixel values (e.g., float, 8-bit integer, etc.).

  • The number of color channels in the image (e.g., 3 for RGB images), names of the channels, and whether any particular channels represent alpha and depth.

  • A user-extensible (and format-extensible) list of any other arbitrarily-named and -typed data that may help describe the image or its disk representation.

The remainder of this section describes the C++ API for ImageSpec. See Section ImageSpec for the corresponding Python bindings.

class OIIO::ImageSpec

ImageSpec describes the data format of an image dimensions, layout, number and meanings of image channels.

The width, height, depth are the size of the data of this image, i.e., the number of pixels in each dimension. A depth greater than 1 indicates a 3D “volumetric” image. The x, y, z fields indicate the origin of the pixel data of the image. These default to (0,0,0), but setting them differently may indicate that this image is offset from the usual origin. Therefore the pixel data are defined over pixel coordinates [xx+width-1] horizontally, [yy+height-1] vertically, and [zz+depth-1] in depth.

The analogous full_width, full_height, full_depth and full_x, full_y, full_z fields define a “full” or “display” image window over the region [full_xfull_x+full_width-1] horizontally, [full_yfull_y+full_height-1] vertically, and [full_zfull_z+full_depth-1] in depth.

Having the full display window different from the pixel data window can be helpful in cases where you want to indicate that your image is a crop window of a larger image (if the pixel data window is a subset of the full display window), or that the pixels include overscan (if the pixel data is a superset of the full display window), or may simply indicate how different non-overlapping images piece together.

For tiled images, tile_width, tile_height, and tile_depth specify that the image is stored in a file organized into rectangular tiles of these dimensions. The default of 0 value for these fields indicates that the image is stored in scanline order, rather than as tiles.

ImageSpec data members

The ImageSpec contains data fields for the values that are required to describe nearly any image, and an extensible list of arbitrary attributes that can hold metadata that may be user-defined or specific to individual file formats.

Here are the hard-coded data fields:

int x

origin (upper left corner) of pixel data

int y

origin (upper left corner) of pixel data

int z

origin (upper left corner) of pixel data

int width

width of the pixel data window

int height

height of the pixel data window

int depth

depth of pixel data, >1 indicates a “volume”

int full_x

origin of the full (display) window

int full_y

origin of the full (display) window

int full_z

origin of the full (display) window

int full_width

width of the full (display) window

int full_height

height of the full (display) window

int full_depth

depth of the full (display) window

int tile_width

tile width (0 for a non-tiled image)

int tile_height

tile height (0 for a non-tiled image)

int tile_depth

tile depth (0 for a non-tiled image, 1 for a non-volume image)

int nchannels

number of image channels, e.g., 4 for RGBA

TypeDesc format

Data format of the channels. Describes the native format of the pixel data values themselves, as a TypeDesc. Typical values would be TypeDesc::UINT8 for 8-bit unsigned values, TypeDesc::FLOAT for 32-bit floating-point values, etc.

std::vector<TypeDesc> channelformats

Optional per-channel data formats. If all channels of the image have the same data format, that will be described by format and channelformats will be empty (zero length). If there are different data formats for each channel, they will be described in the channelformats vector, and the format field will indicate a single default data format for applications that don’t wish to support per-channel formats (usually this will be the format of the channel that has the most precision).

std::vector<std::string> channelnames

The names of each channel, in order. Typically this will be “R”, “G”, “B”, “A” (alpha), “Z” (depth), or other arbitrary names.

int alpha_channel

The index of the channel that represents alpha (pixel coverage and/or transparency). It defaults to -1 if no alpha channel is present, or if it is not known which channel represents alpha.

int z_channel

The index of the channel that represents z or depth (from the camera). It defaults to -1 if no depth channel is present, or if it is not know which channel represents depth.

bool deep

True if the image contains deep data. If true, this indicates that the image describes contains “deep” data consisting of multiple samples per pixel. If false, it’s an ordinary image with one data value (per channel) per pixel.

ParamValueList extra_attribs

A list of arbitrarily-named and arbitrarily-typed additional attributes of the image, for any metadata not described by the hard-coded fields described above. This list may be manipulated with the attribute() and find_attribute() methods.

Public Functions

ImageSpec(TypeDesc format = TypeDesc::UNKNOWN) noexcept

Constructor: given just the data format, set all other fields to something reasonable.

ImageSpec(int xres, int yres, int nchans, TypeDesc fmt = TypeUInt8) noexcept

Constructs an ImageSpec with the given x and y resolution, number of channels, and pixel data format.

All other fields are set to the obvious defaults the image is an ordinary 2D image (not a volume), the image is not offset or a crop of a bigger image, the image is scanline-oriented (not tiled), channel names are “R”, “G”, “B”’ and “A” (up to and including 4 channels, beyond that they are named “channel *n*”), the fourth channel (if it exists) is assumed to be alpha.

explicit ImageSpec(const ROI &roi, TypeDesc fmt = TypeUInt8) noexcept

Construct an ImageSpec whose dimensions (both data and “full”) and number of channels are given by the ROI, pixel data type by fmt, and other fields are set to their default values.

void set_format(TypeDesc fmt) noexcept

Set the data format, and clear any per-channel format information in channelformats.

void default_channel_names() noexcept

Sets the channelnames to reasonable defaults for the number of channels. Specifically, channel names are set to “R”, “G”, “B,” and “A” (up to and including 4 channels, beyond that they are named “channel*n*”.

inline size_t channel_bytes() const noexcept

Returns the number of bytes comprising each channel of each pixel (i.e., the size of a single value of the type described by the format field).

size_t channel_bytes(int chan, bool native = false) const noexcept

Return the number of bytes needed for the single specified channel. If native is false (default), compute the size of one channel of this->format, but if native is true, compute the size of the channel in terms of the “native” data format of that channel as stored in the file.

size_t pixel_bytes(bool native = false) const noexcept

Return the number of bytes for each pixel (counting all channels). If native is false (default), assume all channels are in this->format, but if native is true, compute the size of a pixel in the “native” data format of the file (these may differ in the case of per-channel formats).

size_t pixel_bytes(int chbegin, int chend, bool native = false) const noexcept

Return the number of bytes for just the subset of channels in each pixel described by [chbegin,chend). If native is false (default), assume all channels are in this->format, but if native is true, compute the size of a pixel in the “native” data format of the file (these may differ in the case of per-channel formats).

imagesize_t scanline_bytes(bool native = false) const noexcept

Returns the number of bytes comprising each scanline, i.e., pixel_bytes(native) * width This will return std::numeric_limits<imagesize_t>max() in the event of an overflow where it’s not representable in an imagesize_t.

imagesize_t tile_pixels() const noexcept

Return the number of pixels comprising a tile (or 0 if it is not a tiled image). This will return std::numeric_limits<imagesize_t>max() in the event of an overflow where it’s not representable in an imagesize_t.

imagesize_t tile_bytes(bool native = false) const noexcept

Returns the number of bytes comprising an image tile, i.e., pixel_bytes(native) * tile_width * tile_height * tile_depth If native is false (default), assume all channels are in this->format, but if native is true, compute the size of a pixel in the “native” data format of the file (these may differ in the case of per-channel formats).

imagesize_t image_pixels() const noexcept

Return the number of pixels for an entire image. This will return std::numeric_limits<imagesize_t>max() in the event of an overflow where it’s not representable in an imagesize_t.

imagesize_t image_bytes(bool native = false) const noexcept

Returns the number of bytes comprising an entire image of these dimensions, i.e., pixel_bytes(native) * width * height * depth This will return std::numeric_limits<image size_t>max() in the event of an overflow where it’s not representable in an imagesize_t. If native is false (default), assume all channels are in this->format, but if native is true, compute the size of a pixel in the “native” data format of the file (these may differ in the case of per-channel formats).

inline bool size_t_safe() const noexcept

Verify that on this platform, a size_t is big enough to hold the number of bytes (and pixels) in a scanline, a tile, and the whole image. If this returns false, the image is much too big to allocate and read all at once, so client apps beware and check these routines for overflows!

void attribute(string_view name, TypeDesc type, const void *value)

Add a metadata attribute to extra_attribs, with the given name and data type. The value pointer specifies the address of the data to be copied.

inline void attribute(string_view name, unsigned int value)

Add an unsigned int attribute to extra_attribs.

inline void attribute(string_view name, int value)

Add an int attribute to extra_attribs.

inline void attribute(string_view name, float value)

Add a float attribute to extra_attribs.

inline void attribute(string_view name, string_view value)

Add a string attribute to extra_attribs.

void attribute(string_view name, TypeDesc type, string_view value)

Parse a string containing a textual representation of a value of the given type, and add that as an attribute to extra_attribs. Example:

spec.attribute ("temperature", TypeString, "-273.15");

void erase_attribute(string_view name, TypeDesc searchtype = TypeDesc::UNKNOWN, bool casesensitive = false)

Searches extra_attribs for any attributes matching name (as a regular expression), removing them entirely from extra_attribs. If searchtype is anything other than TypeDesc::UNKNOWN, matches will be restricted only to attributes with the given type. The name comparison will be case-sensitive if casesensitive is true, otherwise in a case-insensitive manner.

ParamValue *find_attribute(string_view name, TypeDesc searchtype = TypeDesc::UNKNOWN, bool casesensitive = false)

Searches extra_attribs for an attribute matching name, returning a pointer to the attribute record, or NULL if there was no match. If searchtype is anything other than TypeDesc::UNKNOWN, matches will be restricted only to attributes with the given type. The name comparison will be exact if casesensitive is true, otherwise in a case-insensitive manner if caseinsensitive is false.

const ParamValue *find_attribute(string_view name, ParamValue &tmpparam, TypeDesc searchtype = TypeDesc::UNKNOWN, bool casesensitive = false) const

Search for the named attribute and return the pointer to its ParamValue record, or NULL if not found. This variety of find_attribute(} can retrieve items such as “width”, which are data members of the ImageSpec, but not in extra_attribs. The tmpparam is a storage area owned by the caller, which is used as temporary buffer in cases where the information does not correspond to an actual extra_attribs (in this case, the return value will be &tmpparam). The extra names it understands are:

  • "x" "y" "z" "width" "height" "depth" "full_x" "full_y" "full_z" "full_width" "full_height" "full_depth"

    Returns the ImageSpec fields of those names (despite the fact that they are technically not arbitrary named attributes in extra_attribs). All are of type int.

  • "datawindow"

    Without a type, or if requested explicitly as an int[4], returns the OpenEXR-like pixel data min and max coordinates, as a 4-element integer array: { x, y, x+width-1, y+height-1 }. If instead you specifically request as an int[6], it will return the volumetric data window, { x, y, z, x+width-1, y+height-1, z+depth-1 }.

  • "displaywindow"

    Without a type, or if requested explicitly as an int[4], returns the OpenEXR-like pixel display min and max coordinates, as a 4-element integer array: { full_x, full_y, full_x+full_width-1, full_y+full_height-1 }. If instead you specifically request as an int[6], it will return the volumetric display window, { full_x, full_y, full_z, full_x+full_width-1, full_y+full_height-1, full_z+full_depth-1 }.

EXAMPLES

ImageSpec spec;           // has the info
Imath::Box2i dw;          // we want the displaywindow here
ParamValue tmp;           // so we can retrieve pseudo-values
TypeDesc int4("int[4]");  // Equivalent: TypeDesc int4(TypeDesc::INT,4);
const ParamValue* p = spec.find_attribute ("displaywindow", int4);
if (p)
    dw = Imath::Box2i(p->get<int>(0), p->get<int>(1),
                      p->get<int>(2), p->get<int>(3));

p = spec.find_attribute("temperature", TypeFloat);
if (p)
    float temperature = p->get<float>();

TypeDesc getattributetype(string_view name, bool casesensitive = false) const

If the named attribute can be found in the ImageSpec, return its data type. If no such attribute exists, return TypeUnknown.

This was added in version 2.1.

bool getattribute(string_view name, TypeDesc type, void *value, bool casesensitive = false) const

If the ImageSpec contains the named attribute and its type matches type, copy the attribute value into the memory pointed to by val (it is up to the caller to ensure there is enough space) and return true. If no such attribute is found, or if it doesn’t match the type, return false and do not modify val.

EXAMPLES:

ImageSpec spec;
...
// Retrieving an integer attribute:
int orientation = 0;
spec.getattribute ("orientation", TypeInt, &orientation);

// Retrieving a string attribute with a char*:
const char* compression = nullptr;
spec.getattribute ("compression", TypeString, &compression);

// Alternately, retrieving a string with a ustring:
ustring compression;
spec.getattribute ("compression", TypeString, &compression);

Note that when passing a string, you need to pass a pointer to the char*, not a pointer to the first character. Also, the char* will end up pointing to characters owned by the ImageSpec; the caller does not need to ever free the memory that contains the characters.

This was added in version 2.1.

int get_int_attribute(string_view name, int defaultval = 0) const

Retrieve the named metadata attribute and return its value as an int. Any integer type will convert to int by truncation or expansion, string data will parsed into an int if its contents consist of of the text representation of one integer. Floating point data will not succeed in converting to an int. If no such metadata exists, or are of a type that cannot be converted, the defaultval will be returned.

float get_float_attribute(string_view name, float defaultval = 0) const

Retrieve the named metadata attribute and return its value as a float. Any integer or floating point type will convert to float in the obvious way (like a C cast), and so will string metadata if its contents consist of of the text representation of one floating point value. If no such metadata exists, or are of a type that cannot be converted, the defaultval will be returned.

string_view get_string_attribute(string_view name, string_view defaultval = string_view()) const

Retrieve any metadata attribute, converted to a string. If no such metadata exists, the defaultval will be returned.

std::string serialize(SerialFormat format, SerialVerbose verbose = SerialDetailed) const

Returns, as a string, a serialized version of the ImageSpec. The format may be either ImageSpec::SerialText or ImageSpec::SerialXML. The verbose argument may be one of: ImageSpec::SerialBrief (just resolution and other vital statistics, one line for SerialText, ImageSpec::SerialDetailed (contains all metadata in original form), or ImageSpec::SerialDetailedHuman (contains all metadata, in many cases with human-readable explanation).

std::string to_xml() const

Converts the contents of the ImageSpec as an XML string.

void from_xml(const char *xml)

Populates the fields of the ImageSpec based on the XML passed in.

std::pair<string_view, int> decode_compression_metadata(string_view defaultcomp = "", int defaultqual = -1) const

Hunt for the “Compression” and “CompressionQuality” settings in the spec and turn them into the compression name and quality. This handles compression name/qual combos of the form “name:quality”.

inline bool valid_tile_range(int xbegin, int xend, int ybegin, int yend, int zbegin, int zend) noexcept

Helper function to verify that the given pixel range exactly covers a set of tiles. Also returns false if the spec indicates that the image isn’t tiled at all.

inline TypeDesc channelformat(int chan) const

Return the channelformat of the given channel. This is safe even if channelformats is not filled out.

inline string_view channel_name(int chan) const

Return the channel name of the given channel. This is safe even if channelnames is not filled out.

inline void get_channelformats(std::vector<TypeDesc> &formats) const

Fill in an array of channel formats describing all channels in the image. (Note that this differs slightly from the member data channelformats, which is empty if there are not separate per-channel formats.)

int channelindex(string_view name) const

Return the index of the channel with the given name, or -1 if no such channel is present in channelnames.

inline ROI roi() const noexcept

Return pixel data window for this ImageSpec expressed as a ROI.

inline ROI roi_full() const noexcept

Return full/display window for this ImageSpec expressed as a ROI.

inline void set_roi(const ROI &r) noexcept

Set pixel data window parameters (x, y, z, width, height, depth) for this ImageSpec from an ROI. Does NOT change the channels of the spec, regardless of r.

inline void set_roi_full(const ROI &r) noexcept

Set full/display window parameters (full_x, full_y, full_z, full_width, full_height, full_depth) for this ImageSpec from an ROI. Does NOT change the channels of the spec, regardless of r.

inline void copy_dimensions(const ImageSpec &other)

Copy from other the image dimensions (x, y, z, width, height, depth, full*, nchannels, format) and data types. It does not copy arbitrary named metadata or channel names (thus, for an ImageSpec with lots of metadata, it is much less expensive than copying the whole thing with operator=()).

inline bool undefined() const noexcept

Returns true for a newly initialized (undefined) ImageSpec. (Designated by no channels and undefined data type true of the uninitialized state of an ImageSpec, and presumably not for any ImageSpec that is useful or purposefully made.)

inline AttrDelegate<ImageSpec> operator[](string_view name)

Array indexing by string will create an AttrDelegate that enables a convenient shorthand for adding and retrieving values from the spec:

  1. Assigning to the delegate adds a metadata attribute:

    ImageSpec spec;
    spec["foo"] = 42;                   // int
    spec["pi"] = float(M_PI);           // float
    spec["oiio:ColorSpace"] = "sRGB";   // string
    spec["cameratoworld"] = Imath::Matrix44(...);  // matrix
    

    Be very careful, the attribute’s type will be implied by the C++ type of what you assign.

  2. String data may be retrieved directly, and for other types, the delegate supports a get<T>() that retrieves an item of type T:

     std::string colorspace = spec["oiio:ColorSpace"];
     int dither = spec["oiio:dither"].get<int>();
    

This was added in version 2.1.

Public Static Functions

static inline void auto_stride(stride_t &xstride, stride_t &ystride, stride_t &zstride, stride_t channelsize, int nchannels, int width, int height) noexcept

Adjust the stride values, if set to AutoStride, to be the right sizes for contiguous data with the given format, channels, width, height.

static inline void auto_stride(stride_t &xstride, stride_t &ystride, stride_t &zstride, TypeDesc format, int nchannels, int width, int height) noexcept

Adjust the stride values, if set to AutoStride, to be the right sizes for contiguous data with the given format, channels, width, height.

static inline void auto_stride(stride_t &xstride, TypeDesc format, int nchannels) noexcept

Adjust xstride, if set to AutoStride, to be the right size for contiguous data with the given format and channels.

static std::string metadata_val(const ParamValue &p, bool human = false)

For a given parameter p, format the value nicely as a string. If human is true, use especially human-readable explanations (units, or decoding of values) for certain known metadata.


“Deep” pixel data: DeepData

class OIIO::DeepData

A DeepData holds the contents of an image of ``deep’’ pixels (multiple depth samples per pixel).

Public Functions

DeepData()

Construct an empty DeepData.

DeepData(const ImageSpec &spec)

Construct and init from an ImageSpec.

DeepData(const DeepData &d)

Copy constructor.

const DeepData &operator=(const DeepData &d)

Copy assignment.

void clear()

Reset the DeepData to be equivalent to its empty initial state.

void free()

In addition to performing the tasks of clear(), also ensure that all allocated memory has been truly freed.

void init(int64_t npix, int nchan, cspan<TypeDesc> channeltypes, cspan<std::string> channelnames)

Initialize the DeepData with the specified number of pixels, channels, channel types, and channel names, and allocate memory for all the data.

void init(const ImageSpec &spec)

Initialize the DeepData based on the ImageSpec’s total number of pixels, number and types of channels. At this stage, all pixels are assumed to have 0 samples, and no sample data is allocated.

bool initialized() const

Is the DeepData initialized?

bool allocated() const

Has the DeepData fully allocated? If no, it is still very inexpensive to call set_capacity().

int64_t pixels() const

Retrieve the total number of pixels.

int channels() const

Retrieve the number of channels.

string_view channelname(int c) const

Return the name of channel c.

TypeDesc channeltype(int c) const

Retrieve the data type of channel c.

size_t channelsize(int c) const

Return the size (in bytes) of one sample datum of channel c.

size_t samplesize() const

Return the size (in bytes) for all channels of one sample.

int samples(int64_t pixel) const

Retrieve the number of samples for the given pixel index.

void set_samples(int64_t pixel, int samps)

Set the number of samples for the given pixel. This must be called after init().

void set_all_samples(cspan<unsigned int> samples)

Set the number of samples for all pixels. The samples.size() is required to match pixels().

void set_capacity(int64_t pixel, int samps)

Set the capacity of samples for the given pixel. This must be called after init().

int capacity(int64_t pixel) const

Retrieve the capacity (number of allocated samples) for the given pixel index.

void insert_samples(int64_t pixel, int samplepos, int n = 1)

Insert n samples of the specified pixel, betinning at the sample position index. After insertion, the new samples will have uninitialized values.

void erase_samples(int64_t pixel, int samplepos, int n = 1)

Erase n samples of the specified pixel, betinning at the sample position index.

float deep_value(int64_t pixel, int channel, int sample) const

Retrieve the value of the given pixel, channel, and sample index, cast to a float.

uint32_t deep_value_uint(int64_t pixel, int channel, int sample) const

Retrieve the value of the given pixel, channel, and sample index, cast to a uint32.

void set_deep_value(int64_t pixel, int channel, int sample, float value)

Set the value of the given pixel, channel, and sample index, for floating-point channels.

void set_deep_value(int64_t pixel, int channel, int sample, uint32_t value)

Set the value of the given pixel, channel, and sample index, for integer channels.

void *data_ptr(int64_t pixel, int channel, int sample)

Retrieve the pointer to a given pixel/channel/sample, or NULL if there are no samples for that pixel. Use with care, and note that calls to insert_samples and erase_samples can invalidate pointers returned by prior calls to data_ptr.

void get_pointers(std::vector<void*> &pointers) const

Fill in the vector with pointers to the start of the first channel for each pixel.

bool copy_deep_sample(int64_t pixel, int sample, const DeepData &src, int64_t srcpixel, int srcsample)

Copy a deep sample from src to this DeepData. They must have the same channel layout. Return true if ok, false if the operation could not be performed.

bool copy_deep_pixel(int64_t pixel, const DeepData &src, int64_t srcpixel)

Copy an entire deep pixel from src to this DeepData, completely replacing any pixel data for that pixel. They must have the same channel layout. Return true if ok, false if the operation could not be performed.

bool split(int64_t pixel, float depth)

Split all samples of that pixel at the given depth zsplit. Samples that span z (i.e. z < zsplit < zback) will be split into two samples with depth ranges [z,zsplit] and [zsplit,zback] with appropriate changes to their color and alpha values. Samples not spanning zsplit will remain intact. This operation will have no effect if there are not Z and Zback channels present. Return true if any splits occurred, false if the pixel was not modified.

void sort(int64_t pixel)

Sort the samples of the pixel by their Z depth.

void merge_overlaps(int64_t pixel)

Merge any adjacent samples in the pixel that exactly overlap in z range. This is only useful if the pixel has previously been split at all sample starts and ends, and sorted by Z. Note that this may change the number of samples in the pixel.

void merge_deep_pixels(int64_t pixel, const DeepData &src, int srcpixel)

Merge the samples of src’s pixel into this DeepData’s pixel. Return true if ok, false if the operation could not be performed.

float opaque_z(int64_t pixel) const

Return the z depth at which the pixel reaches full opacity.

void occlusion_cull(int64_t pixel)

Remove any samples hidden behind opaque samples.


Global Attributes

These helper functions are not part of any other OpenImageIO class, they just exist in the OpenImageIO namespace as general utilities. (See Miscellaneous Utilities for the corresponding Python bindings.)

bool OIIO::attribute(string_view name, TypeDesc type, const void *val)

OIIO::attribute() sets an global attribute (i.e., a property or option) of OpenImageIO. The name designates the name of the attribute, type describes the type of data, and val is a pointer to memory containing the new value for the attribute.

If the name is known, valid attribute that matches the type specified, the attribute will be set to the new value and attribute() will return true. If name is not recognized, or if the types do not match (e.g., type is TypeFloat but the named attribute is a string), the attribute will not be modified, and attribute() will return false.

The following are the recognized attributes:

  • string options

    This catch-all is simply a comma-separated list of name=value settings of named options, which will be parsed and individually set. For example,

    OIIO::attribute ("options", "threads=4,log_times=1");
    

    Note that if an option takes a string value that must itself contain a comma, it is permissible to enclose the value in either ‘single’ or “double” quotes.

  • int threads

    How many threads to use for operations that can be sped up by being multithreaded. (Examples: simultaneous format conversions of multiple scanlines read together, or many ImageBufAlgo operations.) The default is 0, meaning to use the full available hardware concurrency detected.

    Situations where the main application logic is essentially single threaded (i.e., one top-level call into OIIO at a time) should leave this at the default value, or some reasonable number of cores, thus allowing lots of threads to fill the cores when OIIO has big tasks to complete. But situations where you have many threads at the application level, each of which is expected to be making separate OIIO calls simultaneously, should set this to 1, thus having each calling thread do its own work inside of OIIO rather than spawning new threads with a high overall “fan out.””

  • int exr_threads

    Sets the internal OpenEXR thread pool size. The default is to use as many threads as the amount of hardware concurrency detected. Note that this is separate from the OIIO "threads" attribute.

  • string plugin_searchpath

    Colon-separated list of directories to search for dynamically-loaded format plugins.

  • int read_chunk

    When performing a read_image(), this is the number of scanlines it will attempt to read at a time (some formats are more efficient when reading and decoding multiple scanlines). The default is 256. The special value of 0 indicates that it should try to read the whole image if possible.

  • float[] missingcolor, string missingcolor

    This attribute may either be an array of float values, or a string containing a comma-separated list of the values. Setting this option globally is equivalent to always passing an ImageInput open-with-configuration hint "oiio:missingcolor" with the value.

    When set, it gives some ImageInput readers the option of ignoring any missing tiles or scanlines in the file, and instead of treating the read failure of an individual tile as a full error, will interpret is as an intentionally missing tile and proceed by simply filling in the missing pixels with the color specified. If the first element is negative, it will use the absolute value, but draw alternating diagonal stripes of the color. For example,

    float missing[4] = { -1.0, 0.0, 0.0, 0.0 }; // striped red
    OIIO::attribute ("missingcolor", TypeDesc("float[4]"), &missing);
    

    Note that only some file formats support files with missing tiles or scanlines, and this is only taken as a hint. Please see chap-bundledplugins_ for details on which formats accept a "missingcolor" configuration hint.

  • int debug

    When nonzero, various debug messages may be printed. The default is 0 for release builds, 1 for DEBUG builds (values > 1 are for OIIO developers to print even more debugging information), This attribute but also may be overridden by the OPENIMAGEIO_DEBUG environment variable.

  • int tiff:half

    When nonzero, allows TIFF to write half pixel data. N.B. Most apps may not read these correctly, but OIIO will. That’s why the default is not to support it.

  • int log_times

    When the "log_times" attribute is nonzero, ImageBufAlgo functions are instrumented to record the number of times they were called and the total amount of time spent executing them. It can be overridden by environment variable OPENIMAGEIO_LOG_TIMES. If the value of log_times is 2 or more when the application terminates, the timing report will be printed to stdout upon exit.

    When enabled, there is a slight runtime performance cost due to checking the time at the start and end of each of those function calls, and the locking and recording of the data structure that holds the log information. When the log_times attribute is disabled, there is no additional performance cost.

    The report of totals can be retrieved as the value of the "timing_report" attribute, using OIIO:get_attribute() call.

bool OIIO::attribute(string_view name, int val)
bool OIIO::attribute(string_view name, float val)
bool OIIO::attribute(string_view name, string_view val)

Shortcuts for setting an attribute to a single int, float, or string.

bool OIIO::getattribute(string_view name, TypeDesc type, void *val)

Get the named global attribute of OpenImageIO, store it in *val. Return true if found and it was compatible with the type specified, otherwise return false and do not modify the contents of *val. It is up to the caller to ensure that val points to the right kind and size of storage for the given type.

In addition to being able to retrieve all the attributes that are documented as settable by the OIIO::attribute() call, getattribute() can also retrieve the following read-only attributes:

  • string format_list

  • string input_format_list

  • string output_format_list

    A comma-separated list of all the names of, respectively, all supported image formats, all formats accepted as inputs, and all formats accepted as outputs.

  • string extension_list

    For each format, the format name, followed by a colon, followed by a comma-separated list of all extensions that are presumed to be used for that format. Semicolons separate the lists for formats. For example,

     "tiff:tif;jpeg:jpg,jpeg;openexr:exr"
    

  • string library_list

    For each format that uses a dependent library, the format name, followed by a colon, followed by the name and version of the dependency. Semicolons separate the lists for formats. For example,

     "tiff:LIBTIFF 4.0.4;gif:gif_lib 4.2.3;openexr:OpenEXR 2.2.0"
    

  • string “timing_report” A string containing the report of all the log_times.

  • string hw:simd

  • string oiio:simd (read-only)

    A comma-separated list of hardware CPU features for SIMD (and some other things). The "oiio:simd" attribute is similarly a list of which features this build of OIIO was compiled to support.

    This was added in OpenImageIO 1.8.

  • float resident_memory_used_MB

    This read-only attribute can be used for debugging purposes to report the approximate process memory used (resident) by the application, in MB.

  • string timing_report

    Retrieving this attribute returns the timing report generated by the log_timing attribute (if it was enabled). The report is sorted alphabetically and for each named instrumentation region, prints the number of times it executed, the total runtime, and the average per call, like this:

    IBA::computePixelStats        2   2.69ms  (avg   1.34ms)
    IBA::make_texture             1  74.05ms  (avg  74.05ms)
    IBA::mul                      8   2.42ms  (avg   0.30ms)
    IBA::over                    10  23.82ms  (avg   2.38ms)
    IBA::resize                  20   0.24s   (avg  12.18ms)
    IBA::zero                     8   0.66ms  (avg   0.08ms)
    

bool getattribute(string_view name, int &val)
bool getattribute(string_view name, float &val)
bool getattribute(string_view name, char **val)
bool getattribute(string_view name, std::string &val)

Specialized versions of getattribute() in which the data type is implied by the type of the argument (for single int, float, or string). Two string versions exist: one that retrieves it as a std::string and another that retrieves it as a char *. In all cases, the return value is true if the attribute is found and the requested data type conversion was legal.

EXAMPLES:

int threads;
OIIO::getattribute ("threads", &threads);
std::string path;
OIIO::getattribute ("plugin_searchpath", &path);
int get_int_attribute(string_view name, int defaultvalue = 0)
float get_float_attribute(string_view name, float defaultvalue = 0)
string_view get_string_attribute(string_view name, string_view defaultvalue = "")

Specialized versions of getattribute() for common types, in which the data is returned directly, and a supplied default value is returned if the attribute was not found.

EXAMPLES:

int threads = OIIO::getattribute ("threads", 0);
string_view path = OIIO::getattribute ("plugin_searchpath");

Miscellaneous Utilities

These helper functions are not part of any other OpenImageIO class, they just exist in the OIIO namespace as general utilities. (See Miscellaneous Utilities for the corresponding Python bindings.)

int OIIO::openimageio_version()

Returns a numeric value for the version of OpenImageIO, 10000 for each major version, 100 for each minor version, 1 for each patch. For example, OpenImageIO 1.2.3 would return a value of 10203. One example of how this is useful is for plugins to query the version to be sure they are linked against an adequate version of the library.

std::string OIIO::geterror()

Returns any error string describing what went wrong if ImageInput::create() or ImageOutput::create() failed (since in such cases, the ImageInput or ImageOutput itself does not exist to have its own geterror() function called). This function returns the last error for this particular thread; separate threads will not clobber each other’s global error messages.

void OIIO::declare_imageio_format(const std::string &format_name, ImageInput::Creator input_creator, const char **input_extensions, ImageOutput::Creator output_creator, const char **output_extensions, const char *lib_version)

Register the input and output ‘create’ routines and list of file extensions for a particular format.

bool OIIO::is_imageio_format_name(string_view name)

Is name one of the known format names?


Environment variables

There are a few special environment variables that can be used to control OpenImageIO at times that it is not convenient to set options individually from inside the source code.

OPENIMAGEIO_OPTIONS

Allows you to seed the global OpenImageIO-wide options.

The value of the environment variable should be a comma-separated list of name=value settings. If a value is a string that itself needs to contain commas, it may be enclosed in single or double quotes.

Upon startup, the contents of this environment variable will be passed to a call to:

OIIO::attribute ("options", value);

OPENIMAGEIO_IMAGECACHE_OPTIONS

Allows you to seed the options for any ImageCache created.

The value of the environment variable should be a comma-separated list of name=value settings. If a value is a string that itself needs to contain commas, it may be enclosed in single or double quotes.

Upon creation of any ImageCache, the contents of this environment variable will be passed to a call to:

imagecache->attribute ("options", value);

OPENIMAGEIO_TEXTURE_OPTIONS

Allows you to seed the options for any TextureSystem created.

The value of the environment variable should be a comma-separated list of name=value settings. If a value is a string that itself needs to contain commas, it may be enclosed in single or double quotes.

Upon creation of any TextureSystem, the contents of this environment variable will be passed to a call to:

texturesys->attribute ("options", value);

OPENIMAGEIO_THREADS, CUE_THREADS

Either of these sets the default number of threads that OpenImageIO will use for its thread pool. If both are set, OPENIMAGEIO_THREADS will take precedence. If neither is set, the default will be 0, which means to use as many threads as there are physical cores on the machine.