Skip to content

Commit

Permalink
OpenColorIO improvements, especially for 2.2 (#3707)
Browse files Browse the repository at this point in the history
* OpenColorIO improvements, especially for 2.2

* When OIIO builds against OCIO >= 2.2, in the event that there is no
  config supplied (e.g., specified by env `$OCIO`), use he new
  build-in "cg" config to supply a basic set of color spaces and
  transformations. Yay for OCIO 2.2 and its built-in configs!

* New OIIO-understood aliases (regardless of whether they were in the
  config or not): "scene_linear", "srgb", "lin_srgb", and "ACEScg".
  It will do its best to know which, if any, supported color spaces
  are equivalent to these, even if arbitrarily named. For OCIO >= 2.2,
  some trickery is employed to use the new features that can convert
  to built-in config color spaces, transforming several colors in this
  manner and seeing if it gets what would be expected for various
  canonical color spaces.

* `oiiotool --help` now a much abbreviated set of color information
  (just the OCIO version, and the config, and a hint about how to get
  more info).

* A new command `oiiotool --colorconfiginfo` prints the FULL
  inventory of color management information, which now has been
  expanded to reveal the aliases of each color space, print the roles,
  and generally spruce up the output to be much more readable (though
  longer) for large configs.

* New methods for our ColorConfig class:

  - `resolve(name)` turns the name, which could be a color space, an
    alias, a role, or an OIIO-understood universal name (like "sRGB")
    into a canonical color space name.
  - `equivalent(name1,name2)` returns whether or not the two names
    refer, ultimately, to equivalent color spaces (to the best of its
    ability to figure out).

* Some minor changes (including additional `const` qualifiers)
  on the ColorConfig class.

* Make testsuite tests use the built-in OCIO config if OCIO 2.2+ is
  found.

* Build sonar against ocio2.2 so we are primarily testing the new
  code paths.

* For OCIO >= 2.2, because we can count on the built-in configs,
  conditionally compile a bunch of hard-coded color transforms.  These
  will eventually disappear completely, someday, when OCIO 2.2 is the
  minimum supported version.

I think the behavior should all be largely unchanged when running
OIIO in a facility that has a proper OCIO config pointed to by the
`$OCIO` env variable and using color space names contained therein. So
studio users will (I hope) see no changes. For users that have no
OCIO config, or that are writing software that they want to work
reasonably well for common cases no matter what config they encounter
at runtime, this should give more helpful and consistent behavior when
OCIO 2.2+ is used (which I now strongly recommend for anybody not
constrained to 2.1 for compatibility reasons.

But because of the risk and the possible behavioral changes, this is
all currently envisioned as OIIO 2.5 features, and I am not planning
to backport it to the 2.4 release branch. Additionally, a lot has
changed and I expect some additional tweaking and identification of
edge cases I may have missed.

* docs, etc
  • Loading branch information
lgritz authored Dec 18, 2022
1 parent 82a4b08 commit 9c91014
Show file tree
Hide file tree
Showing 41 changed files with 916 additions and 271 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
fail-fast: false
matrix:
include:
- desc: sonar gcc9/C++14 py39 boost1.76 exr3.1 ocio2.1
- desc: sonar gcc9/C++14 py39 boost1.76 exr3.1 ocio2.2
nametag: static-analysis-sonar
os: ubuntu-latest
vfxyear: 2022
Expand All @@ -62,6 +62,7 @@ jobs:
CODECOV=1
CTEST_TEST_TIMEOUT=1200
OIIO_CMAKE_FLAGS="-DOIIO_TEX_IMPLEMENT_VARYINGREF=OFF"
OPENCOLORIO_VERSION=v2.2.0

runs-on: ${{ matrix.os }}
container:
Expand Down
2 changes: 1 addition & 1 deletion src/build-scripts/ci-startup.bash
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export LD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib64:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib:$DYLD_LIBRARY_PATH

export OCIO="$PWD/testsuite/common/OpenColorIO/nuke-default/config.ocio"
# export OCIO="$PWD/testsuite/common/OpenColorIO/nuke-default/config.ocio"
export TESTSUITE_CLEANUP_ON_SUCCESS=${TESTSUITE_CLEANUP_ON_SUCCESS:=1}

mkdir -p build dist
Expand Down
2 changes: 2 additions & 0 deletions src/build-scripts/ci-test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ echo ; echo "Results of oiiotool --version:"
$OpenImageIO_ROOT/bin/oiiotool --version || true
echo ; echo "Results of oiiotool --help:"
$OpenImageIO_ROOT/bin/oiiotool --help || true
echo ; echo "Results of oiiotool --colorconfiginfo:"
$OpenImageIO_ROOT/bin/oiiotool --colorconfiginfo
echo ; echo "Results of oiiotool with no args (should get short help message):"
$OpenImageIO_ROOT/bin/oiiotool || true
echo ; echo "Run unit tests and simple stats:"
Expand Down
9 changes: 8 additions & 1 deletion src/cmake/externalpackages.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,16 @@ checked_find_package (OpenColorIO
DEFINITIONS -DUSE_OCIO=1 -DUSE_OPENCOLORIO=1
# PREFER_CONFIG
)
if (NOT OpenColorIO_FOUND)
if (OpenColorIO_FOUND)
option (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS
"For deveoper debugging/testing ONLY! Disable OCIO 2.2 builtin configs." OFF)
if (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS OR "$ENV{OIIO_DISABLE_BUILTIN_OCIO_CONFIGS}")
add_compile_definitions(OIIO_DISABLE_BUILTIN_OCIO_CONFIGS)
endif ()
else ()
set (OpenColorIO_FOUND 0)
endif ()

checked_find_package (OpenCV 3.0
DEFINITIONS -DUSE_OPENCV=1)

Expand Down
3 changes: 2 additions & 1 deletion src/cmake/testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ macro (oiio_add_tests)
set (_test_disabled 1)
endif ()
endforeach ()
if (0 AND OpenColorIO_VERSION VERSION_GREATER_EQUAL 2.2)
if (OpenColorIO_VERSION VERSION_GREATER_EQUAL 2.2
AND NOT (OIIO_DISABLE_BUILTIN_OCIO_CONFIGS OR "$ENV{OIIO_DISABLE_BUILTIN_OCIO_CONFIGS}"))
# For OCIO 2.2+, have the testsuite use the default built-in config
list (APPEND _ats_ENVIRONMENT "OCIO=ocio://default"
"OIIO_TESTSUITE_OCIOCONFIG=ocio://default")
Expand Down
3 changes: 2 additions & 1 deletion src/doc/builtinplugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,8 @@ preferred except when legacy file access is required.
- encodes the orientation (see Section :ref:`sec-metadata-orientation`)
* - ``oiio:ColorSpace``
- string
- Color space (see Section :ref:`sec-metadata-color`).
- Color space (see Section :ref:`sec-metadata-color`). We currently
assume that any RGBE files encountered are linear with sRGB primaries.
* - ``oiio:Gamma``
- float
- the gamma correction specified in the RGBE header (if it's gamma corrected).
Expand Down
11 changes: 6 additions & 5 deletions src/doc/imageoutput.rst
Original file line number Diff line number Diff line change
Expand Up @@ -906,25 +906,26 @@ The color space hints only describe color channels. You should always pass
alpha, depth, or other non-color channels with linear values.

Here is a simple example of setting up the ``ImageSpec`` when you know that
the pixel values you are writing are linear:
the pixel values you are writing are in your default linear scene-referred
color space:

.. tabs::

.. code-tab:: c++

ImageSpec spec (width, length, channels, format);
spec.attribute ("oiio:ColorSpace", "Linear");
spec.attribute ("oiio:ColorSpace", "scene_linear");

.. code-tab:: py

spec = ImageSpec(width, length, channels, format)
spec.attribute ("oiio:ColorSpace", "Linear")
spec.attribute ("oiio:ColorSpace", "scene_linear")

If a particular ``ImageOutput`` implementation is required (by the rules of
the file format it writes) to have pixels in a particular color space,
the file format it writes) to have pixels in a fixed color space,
then it should try to convert the color values of your image to the right color
space if it is not already in that space. For example, JPEG images
must be in sRGB space, so if you declare your pixels to be ``"Linear"``,
must be in sRGB space, so if you declare your pixels to be ``"scene_linear"``,
the JPEG ``ImageOutput`` will convert to sRGB.

If you leave the ``"oiio:ColorSpace"`` unset, the values will not be
Expand Down
22 changes: 16 additions & 6 deletions src/doc/oiiotool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4004,21 +4004,31 @@ versa).

If you ask for :program:`oiiotool` help (`oiiotool --help`), at the very
bottom you will see the list of all color spaces, looks, and displays that
:program:`oiiotool` knows about.
:program:`oiiotool` knows about. That information (including even more detail)
will be printed with the command `oiiotool --colorconfiginfo`.

.. option:: --iscolorspace <colorspace>
.. option:: --colorconfiginfo

Alter the metadata of the current image so that it thinks its pixels are
in the named color space. This does not alter the pixels of the image,
it only changes :program:`oiiotool`'s understanding of what color space
those those pixels are in.
Print to the console extensive information about the color management
configuration, including the list of all known color spaces (and their
aliases), looks, displays (and their views), as well as which version
of OpenColorIO is being used, and the path to the configuration file.

This command was added in OIIO 2.4.6.

.. option:: --colorconfig <filename>

Instruct :program:`oiiotool` to read an OCIO configuration from a custom
location. Without this, the default is to use the `$OCIO` environment
variable as a guide for the location of the configuration file.

.. option:: --iscolorspace <colorspace>

Alter the metadata of the current image so that it thinks its pixels are
in the named color space. This does not alter the pixels of the image,
it only changes :program:`oiiotool`'s understanding of what color space
those those pixels are in.

.. option:: --colorconvert <fromspace> <tospace>

Replace the current image with a new image whose pixels are transformed
Expand Down
2 changes: 1 addition & 1 deletion src/doc/pythonbindings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3532,7 +3532,7 @@ Color manipulation
.. code-block:: python
Src = ImageBuf ("tahoe.jpg")
Dst = ImageBufAlgo.colorconvert (Src, "sRGB", "linear")
Dst = ImageBufAlgo.colorconvert (Src, "sRGB", "scene_linear")
Expand Down
14 changes: 10 additions & 4 deletions src/doc/stdmetadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,18 @@ Color information

The name of the color space of the color channels. Values include:

- `"Linear"` : Color pixel values are known to be scene-linear and
using facility-default color primaries (presumed sRGB/Rec709 color
primaries if otherwise unknown.
- `"scene_linear"` : Color pixel values are known to be scene-linear and
using facility-default color primaries as defined by the OpenColorIO
configuration. Note that `"linear"` is treated as a synonym. (Note: when
no color config is found, this are presumed to use sRGB/Rec709 color
primaries when built against OpenColorIO 2.1 or earlier, or when no OCIO
support is available, but is presumed to be ACEScg when built against
OCIO 2.2 or higher and using its built-in config.)
- `"lin_srgb"` : Color pixel values are known to be linear and
using sRGB/Rec709 color primaries.
- `"sRGB"` : Using standard sRGB response and primaries.
- `"Rec709"` : Using standard Rec709 response and primaries.
- `"ACES"` : ACES color space encoding.
- `"ACEScg"` : ACEScg color space encoding.
- `"AdobeRGB"` : Adobe RGB color space.
- `"KodakLog"` : Kodak logarithmic color space.
- `"GammaX.Y"` : Color values have been gamma corrected
Expand Down
5 changes: 4 additions & 1 deletion src/hdr.imageio/hdrinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@ HdrInput::RGBE_ReadHeader()
if (!line.size())
return false;

m_spec.attribute("oiio:ColorSpace", "linear"); // presume linear
m_spec.attribute("oiio:ColorSpace", "lin_srgb");
// presume linear w/ srgb primaries -- seems like the safest assumption
// for this old file format.

bool found_FORMAT_line = false;
for (int nlines = 0; nlines < 100 /* safety */; ++nlines) {
if (line.size() == 0 || line[0] == '\n') // stop at blank line
Expand Down
33 changes: 27 additions & 6 deletions src/include/OpenImageIO/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class OIIO_API ColorConfig {
/// This routine will return the error string (and by default, clear any
/// error flags). If no error has occurred since the last time
/// geterror() was called, it will return an empty string.
std::string geterror(bool clear = true);
std::string geterror(bool clear = true) const;

/// Get the number of ColorSpace(s) defined in this configuration
int getNumColorSpaces() const;
Expand Down Expand Up @@ -309,6 +309,15 @@ class OIIO_API ColorConfig {
/// is found.
string_view parseColorSpaceFromString(string_view str) const;

/// Turn the name, which could be a color space, an alias, a role, or
/// an OIIO-understood universal name (like "sRGB") into a canonical
/// color space name. If the name is not recognized, return "".
string_view resolve(string_view name) const;

/// Are the two color space names/aliases/roles equivalent?
bool equivalent(string_view color_space,
string_view other_color_space) const;

/// Return a filename or other identifier for the config we're using.
std::string configname() const;

Expand All @@ -325,6 +334,13 @@ class OIIO_API ColorConfig {
/// OCIO support is available.
static int OpenColorIO_version_hex();

/// Return a default ColorConfig, which is a singleton that will be
/// created the first time it is needed. It will be initialized with the
/// OCIO environment variable, if it exists, or the OCIO built-in config
/// (for OCIO >= 2.2). If neither of those is possible, it will be
/// initialized with a built-in minimal config.
static const ColorConfig& default_colorconfig();

private:
ColorConfig(const ColorConfig&) = delete;
ColorConfig& operator=(const ColorConfig&) = delete;
Expand All @@ -336,7 +352,8 @@ class OIIO_API ColorConfig {



/// Utility -- convert sRGB value to linear
/// Utility -- convert sRGB value to linear transfer function, without
/// any change in color primaries.
/// http://en.wikipedia.org/wiki/SRGB
inline float
sRGB_to_linear(float x)
Expand All @@ -356,7 +373,8 @@ sRGB_to_linear(const simd::vfloat4& x)
}
#endif

/// Utility -- convert linear value to sRGB
/// Utility -- convert linear value to sRGB transfer function, without
/// any change in color primaries.
inline float
linear_to_sRGB(float x)
{
Expand All @@ -366,7 +384,8 @@ linear_to_sRGB(float x)


#ifndef __CUDA_ARCH__
/// Utility -- convert linear value to sRGB
/// Utility -- convert linear value to sRGB transfer function, without
/// any change in color primaries.
inline simd::vfloat4
linear_to_sRGB(const simd::vfloat4& x)
{
Expand All @@ -377,7 +396,8 @@ linear_to_sRGB(const simd::vfloat4& x)
#endif


/// Utility -- convert Rec709 value to linear
/// Utility -- convert Rec709 value to linear transfer function, without
/// any change in color primaries.
/// http://en.wikipedia.org/wiki/Rec._709
inline float
Rec709_to_linear(float x)
Expand All @@ -388,7 +408,8 @@ Rec709_to_linear(float x)
return powf((x + 0.099f) * (1.0f / 1.099f), (1.0f / 0.45f));
}

/// Utility -- convert linear value to Rec709
/// Utility -- convert linear value to Rec709 transfer function, without
/// any change in color primaries.
inline float
linear_to_Rec709(float x)
{
Expand Down
20 changes: 10 additions & 10 deletions src/include/OpenImageIO/imagebufalgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1824,7 +1824,7 @@ bool OIIO_API erode (ImageBuf &dst, const ImageBuf &src,
ImageBuf OIIO_API colorconvert (const ImageBuf &src,
string_view fromspace, string_view tospace, bool unpremult=true,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);

/// Transform using a ColorProcessor, returning an ImageBuf result.
Expand All @@ -1835,7 +1835,7 @@ ImageBuf OIIO_API colorconvert (const ImageBuf &src,
bool OIIO_API colorconvert (ImageBuf &dst, const ImageBuf &src,
string_view fromspace, string_view tospace, bool unpremult=true,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);

/// Transform using a ColorProcessor, storing reults into an existing ImageBuf.
Expand Down Expand Up @@ -1925,14 +1925,14 @@ ImageBuf OIIO_API ociolook (const ImageBuf &src, string_view looks,
string_view fromspace, string_view tospace,
bool unpremult=true, bool inverse=false,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);
/// Write to an existing image `dst` (allocating if it is uninitialized).
bool OIIO_API ociolook (ImageBuf &dst, const ImageBuf &src, string_view looks,
string_view fromspace, string_view tospace,
bool unpremult=true, bool inverse=false,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);


Expand Down Expand Up @@ -1982,15 +1982,15 @@ ImageBuf OIIO_API ociodisplay (const ImageBuf &src,
string_view fromspace="", string_view looks="",
bool unpremult=true, bool inverse=false,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);
/// Write to an existing image `dst` (allocating if it is uninitialized).
bool OIIO_API ociodisplay (ImageBuf &dst, const ImageBuf &src,
string_view display, string_view view,
string_view fromspace="", string_view looks="",
bool unpremult=true, bool inverse=false,
string_view context_key="", string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);

#ifndef OIIO_DOXYGEN
Expand All @@ -2000,15 +2000,15 @@ ImageBuf OIIO_API ociodisplay (const ImageBuf &src,
string_view fromspace, string_view looks,
bool unpremult,
string_view context_key, string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);
// OIIO_DEPRECATED("prefer the kind that takes an `inverse` parameter (2.5)")
bool OIIO_API ociodisplay (ImageBuf &dst, const ImageBuf &src,
string_view display, string_view view,
string_view fromspace, string_view looks,
bool unpremult,
string_view context_key, string_view context_value="",
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);
#endif

Expand Down Expand Up @@ -2039,13 +2039,13 @@ bool OIIO_API ociodisplay (ImageBuf &dst, const ImageBuf &src,
ImageBuf OIIO_API ociofiletransform (const ImageBuf &src,
string_view name,
bool unpremult=true, bool inverse=false,
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);
/// Write to an existing image `dst` (allocating if it is uninitialized).
bool OIIO_API ociofiletransform (ImageBuf &dst, const ImageBuf &src,
string_view name,
bool unpremult=true, bool inverse=false,
ColorConfig *colorconfig=nullptr,
const ColorConfig* colorconfig = nullptr,
ROI roi={}, int nthreads=0);


Expand Down
Loading

0 comments on commit 9c91014

Please sign in to comment.