diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index f56b6219c3..2615b254d2 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -166,6 +166,7 @@ set(SOURCES transforms/builtins/CanonCameras.cpp transforms/builtins/Displays.cpp transforms/builtins/PanasonicCameras.cpp + transforms/builtins/ProPhotoRGB.cpp transforms/builtins/RedCameras.cpp transforms/builtins/SonyCameras.cpp transforms/BuiltinTransform.cpp diff --git a/src/OpenColorIO/Config.cpp b/src/OpenColorIO/Config.cpp index d4d5fbe7fa..6ab5ac2ab1 100644 --- a/src/OpenColorIO/Config.cpp +++ b/src/OpenColorIO/Config.cpp @@ -247,7 +247,7 @@ static constexpr unsigned LastSupportedMajorVersion = OCIO_VERSION_MAJOR; // For each major version keep the most recent minor. static const unsigned int LastSupportedMinorVersion[] = {0, // Version 1 - 5 // Version 2 + 6 // Version 2 }; } // namespace @@ -5656,6 +5656,16 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons << blt->getStyle() << "'."; throw Exception(os.str().c_str()); } + if (m_majorVersion == 2 && m_minorVersion < 6 + && ( 0 == Platform::Strcasecmp(blt->getStyle(), "ROMM_to_CIE-XYZ-D65_BFD") + || 0 == Platform::Strcasecmp(blt->getStyle(), "LINEAR-RIMM_to_ACES2065-1_BFD") + )) + { + std::ostringstream os; + os << "Only config version 2.6 (or higher) can have BuiltinTransform style '" + << blt->getStyle() << "'."; + throw Exception(os.str().c_str()); + } } else if (ConstCDLTransformRcPtr cdl = DynamicPtrCast(transform)) { diff --git a/src/OpenColorIO/transforms/builtins/BuiltinTransformRegistry.cpp b/src/OpenColorIO/transforms/builtins/BuiltinTransformRegistry.cpp index d828f11ace..c6b2392c63 100644 --- a/src/OpenColorIO/transforms/builtins/BuiltinTransformRegistry.cpp +++ b/src/OpenColorIO/transforms/builtins/BuiltinTransformRegistry.cpp @@ -17,6 +17,7 @@ #include "transforms/builtins/CanonCameras.h" #include "transforms/builtins/Displays.h" #include "transforms/builtins/PanasonicCameras.h" +#include "transforms/builtins/ProPhotoRGB.h" #include "transforms/builtins/RedCameras.h" #include "transforms/builtins/SonyCameras.h" #include "utils/StringUtils.h" @@ -117,6 +118,9 @@ void BuiltinTransformRegistryImpl::registerAll() noexcept CAMERA::RED::RegisterAll(*this); CAMERA::SONY::RegisterAll(*this); + // ProPhoto RGB / ROMM RGB support. + PROPHOTO::RegisterAll(*this); + // Display support. DISPLAY::RegisterAll(*this); } diff --git a/src/OpenColorIO/transforms/builtins/ProPhotoRGB.cpp b/src/OpenColorIO/transforms/builtins/ProPhotoRGB.cpp new file mode 100644 index 0000000000..10580f62f0 --- /dev/null +++ b/src/OpenColorIO/transforms/builtins/ProPhotoRGB.cpp @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include + +#include + +#include "ops/gamma/GammaOp.h" +#include "ops/matrix/MatrixOp.h" +#include "transforms/builtins/ACES.h" +#include "transforms/builtins/BuiltinTransformRegistry.h" +#include "transforms/builtins/ColorMatrixHelpers.h" +#include "transforms/builtins/OpHelpers.h" +#include "transforms/builtins/ProPhotoRGB.h" + +namespace OCIO_NAMESPACE +{ + +// ProPhoto RGB / ROMM RGB (Reference Output Medium Metric RGB) +// Specified in ANSI/I3A IT10.7666:2003 +// +// Primaries and white point. +namespace ROMM_RGB +{ + +static const Chromaticities red_xy(0.7347, 0.2653); +static const Chromaticities grn_xy(0.1596, 0.8404); +static const Chromaticities blu_xy(0.0366, 0.0001); +static const Chromaticities wht_xy(0.3457, 0.3585); // D50 + +const Primaries primaries(red_xy, grn_xy, blu_xy, wht_xy); + +} // namespace ROMM_RGB + +// ROMM RGB uses a piecewise gamma function with gamma 1.8. +// +// Encoded to Linear (decoding): +// if (encoded < 1.0 / 512.0): // breakpoint = 16 * 1.0 / 512.0 +// linear = encoded / 16.0 +// else: +// linear = encoded ^ 1.8 +// +// Linear to Encoded (encoding): +// if (linear < 1.0 / 512.0): +// encoded = linear * 16.0 +// else: +// encoded = linear ^ (1/1.8) +// +namespace ROMM_RGB_GAMMA_18 +{ + +static constexpr double gamma = 1.8; +static constexpr double slope = 16.0; // Slope of linear segment. +static constexpr double breakEnc = 1.0 / 32.0; // Encoded breakpoint + +void GenerateEncodedToLinearOps(OpRcPtrVec & ops) +{ + // Encoded gamma 1.8 to linear curve using LUT for accuracy. + auto GenerateLutValues = [](double in) -> float + { + const double absIn = std::abs(in); + double out = 0.0; + + if (absIn < breakEnc) + { + out = absIn / slope; + } + else + { + out = std::pow(absIn, gamma); + } + + return float(std::copysign(out, in)); + }; + + CreateHalfLut(ops, GenerateLutValues); +} + +} // namespace ROMM_RGB_GAMMA_18 + +namespace PROPHOTO +{ + +void RegisterAll(BuiltinTransformRegistryImpl & registry) noexcept +{ + // Linear ProPhoto RGB to ACES2065-1. + { + auto LINEAR_RIMM_to_ACES2065_1_BFD_Functor = [](OpRcPtrVec & ops) + { + // Convert from ROMM RGB (D50) to ACES AP0 (D60). + // Uses Bradford chromatic adaptation. + MatrixOpData::MatrixArrayPtr matrix = build_conversion_matrix(ROMM_RGB::primaries, + ACES_AP0::primaries, + ADAPTATION_BRADFORD); + CreateMatrixOp(ops, matrix, TRANSFORM_DIR_FORWARD); + }; + + registry.addBuiltin("LINEAR-RIMM_to_ACES2065-1_BFD", + "Convert ProPhoto RGB (linear) to ACES2065-1", + LINEAR_RIMM_to_ACES2065_1_BFD_Functor); + } + + // Encoded ProPhoto RGB (gamma 1.8) to CIE XYZ D65. + { + auto ROMM_to_CIE_XYZ_D65_BFD_Functor = [](OpRcPtrVec & ops) + { + ROMM_RGB_GAMMA_18::GenerateEncodedToLinearOps(ops); + + MatrixOpData::MatrixArrayPtr matrix + = build_conversion_matrix_to_XYZ_D65(ROMM_RGB::primaries, ADAPTATION_BRADFORD); + CreateMatrixOp(ops, matrix, TRANSFORM_DIR_FORWARD); + }; + + registry.addBuiltin("ROMM_to_CIE-XYZ-D65_BFD", + "Convert ProPhoto RGB (slope-limited gamma 1.8 encoded) to CIE XYZ D65", + ROMM_to_CIE_XYZ_D65_BFD_Functor); + } +} + +} // namespace PROPHOTO + +} // namespace OCIO_NAMESPACE diff --git a/src/OpenColorIO/transforms/builtins/ProPhotoRGB.h b/src/OpenColorIO/transforms/builtins/ProPhotoRGB.h new file mode 100644 index 0000000000..75df22208a --- /dev/null +++ b/src/OpenColorIO/transforms/builtins/ProPhotoRGB.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + + +#ifndef INCLUDED_OCIO_PROPHOTO_RGB_H +#define INCLUDED_OCIO_PROPHOTO_RGB_H + + +namespace OCIO_NAMESPACE +{ + +class BuiltinTransformRegistryImpl; + +namespace PROPHOTO +{ + +void RegisterAll(BuiltinTransformRegistryImpl & registry) noexcept; + +} // namespace PROPHOTO + +} // namespace OCIO_NAMESPACE + + +#endif // INCLUDED_OCIO_PROPHOTO_RGB_H diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 12fd06c1ba..69968c7cd3 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -180,6 +180,7 @@ set(SOURCES transforms/builtins/Displays.cpp transforms/builtins/OpHelpers.cpp transforms/builtins/PanasonicCameras.cpp + transforms/builtins/ProPhotoRGB.cpp transforms/builtins/RedCameras.cpp transforms/builtins/SonyCameras.cpp SystemMonitor.cpp diff --git a/tests/cpu/Config_tests.cpp b/tests/cpu/Config_tests.cpp index b3d69c1688..d3fe15028d 100644 --- a/tests/cpu/Config_tests.cpp +++ b/tests/cpu/Config_tests.cpp @@ -2093,12 +2093,12 @@ OCIO_ADD_TEST(Config, version) { OCIO_CHECK_THROW_WHAT(config->setVersion(2, 9), OCIO::Exception, "The minor version 9 is not supported for major version 2. " - "Maximum minor version is 5"); + "Maximum minor version is 6"); OCIO_CHECK_NO_THROW(config->setMajorVersion(2)); OCIO_CHECK_THROW_WHAT(config->setMinorVersion(9), OCIO::Exception, "The minor version 9 is not supported for major version 2. " - "Maximum minor version is 5"); + "Maximum minor version is 6"); } { @@ -10415,4 +10415,3 @@ OCIO_ADD_TEST(Config, interchange_attributes) config->setVersion(2, 5); } } - diff --git a/tests/cpu/transforms/BuiltinTransform_tests.cpp b/tests/cpu/transforms/BuiltinTransform_tests.cpp index cc57edf412..fee0b717b0 100644 --- a/tests/cpu/transforms/BuiltinTransform_tests.cpp +++ b/tests/cpu/transforms/BuiltinTransform_tests.cpp @@ -720,7 +720,14 @@ AllValues UnitTestValues { "DISPLAY - CIE-XYZ-D65_to_REC.2100-HLG-1000nit", { 6.0e-5f, { 0.5f, 0.4f, 0.3f, -0.1f, 1.01f, 0.2f }, - { 0.5649694f, 0.4038837f, 0.3751478f, -0.505630434f, 0.738133013f, 0.251128823f } } } + { 0.5649694f, 0.4038837f, 0.3751478f, -0.505630434f, 0.738133013f, 0.251128823f } } }, + { "ROMM_to_CIE-XYZ-D65_BFD", + { 1.0e-6f, + { 0.5f, 0.4f, 0.3f, 0.03f, 0.02f, 0.01f}, + { 0.248054191470f, 0.216382518411f, 0.124372318387f, 0.001608968596f, 0.001407349831f, 0.000677472563f} } }, + { "LINEAR-RIMM_to_ACES2065-1_BFD", + { 1.0e-6f, + {0.5f, 0.4f, 0.3f}, {0.47351069f, 0.39131449f, 0.29965645f} } } }; } // anon. diff --git a/tests/cpu/transforms/builtins/BuiltinTransformRegistry_tests.cpp b/tests/cpu/transforms/builtins/BuiltinTransformRegistry_tests.cpp index c67245debd..3543b3d5f9 100644 --- a/tests/cpu/transforms/builtins/BuiltinTransformRegistry_tests.cpp +++ b/tests/cpu/transforms/builtins/BuiltinTransformRegistry_tests.cpp @@ -95,8 +95,8 @@ OCIO_ADD_TEST(Builtins, read_write) // The unit test validates the read/write and the processor creation for all the existing // builtin transforms. - static constexpr char CONFIG_BUILTIN_TRANSFORMS[] { -R"(ocio_profile_version: 2.4 +static constexpr char CONFIG_BUILTIN_TRANSFORMS[] { +R"(ocio_profile_version: 2.6 environment: {} @@ -359,6 +359,53 @@ active_views: [] errMsg); } +void TestStyle26(const std::string & style) +{ + static constexpr char BASE[] { +R"(ocio_profile_version: 2.5 + +environment: + {} +search_path: "" +strictparsing: true +luma: [0.2126, 0.7152, 0.0722] + +roles: + default: ref + +file_rules: + - ! {name: Default, colorspace: default} + +displays: + Disp1: + - ! {name: View1, colorspace: test} + +active_displays: [] +active_views: [] + +colorspaces: + - ! + name: ref + + - ! + name: test + from_scene_reference: ! {style: )" }; + + std::string CONFIG(BASE); + CONFIG += style; + CONFIG += "}"; + + std::istringstream iss; + iss.str(CONFIG); + + const std::string errMsg = + "Only config version 2.6 (or higher) can have BuiltinTransform style '" + style + "'."; + + OCIO_CHECK_THROW_WHAT(OCIO::Config::CreateFromStream(iss), + OCIO::Exception, + errMsg); +} + } // end anon OCIO_ADD_TEST(Builtins, version_2_3_validation) @@ -403,4 +450,14 @@ OCIO_ADD_TEST(Builtins, version_2_3_validation) TestStyle("ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-REC2020-D60-in-REC2020-D65_2.0"); TestStyle("ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-REC2020-D60-in-REC2020-D65_2.0"); TestStyle("ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-REC2020-D60-in-REC2020-D65_2.0"); + +} + +OCIO_ADD_TEST(Builtins, version_2_5_validation) +{ + // The unit test validates that the config reader checkVersionConsistency check throws for + // version 2.5 configs containing a Builtin Transform with the new 2.6 ROMM styles. + + TestStyle26("ROMM_to_CIE-XYZ-D65_BFD"); + TestStyle26("LINEAR-RIMM_to_ACES2065-1_BFD"); }