diff --git a/src/doc/pythonbindings.rst b/src/doc/pythonbindings.rst index 35a73ff00b..d07735eed2 100644 --- a/src/doc/pythonbindings.rst +++ b/src/doc/pythonbindings.rst @@ -3888,6 +3888,73 @@ sections) work with deep inputs:: | +.. _sec-pythoncolorconfig: + + +ColorConfig +=========== + +The `ColorConfig` class that represents the set of color transformations that +are allowed. + +If OpenColorIO is enabled at build time, this configuration is loaded at +runtime, allowing the user to have complete control of all color transformation +math. See the +`OpenColorIO documentation `_ for details. + +If OpenColorIO is not enabled at build time, a generic color configuration +is provided for minimal color support. + +.. + TODO: The documentation for this class is incomplete. + +.. py:method:: get_cicp (colorspace) + + Find CICP code corresponding to the colorspace. + Return a sequence of 4 ints, or None if not found. + + Example: + + .. code-block:: python + + colorconfig = oiio.ColorConfig() + cicp = colorconfig.get_cicp("pq_rec2020_display") + if cicp: + primaries, transfer, matrix, color_range = cicp + + This function was added in OpenImageIO 3.1. + + +.. py:method:: get_color_interop_id (colorspace) + + Find color interop ID for the given colorspace. + Returns empty string if not found. + + Example: + + .. code-block:: python + + colorconfig = oiio.ColorConfig() + interop_id = colorconfig.get_color_interop_id("Rec.2100-PQ - Display") + + This function was added in OpenImageIO 3.1. + + +.. py:method:: get_color_interop_id (cicp) + + Find color interop ID corresponding to the CICP code. + Returns empty string if not found. + + Example: + + .. code-block:: python + + colorconfig = oiio.ColorConfig() + interop_id = colorconfig.get_color_interop_id([9, 16, 9, 1]) + + This function was added in OpenImageIO 3.1. + + .. _sec-pythonmiscapi: Miscellaneous Utilities diff --git a/src/ffmpeg.imageio/ffmpeginput.cpp b/src/ffmpeg.imageio/ffmpeginput.cpp index 8eec06b08f..26227dd61c 100644 --- a/src/ffmpeg.imageio/ffmpeginput.cpp +++ b/src/ffmpeg.imageio/ffmpeginput.cpp @@ -71,6 +71,7 @@ receive_frame(AVCodecContext* avctx, AVFrame* picture, AVPacket* avpkt) +#include #include #include #include @@ -549,6 +550,11 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec) m_codec_context->colorspace, m_codec_context->color_range == AVCOL_RANGE_MPEG ? 0 : 1 }; m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp); + const ColorConfig& colorconfig(ColorConfig::default_colorconfig()); + string_view interop_id = colorconfig.get_color_interop_id(cicp); + if (!interop_id.empty()) + m_spec.attribute("oiio:ColorSpace", interop_id); + m_nsubimages = m_frames; spec = m_spec; m_filename = name; diff --git a/src/heif.imageio/heifinput.cpp b/src/heif.imageio/heifinput.cpp index 4ba8e2fb61..349bcdb1d4 100644 --- a/src/heif.imageio/heifinput.cpp +++ b/src/heif.imageio/heifinput.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // https://github.com/AcademySoftwareFoundation/OpenImageIO +#include #include #include #include @@ -292,6 +293,11 @@ HeifInput::seek_subimage(int subimage, int miplevel) int(nclx->matrix_coefficients), int(nclx->full_range_flag ? 1 : 0) }; m_spec.attribute("CICP", TypeDesc(TypeDesc::INT, 4), cicp); + const ColorConfig& colorconfig( + ColorConfig::default_colorconfig()); + string_view interop_id = colorconfig.get_color_interop_id(cicp); + if (!interop_id.empty()) + m_spec.attribute("oiio:ColorSpace", interop_id); } heif_nclx_color_profile_free(nclx); } diff --git a/src/heif.imageio/heifoutput.cpp b/src/heif.imageio/heifoutput.cpp index 6ed1dbb439..9998ab5a5f 100644 --- a/src/heif.imageio/heifoutput.cpp +++ b/src/heif.imageio/heifoutput.cpp @@ -3,6 +3,7 @@ // https://github.com/AcademySoftwareFoundation/OpenImageIO +#include #include #include #include @@ -249,10 +250,13 @@ HeifOutput::close() std::unique_ptr nclx(heif_nclx_color_profile_alloc(), heif_nclx_color_profile_free); - const ParamValue* p = m_spec.find_attribute("CICP", - TypeDesc(TypeDesc::INT, 4)); - if (p) { - const int* cicp = static_cast(p->data()); + const ColorConfig& colorconfig(ColorConfig::default_colorconfig()); + const ParamValue* p = m_spec.find_attribute("CICP", + TypeDesc(TypeDesc::INT, 4)); + string_view colorspace = m_spec.get_string_attribute("oiio:ColorSpace"); + cspan cicp = (p) ? p->as_cspan() + : colorconfig.get_cicp(colorspace); + if (!cicp.empty()) { nclx->color_primaries = heif_color_primaries(cicp[0]); nclx->transfer_characteristics = heif_transfer_characteristics( cicp[1]); diff --git a/src/include/OpenImageIO/color.h b/src/include/OpenImageIO/color.h index 46676efe76..99eba56396 100644 --- a/src/include/OpenImageIO/color.h +++ b/src/include/OpenImageIO/color.h @@ -402,6 +402,24 @@ class OIIO_API ColorConfig { bool equivalent(string_view color_space, string_view other_color_space) const; + /// Find CICP code corresponding to the colorspace. + /// Return a cspan of 4 ints, or an empty span if not found. + /// + /// @version 3.1 + cspan get_cicp(string_view colorspace) const; + + /// Find color interop ID for the given colorspace. + /// Returns empty string if not found. + /// + /// @version 3.1 + string_view get_color_interop_id(string_view colorspace) const; + + /// Find color interop ID corresponding to the CICP code. + /// Returns empty string if not found. + /// + /// @version 3.1 + string_view get_color_interop_id(const int cicp[4]) const; + /// Return a filename or other identifier for the config we're using. std::string configname() const; diff --git a/src/libOpenImageIO/color_ocio.cpp b/src/libOpenImageIO/color_ocio.cpp index 26f45c8d2b..a365cd9b48 100644 --- a/src/libOpenImageIO/color_ocio.cpp +++ b/src/libOpenImageIO/color_ocio.cpp @@ -1997,6 +1997,173 @@ ColorConfig::parseColorSpaceFromString(string_view str) const } +////////////////////////////////////////////////////////////////////////// +// +// Color Interop ID + +namespace { +enum class CICPPrimaries : int { + Rec709 = 1, + Rec2020 = 9, + XYZD65 = 10, + P3D65 = 12, +}; + +enum class CICPTransfer : int { + BT709 = 1, + Gamma22 = 4, + Linear = 8, + sRGB = 13, + PQ = 16, + Gamma26 = 17, + HLG = 18, +}; + +enum class CICPMatrix : int { + RGB = 0, + BT709 = 1, + Unspecified = 2, + Rec2020_NCL = 9, + Rec2020_CL = 10, +}; + +enum class CICPRange : int { + Narrow = 0, + Full = 1, +}; + +struct ColorInteropID { + constexpr ColorInteropID(const char* interop_id) + : interop_id(interop_id) + , cicp({ 0, 0, 0, 0 }) + , has_cicp(false) + { + } + + constexpr ColorInteropID(const char* interop_id, CICPPrimaries primaries, + CICPTransfer transfer, CICPMatrix matrix) + : interop_id(interop_id) + , cicp({ int(primaries), int(transfer), int(matrix), + int(CICPRange::Full) }) + , has_cicp(true) + { + } + + const char* interop_id; + std::array cicp; + bool has_cicp; +}; + +// Mapping between color interop ID and CICP, based on Color Interop Forum +// recommendations. +constexpr ColorInteropID color_interop_ids[] = { + // Scene referred interop IDs first so they are the default in automatic + // conversion from CICP to interop ID. Some are not display color spaces + // at all, but can be represented by CICP anyway. + { "lin_ap1_scene" }, + { "lin_ap0_scene" }, + { "lin_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::Linear, + CICPMatrix::BT709 }, + { "lin_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::Linear, + CICPMatrix::BT709 }, + { "lin_rec2020_scene", CICPPrimaries::Rec2020, CICPTransfer::Linear, + CICPMatrix::Rec2020_CL }, + { "lin_adobergb_scene" }, + { "lin_ciexyzd65_scene", CICPPrimaries::XYZD65, CICPTransfer::Linear, + CICPMatrix::Unspecified }, + { "srgb_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::sRGB, + CICPMatrix::BT709 }, + { "g22_rec709_scene", CICPPrimaries::Rec709, CICPTransfer::Gamma22, + CICPMatrix::BT709 }, + { "g18_rec709_scene" }, + { "srgb_ap1_scene" }, + { "g22_ap1_scene" }, + { "srgb_p3d65_scene", CICPPrimaries::P3D65, CICPTransfer::sRGB, + CICPMatrix::BT709 }, + { "g22_adobergb_scene" }, + { "data" }, + { "unknown" }, + + // Display referred interop IDs. + { "srgb_rec709_display", CICPPrimaries::Rec709, CICPTransfer::sRGB, + CICPMatrix::BT709 }, + { "g24_rec709_display", CICPPrimaries::Rec709, CICPTransfer::BT709, + CICPMatrix::BT709 }, + { "srgb_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB, + CICPMatrix::BT709 }, + { "srgbe_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::sRGB, + CICPMatrix::BT709 }, + { "pq_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::PQ, + CICPMatrix::Rec2020_NCL }, + { "pq_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::PQ, + CICPMatrix::Rec2020_NCL }, + { "hlg_rec2020_display", CICPPrimaries::Rec2020, CICPTransfer::HLG, + CICPMatrix::Rec2020_NCL }, + // No CICP mapping to keep previous behavior unchanged, as Gamma 2.2 + // display is more likely meant to be written as sRGB. On read the + // scene referred interop ID will be used. + { "g22_rec709_display", + /* CICPPrimaries::Rec709, CICPTransfer::Gamma22, CICPMatrix::BT709 */ }, + // No CICP code for Adobe RGB primaries. + { "g22_adobergb_display" }, + { "g26_p3d65_display", CICPPrimaries::P3D65, CICPTransfer::Gamma26, + CICPMatrix::BT709 }, + { "g26_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::Gamma26, + CICPMatrix::Unspecified }, + { "pq_xyzd65_display", CICPPrimaries::XYZD65, CICPTransfer::PQ, + CICPMatrix::Unspecified }, +}; +} // namespace + +string_view +ColorConfig::get_color_interop_id(string_view colorspace) const +{ + if (colorspace.empty()) + return ""; +#if OCIO_VERSION_HEX >= MAKE_OCIO_VERSION_HEX(2, 5, 0) + if (getImpl()->config_ && !disable_ocio) { + OCIO::ConstColorSpaceRcPtr c = getImpl()->config_->getColorSpace( + std::string(resolve(colorspace)).c_str()); + const char* interop_id = (c) ? c->getInteropID() : nullptr; + if (interop_id) { + return interop_id; + } + } +#endif + for (const ColorInteropID& interop : color_interop_ids) { + if (equivalent(colorspace, interop.interop_id)) { + return interop.interop_id; + } + } + return ""; +} + +string_view +ColorConfig::get_color_interop_id(const int cicp[4]) const +{ + for (const ColorInteropID& interop : color_interop_ids) { + if (interop.has_cicp && interop.cicp[0] == cicp[0] + && interop.cicp[1] == cicp[1]) { + return interop.interop_id; + } + } + return ""; +} + +cspan +ColorConfig::get_cicp(string_view colorspace) const +{ + string_view interop_id = get_color_interop_id(colorspace); + if (!interop_id.empty()) { + for (const ColorInteropID& interop : color_interop_ids) { + if (interop.has_cicp && interop_id == interop.interop_id) { + return interop.cicp; + } + } + } + return cspan(); +} + ////////////////////////////////////////////////////////////////////////// // diff --git a/src/png.imageio/png_pvt.h b/src/png.imageio/png_pvt.h index a6a7c06609..3c103eb836 100644 --- a/src/png.imageio/png_pvt.h +++ b/src/png.imageio/png_pvt.h @@ -330,8 +330,12 @@ read_info(png_structp& sp, png_infop& ip, int& bit_depth, int& color_type, { png_byte pri = 0, trc = 0, mtx = 0, vfr = 0; if (png_get_cICP(sp, ip, &pri, &trc, &mtx, &vfr)) { - int cicp[4] = { pri, trc, mtx, vfr }; + const int cicp[4] = { pri, trc, mtx, vfr }; spec.attribute(CICP_ATTR, TypeDesc(TypeDesc::INT, 4), cicp); + const ColorConfig& colorconfig(ColorConfig::default_colorconfig()); + string_view interop_id = colorconfig.get_color_interop_id(cicp); + if (!interop_id.empty()) + spec.attribute("oiio:ColorSpace", interop_id); } } #endif @@ -608,7 +612,8 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec, string_view colorspace = spec.get_string_attribute("oiio:ColorSpace", "srgb_rec709_scene"); const ColorConfig& colorconfig(ColorConfig::default_colorconfig()); - srgb = false; + OIIO_MAYBE_UNUSED bool wrote_colorspace = false; + srgb = false; if (colorconfig.equivalent(colorspace, "srgb_rec709_scene")) { srgb = true; gamma = 1.0f; @@ -628,7 +633,8 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec, if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG gAMA chunk"; png_set_gAMA(sp, ip, 1.0); - srgb = false; + srgb = false; + wrote_colorspace = true; } else if (Strutil::istarts_with(colorspace, "Gamma")) { // Back compatible, this is DEPRECATED(3.1) Strutil::parse_word(colorspace); @@ -638,24 +644,28 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec, if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG gAMA chunk"; png_set_gAMA(sp, ip, 1.0f / gamma); - srgb = false; + srgb = false; + wrote_colorspace = true; } else if (colorconfig.equivalent(colorspace, "g22_rec709_scene")) { gamma = 2.2f; if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG gAMA chunk"; png_set_gAMA(sp, ip, 1.0f / gamma); - srgb = false; + srgb = false; + wrote_colorspace = true; } else if (colorconfig.equivalent(colorspace, "g18_rec709_scene")) { gamma = 1.8f; if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG gAMA chunk"; png_set_gAMA(sp, ip, 1.0f / gamma); - srgb = false; + srgb = false; + wrote_colorspace = true; } else if (colorconfig.equivalent(colorspace, "srgb_rec709_scene")) { if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG gAMA and cHRM chunk"; png_set_sRGB_gAMA_and_cHRM(sp, ip, PNG_sRGB_INTENT_ABSOLUTE); - srgb = true; + srgb = true; + wrote_colorspace = true; } // Write ICC profile, if we have anything @@ -667,8 +677,10 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec, return "Could not set PNG iCCP chunk"; unsigned char* icc_profile = (unsigned char*)icc_profile_parameter->data(); - if (icc_profile && length) + if (icc_profile && length) { png_set_iCCP(sp, ip, "Embedded Profile", 0, icc_profile, length); + wrote_colorspace = true; + } } if (false && !spec.find_attribute("DateTime")) { @@ -724,13 +736,17 @@ write_info(png_structp& sp, png_infop& ip, int& color_type, ImageSpec& spec, } #ifdef PNG_cICP_SUPPORTED + // Only automatically determine CICP from oiio::ColorSpace if we didn't + // write colorspace metadata yet. const ParamValue* p = spec.find_attribute(CICP_ATTR, TypeDesc(TypeDesc::INT, 4)); - if (p) { - const int* int_vals = static_cast(p->data()); + cspan cicp = (p) ? p->as_cspan() + : (!wrote_colorspace) ? colorconfig.get_cicp(colorspace) + : cspan(); + if (!cicp.empty()) { png_byte vals[4]; for (int i = 0; i < 4; ++i) - vals[i] = static_cast(int_vals[i]); + vals[i] = static_cast(cicp[i]); if (setjmp(png_jmpbuf(sp))) // NOLINT(cert-err52-cpp) return "Could not set PNG cICP chunk"; // libpng will only write the chunk if the third byte is 0 diff --git a/src/python/py_colorconfig.cpp b/src/python/py_colorconfig.cpp index 129d089502..35f8e304e8 100644 --- a/src/python/py_colorconfig.cpp +++ b/src/python/py_colorconfig.cpp @@ -4,6 +4,7 @@ #include "py_oiio.h" #include +#include #include namespace PyOpenImageIO { @@ -160,6 +161,24 @@ declare_colorconfig(py::module& m) return self.equivalent(color_space, other_color_space); }, "color_space"_a, "other_color_space"_a) + .def("get_color_interop_id", + [](const ColorConfig& self, const std::string& colorspace) { + return std::string(self.get_color_interop_id(colorspace)); + }) + .def("get_color_interop_id", + [](const ColorConfig& self, const std::array cicp) { + return std::string(self.get_color_interop_id(cicp.data())); + }) + .def("get_cicp", + [](const ColorConfig& self, const std::string& colorspace) + -> std::optional> { + cspan cicp = self.get_cicp(colorspace); + if (!cicp.empty()) { + return std::array( + { cicp[0], cicp[1], cicp[2], cicp[3] }); + } + return std::nullopt; + }) .def("configname", &ColorConfig::configname) .def_static("default_colorconfig", []() -> const ColorConfig& { return ColorConfig::default_colorconfig(); diff --git a/src/python/stubs/OpenImageIO/__init__.pyi b/src/python/stubs/OpenImageIO/__init__.pyi index 200be7d774..88681897d6 100644 --- a/src/python/stubs/OpenImageIO/__init__.pyi +++ b/src/python/stubs/OpenImageIO/__init__.pyi @@ -207,6 +207,11 @@ class ColorConfig: def getRoles(self) -> list[str]: ... def getViewNameByIndex(self, display: str = ..., *, index: typing.SupportsInt) -> str: ... def getViewNames(self, display: str = ...) -> list[str]: ... + def get_cicp(self, *args, **kwargs): ... + @overload + def get_color_interop_id(self, arg0: str, /) -> str: ... + @overload + def get_color_interop_id(self, arg0, /) -> str: ... def geterror(self) -> str: ... def parseColorSpaceFromString(self, arg0: str, /) -> str: ... def resolve(self, name: str) -> str: ... diff --git a/testsuite/ffmpeg/ref/out-ffmpeg6.1.txt b/testsuite/ffmpeg/ref/out-ffmpeg6.1.txt index 0d037e3cc5..1f1258b343 100644 --- a/testsuite/ffmpeg/ref/out-ffmpeg6.1.txt +++ b/testsuite/ffmpeg/ref/out-ffmpeg6.1.txt @@ -96,6 +96,7 @@ ref/vp9_rec2100_pq.mkv : 384 x 216, 3 channel, uint10 FFmpeg movie FramesPerSecond: 24/1 (24) ffmpeg:codec_name: "Google VP9" oiio:BitsPerSample: 10 + oiio:ColorSpace: "pq_rec2020_display" oiio:Movie: 1 oiio:subimages: 2 subimage 1: 384 x 216, 3 channel, uint10 FFmpeg movie @@ -106,5 +107,6 @@ ref/vp9_rec2100_pq.mkv : 384 x 216, 3 channel, uint10 FFmpeg movie FramesPerSecond: 24/1 (24) ffmpeg:codec_name: "Google VP9" oiio:BitsPerSample: 10 + oiio:ColorSpace: "pq_rec2020_display" oiio:Movie: 1 oiio:subimages: 2 diff --git a/testsuite/ffmpeg/ref/out-ffmpeg8.0.txt b/testsuite/ffmpeg/ref/out-ffmpeg8.0.txt index a4b503edca..28084a22e3 100644 --- a/testsuite/ffmpeg/ref/out-ffmpeg8.0.txt +++ b/testsuite/ffmpeg/ref/out-ffmpeg8.0.txt @@ -96,6 +96,7 @@ ref/vp9_rec2100_pq.mkv : 384 x 216, 3 channel, uint10 FFmpeg movie FramesPerSecond: 24/1 (24) ffmpeg:codec_name: "Google VP9" oiio:BitsPerSample: 10 + oiio:ColorSpace: "pq_rec2020_display" oiio:Movie: 1 oiio:subimages: 2 subimage 1: 384 x 216, 3 channel, uint10 FFmpeg movie @@ -106,5 +107,6 @@ ref/vp9_rec2100_pq.mkv : 384 x 216, 3 channel, uint10 FFmpeg movie FramesPerSecond: 24/1 (24) ffmpeg:codec_name: "Google VP9" oiio:BitsPerSample: 10 + oiio:ColorSpace: "pq_rec2020_display" oiio:Movie: 1 oiio:subimages: 2 diff --git a/testsuite/heif/ref/out-libheif1.12-orient.txt b/testsuite/heif/ref/out-libheif1.12-orient.txt index 78b7d9fd6f..875e3ac54e 100644 --- a/testsuite/heif/ref/out-libheif1.12-orient.txt +++ b/testsuite/heif/ref/out-libheif1.12-orient.txt @@ -64,7 +64,17 @@ cicp_pq.avif : 16 x 16, 4 channel, uint10 heif Exif:FlashPixVersion: "0100" heif:UnassociatedAlpha: 1 oiio:BitsPerSample: 10 - oiio:ColorSpace: "srgb_rec709_scene" + oiio:ColorSpace: "pq_rec2020_display" +Reading colorspace_hlg.avif +colorspace_hlg.avif : 16 x 16, 4 channel, uint10 heif + SHA-1: 0F3CAB52D479BC23E9C981DBADDFEF1F792E5540 + channel list: R, G, B, A + CICP: 9, 18, 9, 1 + Exif:ExifVersion: "0230" + Exif:FlashPixVersion: "0100" + heif:UnassociatedAlpha: 1 + oiio:BitsPerSample: 10 + oiio:ColorSpace: "hlg_rec2020_display" Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic ../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E diff --git a/testsuite/heif/ref/out-libheif1.4.txt b/testsuite/heif/ref/out-libheif1.4.txt index bd0ff14603..9d8304f14a 100644 --- a/testsuite/heif/ref/out-libheif1.4.txt +++ b/testsuite/heif/ref/out-libheif1.4.txt @@ -64,7 +64,17 @@ cicp_pq.avif : 16 x 16, 4 channel, uint10 heif Exif:FlashPixVersion: "0100" heif:UnassociatedAlpha: 1 oiio:BitsPerSample: 10 - oiio:ColorSpace: "srgb_rec709_scene" + oiio:ColorSpace: "pq_rec2020_display" +Reading colorspace_hlg.avif +colorspace_hlg.avif : 16 x 16, 4 channel, uint10 heif + SHA-1: 0F3CAB52D479BC23E9C981DBADDFEF1F792E5540 + channel list: R, G, B, A + CICP: 9, 18, 9, 1 + Exif:ExifVersion: "0230" + Exif:FlashPixVersion: "0100" + heif:UnassociatedAlpha: 1 + oiio:BitsPerSample: 10 + oiio:ColorSpace: "hlg_rec2020_display" Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic ../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E diff --git a/testsuite/heif/ref/out-libheif1.5.txt b/testsuite/heif/ref/out-libheif1.5.txt index 39398f71cd..9dfd4ff23d 100644 --- a/testsuite/heif/ref/out-libheif1.5.txt +++ b/testsuite/heif/ref/out-libheif1.5.txt @@ -64,7 +64,17 @@ cicp_pq.avif : 16 x 16, 4 channel, uint10 heif Exif:FlashPixVersion: "0100" heif:UnassociatedAlpha: 1 oiio:BitsPerSample: 10 - oiio:ColorSpace: "srgb_rec709_scene" + oiio:ColorSpace: "pq_rec2020_display" +Reading colorspace_hlg.avif +colorspace_hlg.avif : 16 x 16, 4 channel, uint10 heif + SHA-1: 0F3CAB52D479BC23E9C981DBADDFEF1F792E5540 + channel list: R, G, B, A + CICP: 9, 18, 9, 1 + Exif:ExifVersion: "0230" + Exif:FlashPixVersion: "0100" + heif:UnassociatedAlpha: 1 + oiio:BitsPerSample: 10 + oiio:ColorSpace: "hlg_rec2020_display" Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic ../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E diff --git a/testsuite/heif/ref/out-libheif1.9-with-av1-alt2.txt b/testsuite/heif/ref/out-libheif1.9-with-av1-alt2.txt index 6be6dc26e0..c938a6fe73 100644 --- a/testsuite/heif/ref/out-libheif1.9-with-av1-alt2.txt +++ b/testsuite/heif/ref/out-libheif1.9-with-av1-alt2.txt @@ -64,7 +64,17 @@ cicp_pq.avif : 16 x 16, 4 channel, uint10 heif Exif:FlashPixVersion: "0100" heif:UnassociatedAlpha: 1 oiio:BitsPerSample: 10 - oiio:ColorSpace: "srgb_rec709_scene" + oiio:ColorSpace: "pq_rec2020_display" +Reading colorspace_hlg.avif +colorspace_hlg.avif : 16 x 16, 4 channel, uint10 heif + SHA-1: 0F3CAB52D479BC23E9C981DBADDFEF1F792E5540 + channel list: R, G, B, A + CICP: 9, 18, 9, 1 + Exif:ExifVersion: "0230" + Exif:FlashPixVersion: "0100" + heif:UnassociatedAlpha: 1 + oiio:BitsPerSample: 10 + oiio:ColorSpace: "hlg_rec2020_display" Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic ../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif SHA-1: 8064B23A1A995B0D6525AFB5248EEC6C730BBB6C diff --git a/testsuite/heif/ref/out-libheif1.9-with-av1.txt b/testsuite/heif/ref/out-libheif1.9-with-av1.txt index e1f848ea83..f6d7ca55a5 100644 --- a/testsuite/heif/ref/out-libheif1.9-with-av1.txt +++ b/testsuite/heif/ref/out-libheif1.9-with-av1.txt @@ -64,7 +64,17 @@ cicp_pq.avif : 16 x 16, 4 channel, uint10 heif Exif:FlashPixVersion: "0100" heif:UnassociatedAlpha: 1 oiio:BitsPerSample: 10 - oiio:ColorSpace: "srgb_rec709_scene" + oiio:ColorSpace: "pq_rec2020_display" +Reading colorspace_hlg.avif +colorspace_hlg.avif : 16 x 16, 4 channel, uint10 heif + SHA-1: 0F3CAB52D479BC23E9C981DBADDFEF1F792E5540 + channel list: R, G, B, A + CICP: 9, 18, 9, 1 + Exif:ExifVersion: "0230" + Exif:FlashPixVersion: "0100" + heif:UnassociatedAlpha: 1 + oiio:BitsPerSample: 10 + oiio:ColorSpace: "hlg_rec2020_display" Reading ../oiio-images/heif/greyhounds-looking-for-a-table.heic ../oiio-images/heif/greyhounds-looking-for-a-table.heic : 3024 x 4032, 3 channel, uint8 heif SHA-1: 8211F56BBABDC7615CCAF67CBF49741D1A292D2E diff --git a/testsuite/heif/run.py b/testsuite/heif/run.py index 9dc5a06f35..0a3250e374 100755 --- a/testsuite/heif/run.py +++ b/testsuite/heif/run.py @@ -13,6 +13,11 @@ " -d uint10 --cicp \"9,16,9,1\" -o cicp_pq.avif" ) command += info_command ("cicp_pq.avif", safematch=True) + +command += oiiotool (os.path.join(imagedir, "test-10bit.avif") + + " -d uint10 --attrib oiio:ColorSpace hlg_rec2020_display -o colorspace_hlg.avif" ) +command += info_command ("colorspace_hlg.avif", safematch=True) + files = [ "greyhounds-looking-for-a-table.heic", "sewing-threads.heic" ] for f in files: command = command + info_command (os.path.join(OIIO_TESTSUITE_IMAGEDIR, f)) diff --git a/testsuite/python-colorconfig/ref/out-ocio23.txt b/testsuite/python-colorconfig/ref/out-ocio23.txt index 883ef051d4..1badffcb7f 100644 --- a/testsuite/python-colorconfig/ref/out-ocio23.txt +++ b/testsuite/python-colorconfig/ref/out-ocio23.txt @@ -26,6 +26,11 @@ equivalent('linear', 'lin_srgb'): False equivalent('scene_linear', 'lin_srgb'): False equivalent('ACEScg', 'scene_linear'): True equivalent('lnf', 'scene_linear'): False +get_color_interop_id('ACEScg') = lin_ap1_scene +get_color_interop_id('lin_srgb') = lin_rec709_scene +get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene +get_cicp('pq_rec2020_display') = [9, 16, 9, 1] +get_cicp('unknown_interop_id') = None Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out-ocio24.txt b/testsuite/python-colorconfig/ref/out-ocio24.txt index 1bf39d0cb3..2882859127 100644 --- a/testsuite/python-colorconfig/ref/out-ocio24.txt +++ b/testsuite/python-colorconfig/ref/out-ocio24.txt @@ -26,6 +26,11 @@ equivalent('linear', 'lin_srgb'): False equivalent('scene_linear', 'lin_srgb'): False equivalent('ACEScg', 'scene_linear'): True equivalent('lnf', 'scene_linear'): False +get_color_interop_id('ACEScg') = lin_ap1_scene +get_color_interop_id('lin_srgb') = lin_rec709_scene +get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene +get_cicp('pq_rec2020_display') = [9, 16, 9, 1] +get_cicp('unknown_interop_id') = None Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out-ocio25.txt b/testsuite/python-colorconfig/ref/out-ocio25.txt index 07569ff915..b12d8ce08d 100644 --- a/testsuite/python-colorconfig/ref/out-ocio25.txt +++ b/testsuite/python-colorconfig/ref/out-ocio25.txt @@ -26,6 +26,11 @@ equivalent('linear', 'lin_srgb'): False equivalent('scene_linear', 'lin_srgb'): False equivalent('ACEScg', 'scene_linear'): True equivalent('lnf', 'scene_linear'): False +get_color_interop_id('ACEScg') = lin_ap1_scene +get_color_interop_id('lin_srgb') = lin_rec709_scene +get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene +get_cicp('pq_rec2020_display') = [9, 16, 9, 1] +get_cicp('unknown_interop_id') = None Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/ref/out.txt b/testsuite/python-colorconfig/ref/out.txt index 9dee6146d9..cb9a3dddfc 100644 --- a/testsuite/python-colorconfig/ref/out.txt +++ b/testsuite/python-colorconfig/ref/out.txt @@ -26,6 +26,11 @@ equivalent('linear', 'lin_srgb'): False equivalent('scene_linear', 'lin_srgb'): False equivalent('ACEScg', 'scene_linear'): True equivalent('lnf', 'scene_linear'): False +get_color_interop_id('ACEScg') = lin_ap1_scene +get_color_interop_id('lin_srgb') = lin_rec709_scene +get_color_interop_id([1, 13, 1, 1]) = srgb_rec709_scene +get_cicp('pq_rec2020_display') = [9, 16, 9, 1] +get_cicp('unknown_interop_id') = None Loaded test OCIO config: oiio_test_v0.9.2.ocio Parsed color space for filepath 'foo_lin_ap1.exr': ACEScg diff --git a/testsuite/python-colorconfig/src/test_colorconfig.py b/testsuite/python-colorconfig/src/test_colorconfig.py index 597223e785..766e6a037b 100755 --- a/testsuite/python-colorconfig/src/test_colorconfig.py +++ b/testsuite/python-colorconfig/src/test_colorconfig.py @@ -48,6 +48,11 @@ print ("equivalent('scene_linear', 'lin_srgb'):", config.equivalent("scene_linear", "lin_srgb")) print ("equivalent('ACEScg', 'scene_linear'):", config.equivalent("ACEScg", "scene_linear")) print ("equivalent('lnf', 'scene_linear'):", config.equivalent("lnf", "scene_linear")) + print ("get_color_interop_id('ACEScg') = ", config.get_color_interop_id("ACEScg")) + print ("get_color_interop_id('lin_srgb') = ", config.get_color_interop_id("lin_srgb")) + print ("get_color_interop_id([1, 13, 1, 1]) = ", config.get_color_interop_id([1, 13, 1, 1])) + print ("get_cicp('pq_rec2020_display') = ", config.get_cicp("pq_rec2020_display")) + print ("get_cicp('unknown_interop_id') = ", config.get_cicp("unknown_interop_id")) print ("") config = oiio.ColorConfig(str(TEST_CONFIG_PATH))