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 Python Bindings for the corresponding Python bindings.

struct 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 USTRINGHASH#

The hash of a ustring.

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)

constexpr TypeDesc(const TypeDesc &t) noexcept = default#

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 constexpr friend 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 constexpr friend 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 constexpr friend 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 Sections sec-imageoutput-metadata, sec-imageinput-metadata, and the documentation of individual ImageIO plugins for details).

Non-owning string views: string_view#

using string_view = basic_string_view<char>;

string_view is a synonym for a non-mutable string_view<char>.

template<class CharT, class Traits = std::char_traits<CharT>>
class basic_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. This is analogous to C++17 std::string_view, but supports C++14.

Note: string_view is an alias for basic_string_view<char>.

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 a proper c_str() method (which is NOT provided by std::string_view), which would be 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), the usual practice is to call fopen(std::string(my_string_view).c_str()).

Public Functions

inline constexpr basic_string_view() noexcept#

Default ctr.

inline constexpr basic_string_view(const basic_string_view &copy)#

Copy ctr.

inline constexpr basic_string_view(const CharT *chars, size_t len) noexcept#

Construct from char* and length.

inline constexpr basic_string_view(const CharT *chars) noexcept#

Construct from char*, use strlen to determine length.

inline basic_string_view(const 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 constexpr string str() const#

Convert a string_view to a std::string. NOTE: the str() method is not part of the C++17 std::string_view. If strict interchangeability with std::string_view is desired, you might prefer the equivalent idiom std::string(sv).

const CharT *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 &#8212; 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 &#8212; 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::basic_string<CharT, Traits>() const#

Convert a string_view to a std::string.

inline constexpr bool empty() const noexcept#

Is the basic_string_view empty, containing no characters?

inline constexpr const_reference operator[](size_type pos) const#

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

inline constexpr const_reference at(size_t pos) const#

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

inline size_type find(basic_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(basic_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 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 characters 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 algorithms that would work on a “const std::string &” will also work on a ustring.

Note that like a char*, but unlike a std::string, a ustring is not allowed to contain any embedded NUL (‘\0’) characters. When constructing ustrings from a std::string or a string_view, the contents will be truncated at the point of any NUL character. This is done to ensure that ustring::c_str() refers to the same C-style character sequence as the ustring itself or ustring::string().

Usage guidelines:

Compared to standard strings, ustrings have several advantages:

  • Each individual ustring is very small &#8212; 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 &#8212; 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 Types

using rep_t = const char*#

The underlying representation type.

using hash_t = uint64_t#

The hash type.

Public Functions

inline constexpr ustring() noexcept#

Default ctr for ustring &#8212; 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.

ustring(const ustring &str) noexcept = default#

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 explicit ustring(ustringhash hash)#

Construct from a known ustringhash.

~ustring() noexcept = default#

ustring destructor.

inline operator string_view() const noexcept#

Conversion to an OIIO::string_view.

inline explicit operator std::string() const noexcept#

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

inline ustring &assign(const ustring &str)#

Assign a ustring to *this.

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

Assign a substring of a ustring to *this.

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

Assign a std::string to *this.

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

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

inline ustring &assign(const char *str)#

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

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

Assign the first n characters of str to *this.

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

Assign n copies of c to *this.

inline ustring &assign(string_view str)#

Assign a string_view to *this.

ustring &operator=(const ustring &str) noexcept = default#

Assign a ustring to another ustring.

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

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

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

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

inline ustring &operator=(string_view str)#

Assign a string_view to a ustring.

inline 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() noexcept#

Reset to an empty string.

inline size_t length() const noexcept#

Return the number of characters in the string.

inline hash_t hash() const noexcept#

Return a hashed version of the string.

inline ustringhash uhash() const noexcept#

Return a hashed version of the string.

inline size_t size() const noexcept#

Return the number of characters in the string.

inline bool empty() const noexcept#

Is the string empty &#8212; 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 &#8212; 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 &#8212; 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.

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!!!

static ustring from_hash(hash_t hash)#

Return the ustring corresponding to the given hash, or the empty ustring() if there is no registered ustring with that hash. Note that if there are multiple ustrings with the same hash, this will return the first one it finds in the table.

Friends

inline 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 bool operator==(const std::string &a, const ustring &b) noexcept#

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

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

Test for lexicographic equality between string_view a and ustring b.

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

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

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

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

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

Test for lexicographic inequality between string_view a and ustring b.

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

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

inline 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 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 initializing 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).

Subclassed by OIIO::ParamValueSpan

Public Functions

constexpr span() noexcept = default#

Default constructor &#8212; the span will be {nullptr,0}.

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]) noexcept#

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) noexcept#

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) noexcept#

