Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color management nomenclature improvements #4479

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/cineon.imageio/cineoninput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,27 +169,26 @@ CineonInput::open(const std::string& name, ImageSpec& newspec)
// This is not very smart, but it seems that as a practical matter,
// all Cineon files are log. So ignore the gamma field and just set
// the color space to KodakLog.
m_spec.attribute("oiio:ColorSpace", "KodakLog");
m_spec.set_colorspace("KodakLog");
#else
// image linearity
// FIXME: making this more robust would require the per-channel transfer
// function functionality which isn't yet in OIIO
switch (m_cin.header.ImageDescriptor(0)) {
case cineon::kRec709Red:
case cineon::kRec709Green:
case cineon::kRec709Blue: m_spec.attribute("oiio:ColorSpace", "Rec709");
case cineon::kRec709Blue: m_spec.set_colorspace("Rec709");
default:
// either grayscale or printing density
if (!std::isinf(m_cin.header.Gamma()) && m_cin.header.Gamma() != 0.0f)
// actual gamma value is read later on
m_spec.attribute("oiio:ColorSpace",
Strutil::fmt::format("Gamma{:.2g}", g));
set_colorspace_rec709_gamma(m_spec, float(m_cin.header.Gamma()));
break;
}

// gamma exponent
if (!std::isinf(m_cin.header.Gamma()) && m_cin.header.Gamma() != 0.0f)
m_spec.attribute("oiio:Gamma", (float)m_cin.header.Gamma());
set_colorspace_rec709_gamma(m_spec, float(m_cin.header.Gamma()));
#endif

// general metadata
Expand Down
2 changes: 1 addition & 1 deletion src/dds.imageio/ddsinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ DDSInput::seek_subimage(int subimage, int miplevel)
// linear color space for HDR-ish images
if (colorspace == nullptr
&& (basetype == TypeDesc::HALF || basetype == TypeDesc::FLOAT))
colorspace = "linear";
colorspace = "lin_rec709";

m_spec.set_colorspace(colorspace);