Construct from mutable element std::array.

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

Construct from read-only element std::array.

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

Construct a span from an initializer_list.

constexpr span &operator=(const span &copy) = default#

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 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 &#8212; 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 constexpr friend bool operator== (const ROI &a, const ROI &b) noexcept

Test equality of two ROIs.

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

Test inequality of two ROIs.

inline 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 ImageSpec#

ImageSpec describes the data format of an image &#8212; 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.

inline ImageSpec(string_view format) noexcept#

Constructor: given just the data format (as any type name recognized by the TypeDesc constructor), 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 &#8212; 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.

inline ImageSpec(int xres, int yres, int nchans, string_view fmt) noexcept#

Construct an ImageSpec with the given x and y resolution, number of channels, and pixel data format name (as any type name recognized by the TypeDesc constructor).

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.

inline explicit ImageSpec(const ROI &roi, string_view fmt) noexcept#

Construct an ImageSpec from an ROI giving dimensions, and the name of a data type that will be recognized by the TypeDesc constructor.

void set_format(TypeDesc fmt) noexcept#

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

inline void set_format(string_view fmt) noexcept#

Set the data format, and clear any per-channel format information in channelformats. The fmt may be a string such as "uint8", or any other type name recognized by the TypeDesc constructor.

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.

void attribute(string_view name, string_view value)#

Add a string attribute to extra_attribs.

void attribute(string_view name, ustring value)#

Add a string attribute (passed as a ustring) 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", TypeFloat, "-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=()).

void set_colorspace(string_view name)#

Set the metadata to presume that color space is name (or to assume nothing about the color space if name is empty). The core operation is to set the “oiio:ColorSpace” attribute, but it also removes or alters several other attributes that may hint color space in ways that might be contradictory or no longer true.

Version

2.5

inline bool undefined() const noexcept#

Returns true for a newly initialized (undefined) ImageSpec. (Designated by no channels and undefined data type &#8212; 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 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 &src)#

Copy constructor.

DeepData(const DeepData &src, cspan<TypeDesc> channeltypes)#

Copy constructor with change of channel types.

DeepData(DeepData &&src)#

Move 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.

bool same_channeltypes(const DeepData &other) const#

Does this DeepData have the same channel types as other?

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 a 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 font_searchpath

    Colon-separated (or semicolon-separated) list of directories to search if fonts are needed. (Such as for ImageBufAlgo::render_text().)

  • int use_tbb

    If nonzero and TBB was found and support configured when OIIO was compiled, parallel processing within OIIO (including inside the parallel.h utilities) will try to use TBB by default where possible. If zero, they will try to use OIIO’s native thread pool even if TBB is available.

  • string plugin_searchpath

    Colon-separated (or semicolon-separated) list of directories to search for dynamically-loaded format plugins.

  • int try_all_readers

    When nonzero (the default), a call to ImageInput::create() or ImageInput::open() that does not succeed in opening the file with the format reader implied by the file extension will try all available format readers to see if one of them can open the file. If this is zero, the only reader that will be tried is the one implied by the file extension.

  • 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 dds:bc5normal

    When nonzero, treats BC5/ATI2 format files as normal maps (loads as 3 channels, computes blue from red and green). Default is 0.

  • int openexr:core

    When nonzero, use the new “OpenEXR core C library” when available, for OpenEXR >= 3.1. This is experimental, and currently defaults to 0.

  • int limits:channels (1024)

    When nonzero, the maximum number of color channels in an image. Image files whose headers indicate they have more channels might be assumed to be corrupted or malicious files. In situations when more channels are expected to be encountered, the application should raise this limit. The default is 1024 channels.

  • int limits:imagesize_MB (32768)

    When nonzero, the maximum expected size in MB of the uncompressed pixel data of a single 2D image. Images whose headers indicate that they are larger than this might be assumed to be corrupted or malicious files. The default is 32768 (32 GB of uncompressed pixel data &#8212; equivalent to 64k x 64k x 4 channel x half), or the total amount of total physical memory available to the running process, whichever is smaller. In situations when images larger than this are expected to be encountered, you should raise this limit. Setting the limit to 0 means having no limit.

  • int log_times (0)

    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. The totals will be recorded and can be retrieved as a string by using OIIO::getattribute("timing_report", ...). Additionally, if the value is 2 or more, the timing report will be printed to stdout upon application exit (not advised in contexts where it isn’t ok to print to the terminal via stdout, such as GUI apps or libraries).

    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.

  • oiio:print_uncaught_errors (1)

    If nonzero, upon program exit, any error messages that would have been retrieved by a call to OIIO::geterror(), but never were, will be printed to stdout. While this may seem chaotic, we are presuming that any well-written library or application will proactively check error codes and retrieve errors, so this will never print anything upon exit. But for less sophisticated applications (or users), this is very useful for forcing display of error messages so that users can see relevant errors even if they never check them explicitly, thus self-diagnose their troubles before asking the project dev deam for help. Advanced users who for some reason desire to neither retrieve errors themselves nor have them printed in this manner can disable the behavior by setting this attribute to 0.

  • imagebuf:print_uncaught_errors (1)

    If nonzero, an ImageBuf upon destruction will print any error messages that were never retrieved by its geterror() method. While this may seem chaotic, we are presuming that any well-written library or application will proactively check error codes and retrieve errors, so will never print anything upon destruction. But for less sophisticated applications (or users), this is very useful for forcing display of error messages so that users can see relevant errors even if they never check them explicitly, thus self-diagnose their troubles before asking the project dev deam for help. Advanced users who for some reason desire to neither retrieve errors themselves nor have them printed in this manner can disable the behavior by setting this attribute to 0.

  • imagebuf:use_imagecache (0)

    If nonzero, an ImageBuf that references a file but is not given an ImageCache will read the image through the default ImageCache.

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 version

    The version designation of the OpenImageIO library, as a string.

  • 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 font_list

  • string font_file_list

  • string font_dir_list

    A semicolon-separated list of, respectively, all the fonts that OpenImageIO can find, all the font files that OpenImageIO can find (with full paths), and all the directories that OpenImageIO will search for fonts. (Added in OpenImageIO 2.5)

  • string filter_list

    A semicolon-separated list of all built-in 2D filters. (Added in OpenImageIO 2.5.9)

  • int64_t IB_local_mem_current

  • int64_t IB_local_mem_peak

    Current and peak size (in bytes) of how much memory was consumed by ImageBufs that owned their own allcoated local pixel buffers. (Added in OpenImageIO 2.5.)

  • float IB_total_open_time

  • float IB_total_image_read_time

    Total amount of time (in seconds) that ImageBufs spent opening (including reading header information) and reading pixel data from files that they opened and read themselves (that is, excluding I/O from IBs that were backed by ImageCach. (Added in OpenImageIO 2.5.)

  • string opencolorio_version

    Returns the version (such as “2.2.0”) of OpenColorIO that is used by OpenImageiO, or “0.0.0” if no OpenColorIO support has been enabled. (Added in OpenImageIO 2.4.6)

  • int opencv_version

    Returns the encoded version (such as 40701 for 4.7.1) of the OpenCV that is used by OpenImageIO, or 0 if no OpenCV support has been enabled. (Added in OpenImageIO 2.5.2)

  • string hw:simd

  • string build:simd (read-only)

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

    These were added in OpenImageIO 1.8. The "build:simd" attribute was added added in OpenImageIO 2.5.8 as a preferred synonym for what previously was called "oiio:simd", which is now deprecated.

  • string build:platform (read-only)

    THe name of the OS and CPU architecture that OpenImageIO was built for (e.g., "Linux/x86_64"). (Added in OpenImageIO 2.5.8.)

  • string build:compiler (read-only)

    THe name and version of the compiler used to build OIIO. (Added in OpenImageIO 2.5.8.)

  • string build:dependencies (read-only)

    List of library dependencieis (where known) and versions, separatd by semicolons. (Added in OpenImageIO 2.5.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::get_int_attribute ("threads", 0);
string_view path = OIIO::get_string_attribute ("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.

bool OIIO::has_error()#

Is there a pending global error message waiting to be retrieved?

std::string OIIO::geterror(bool clear = true)#

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, and clear the pending error message unless clear is false; 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?

Startup and Shutdown#

void OIIO::shutdown()#

OIIO::shutdown prepares OpenImageIO for shutdown. Before exiting an application that utilizes OpenImageIO the OIIO::shutdown function must be called, which will perform shutdown of any running thread-pools. Failing to call OIIO::shutdown could lead to a sporadic dead-lock during application shutdown on certain platforms such as Windows.


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_FONTS

A searchpath for finding fonts (for example, when using by ImageBufAlgo::render_text or oiiotool --text). This may contain a list of directories separated by “:” or “;”.

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.