Expand Down
6 changes: 6 additions & 0 deletions src/doc/imageioapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ just exist in the OIIO namespace as general utilities. (See

.. doxygenfunction:: get_extension_map

.. doxygenfunction:: OIIO::set_colorspace

.. doxygenfunction:: OIIO::set_colorspace_rec709_gamma

.. doxygenfunction:: OIIO::equivalent_colorspace

|

.. _sec-startupshutdown:
Expand Down
4 changes: 2 additions & 2 deletions src/doc/imageoutput.rst
Original file line number Diff line number Diff line change
Expand Up @@ -888,12 +888,12 @@ color space:
.. code-tab:: c++

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

.. code-tab:: py

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

If a particular ``ImageOutput`` implementation is required (by the rules of
the file format it writes) to have pixels in a fixed color space,
Expand Down
48 changes: 47 additions & 1 deletion src/doc/pythonbindings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,6 @@ Section :ref:`sec-ImageSpec`, is replicated for Python.
spec.set_colorspace ("sRGB")



.. py:method:: ImageSpec.undefined ()

Returns `True` for a newly initialized (undefined) ImageSpec.
Expand Down Expand Up @@ -3885,6 +3884,53 @@ details.
formats = oiio.get_string_attribute ("format_list")


.. py:method:: set_colorspace (spec, name)

Set the metadata of the `spec` to presume that color space is `name` (or
to assume nothing about the color space if `name` is empty).

Example:

.. code-block:: python

spec = oiio.ImageSpec()
oiio.set_colorspace (spec, "lin_rec709")

This function was added in OpenImageIO 3.0.


.. py:method:: set_colorspace_rec709_gamma (spec, name)

Set the metadata of the `spec` to reflect Rec709 color primaries and the
given gamma.

Example:

.. code-block:: python

spec = oiio.ImageSpec()
oiio.set_colorspace_rec709_gamma (spec, 2.2)

This function was added in OpenImageIO 3.0.


.. py:method:: equivalent_colorspace (a, b)

Return `True` if the color spaces `a` and `b` are equivalent in the
default active color config.

Example:

.. code-block:: python

# ib is an ImageBuf
cs = ib.spec().get_string_attribute("oiio:ColorSpace")
if oiio.equivalent_colorspace(cs, "sRGB") :
print ("The image is sRGB")

This function was added in OpenImageIO 3.0.


.. py:method:: is_imageio_format_name (name)

Returns True if `name` is the name of a known and supported file format,
Expand Down
17 changes: 9 additions & 8 deletions src/doc/stdmetadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,19 @@ Color information

- `"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.
configuration.
- `"lin_srgb"`, `"lin_rec709"` : Color pixel values are known to be
linear and using sRGB/Rec709 color primaries. Note that `"linear"` is
treated as a synonym.
- `"sRGB"` : Using standard sRGB response and primaries.
- `"Rec709"` : Using standard Rec709 response and primaries.
- `"ACEScg"` : ACEScg color space encoding.
- `"AdobeRGB"` : Adobe RGB color space.
- `"KodakLog"` : Kodak logarithmic color space.
- `"g22_rec709"` : Rec709/sRGB primaries, but using a response curve
corresponding to gamma 2.2.
- `"g18_rec709"` : Rec709/sRGB primaries, but using a response curve
corresponding to gamma 1.8.
- `"GammaX.Y"` : Color values have been gamma corrected
(raised to the power :math:`1/\gamma`). The `X.Y` is the numeric value
of the gamma exponent.
Expand Down Expand Up @@ -230,7 +231,7 @@ Disk file format info/hints
`piz`, `pxr24`, `b44`, `b44a`, `dwaa`, or `dwab`.

he compression name is permitted to have a quality value to be appended
fter a colon, for example `dwaa:60`. The exact meaning and range of
after a colon, for example `dwaa:60`. The exact meaning and range of
he quality value can vary between different file formats and compression
odes, and some don't support quality values at all (it will be ignored if
ot supported, or if out of range).
Expand Down
13 changes: 4 additions & 9 deletions src/dpx.imageio/dpxinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,17 +312,12 @@ DPXInput::seek_subimage(int subimage, int miplevel)

// image linearity
switch (m_dpx.header.Transfer(subimage)) {
case dpx::kLinear: m_spec.attribute("oiio:ColorSpace", "Linear"); break;
case dpx::kLogarithmic:
m_spec.attribute("oiio:ColorSpace", "KodakLog");
break;
case dpx::kITUR709: m_spec.attribute("oiio:ColorSpace", "Rec709"); break;
case dpx::kLinear: m_spec.set_colorspace("Linear"); break;
case dpx::kLogarithmic: m_spec.set_colorspace("KodakLog"); break;
case dpx::kITUR709: m_spec.set_colorspace("Rec709"); break;
case dpx::kUserDefined:
if (!std::isnan(m_dpx.header.Gamma()) && m_dpx.header.Gamma() != 0) {
float g = float(m_dpx.header.Gamma());
m_spec.attribute("oiio:ColorSpace",
Strutil::fmt::format("Gamma{:.2}", g));
m_spec.attribute("oiio:Gamma", g);
set_colorspace_rec709_gamma(m_spec, float(m_dpx.header.Gamma()));
break;
}
// intentional fall-through
Expand Down
2 changes: 1 addition & 1 deletion src/gif.imageio/gifinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ GIFInput::read_subimage_metadata(ImageSpec& newspec)
newspec.nchannels = 4;
newspec.default_channel_names();
newspec.alpha_channel = 4;
newspec.attribute("oiio:ColorSpace", "sRGB");
newspec.set_colorspace("sRGB");

m_previous_disposal_method = m_disposal_method;
m_disposal_method = DISPOSAL_UNSPECIFIED;
Expand Down
10 changes: 2 additions & 8 deletions src/hdr.imageio/hdrinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ HdrInput::RGBE_ReadHeader()
if (!line.size())
return false;

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

Expand All @@ -310,13 +310,7 @@ HdrInput::RGBE_ReadHeader()
// 2.2, not 2.19998.
float g = float(1.0 / tempf);
g = roundf(100.0 * g) / 100.0f;
m_spec.attribute("oiio:Gamma", g);
if (g == 1.0f)
m_spec.attribute("oiio:ColorSpace", "linear");
else
m_spec.attribute("oiio:ColorSpace",
Strutil::fmt::format("Gamma{:.2g}", g));

set_colorspace_rec709_gamma(m_spec, g);
} else if (Strutil::parse_values(line,
"EXPOSURE=", span<float>(tempf))) {
m_spec.attribute("hdr:exposure", tempf);
Expand Down
2 changes: 1 addition & 1 deletion src/heif.imageio/heifinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ HeifInput::seek_subimage(int subimage, int miplevel)
m_himage.get_height(heif_channel_interleaved), bits / 8,
TypeUInt8);

m_spec.attribute("oiio:ColorSpace", "sRGB");
m_spec.set_colorspace("sRGB");

#if LIBHEIF_HAVE_VERSION(1, 12, 0)
// Libheif >= 1.12 added API call to find out if the image is associated
Expand Down
2 changes: 1 addition & 1 deletion src/iconvert/iconvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ adjust_spec(ImageInput* in, ImageOutput* out, const ImageSpec& inspec,

outspec.attribute("oiio:Gamma", gammaval);
if (sRGB) {
outspec.attribute("oiio:ColorSpace", "sRGB");
outspec.set_colorspace("sRGB");
if (!strcmp(in->format_name(), "jpeg")
|| outspec.find_attribute("Exif:ColorSpace"))
outspec.attribute("Exif:ColorSpace", 1);
Expand Down
17 changes: 17 additions & 0 deletions src/include/OpenImageIO/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,23 @@ class OIIO_API ColorConfig {
/// Return a filename or other identifier for the config we're using.
std::string configname() const;

/// Set the spec's 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 3.0
void set_colorspace(ImageSpec& spec, string_view name) const;

/// Set the spec's metadata to reflect Rec709 color primaries and the given
/// gamma. 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 3.0
void set_colorspace_rec709_gamma(ImageSpec& spec, float gamma) const;

/// Return if OpenImageIO was built with OCIO support
static bool supportsOpenColorIO();

Expand Down
12 changes: 5 additions & 7 deletions src/include/OpenImageIO/imagebufalgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1817,12 +1817,9 @@ bool OIIO_API erode (ImageBuf &dst, const ImageBuf &src,
/// transformed, and the fourth channel (if it exists) is presumed to be
/// alpha. Any additional channels will be simply copied unaltered.
///
/// If OIIO was built with OpenColorIO support enabled, then the
/// transformation may be between any two spaces supported by the active
/// The transformation may be between any two spaces supported by the active
/// OCIO configuration, or may be a "look" transformation created by
/// `ColorConfig::createLookTransform`. If OIIO was not built with
/// OpenColorIO support enabled, then the only transformations available are
/// from "sRGB" to "linear" and vice versa.
/// `ColorConfig::createLookTransform`.
///
/// @param fromspace/tospace
/// For the varieties of `colorconvert()` that use named color
Expand Down Expand Up @@ -1927,7 +1924,8 @@ bool OIIO_API colormatrixtransform (ImageBuf &dst, const ImageBuf &src,
/// The looks to apply (comma-separated).
/// @param fromspace/tospace
/// For the varieties of `colorconvert()` that use named color
/// spaces, these specify the color spaces by name.
/// spaces, these specify the color spaces by name. If either
/// is the empty string, it will use `"scene_linear"`.
/// @param unpremult
/// If true, unpremultiply the image (divide the RGB channels by
/// alpha if it exists and is nonzero) before color conversion,
Expand Down Expand Up @@ -1979,7 +1977,7 @@ bool OIIO_API ociolook (ImageBuf &dst, const ImageBuf &src, string_view looks,
/// If `fromspace` is not supplied, it will assume that the
/// source color space is whatever is indicated by the source
/// image's metadata or filename, and if that cannot be deduced,
/// it will be assumed to be scene linear.
/// it will be assumed to be `"scene_linear"`.
/// @param looks
/// The looks to apply (comma-separated). This may be empty,
/// in which case no "look" is used. Note: this parameter value
Expand Down
27 changes: 27 additions & 0 deletions src/include/OpenImageIO/imageio.h
Original file line number Diff line number Diff line change
Expand Up @@ -3254,6 +3254,33 @@ inline string_view get_string_attribute (string_view name,
}


/// Set the metadata of the `spec` 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. This uses the current default
/// color config to adjudicate color space name equivalencies.
///
/// @version 3.0
OIIO_API void set_colorspace(ImageSpec& spec, string_view name);

/// Set the metadata of the `spec` to reflect Rec709 color primaries and the
/// given gamma. 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. This uses the
/// current default color config to adjudicate color space name equivalencies.
///
/// @version 3.0
OIIO_API void set_colorspace_rec709_gamma(ImageSpec& spec, float gamma);


/// Are the two named color spaces equivalent, based on the default color
/// config in effect?
///
/// @version 3.0
OIIO_API bool equivalent_colorspace(string_view a, string_view b);


/// Register the input and output 'create' routines and list of file
/// extensions for a particular format.
OIIO_API void declare_imageio_format (const std::string &format_name,
Expand Down
2 changes: 1 addition & 1 deletion src/jpeg.imageio/jpeginput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ JpgInput::open(const std::string& name, ImageSpec& newspec)
return false;

// Assume JPEG is in sRGB unless the Exif or XMP tags say otherwise.
m_spec.attribute("oiio:ColorSpace", "sRGB");
m_spec.set_colorspace("sRGB");

if (m_cinfo.jpeg_color_space == JCS_CMYK)
m_spec.attribute("jpeg:ColorSpace", "CMYK");
Expand Down
3 changes: 2 additions & 1 deletion src/jpeg.imageio/jpegoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ JpgOutput::open(const std::string& name, const ImageSpec& newspec,
comment.size() + 1);
}

if (Strutil::iequals(m_spec.get_string_attribute("oiio:ColorSpace"), "sRGB"))
if (equivalent_colorspace(m_spec.get_string_attribute("oiio:ColorSpace"),
"sRGB"))
m_spec.attribute("Exif:ColorSpace", 1);

// Write EXIF info
Expand Down
2 changes: 1 addition & 1 deletion src/jpeg2000.imageio/jpeg2000input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ Jpeg2000Input::open(const std::string& name, ImageSpec& p_spec)
m_spec.full_height = m_image->y1;

m_spec.attribute("oiio:BitsPerSample", maxPrecision);
m_spec.attribute("oiio:ColorSpace", "sRGB");
m_spec.set_colorspace("sRGB");

if (m_image->icc_profile_len && m_image->icc_profile_buf) {
m_spec.attribute("ICCProfile",
Expand Down
Loading
Loading