Skip to content

Commit 6c8443c

Browse files
File interpolation v1 compatibility (#1215)
Signed-off-by: Bernard Lefebvre <[email protected]> (cherry picked from commit 30a6b0f39acb3304950e7c70e46327206acb433f) Co-authored-by: doug-walker <[email protected]>
1 parent 3d3eefc commit 6c8443c

File tree

7 files changed

+153
-41
lines changed

7 files changed

+153
-41
lines changed

include/OpenColorIO/OpenColorTransforms.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,12 @@ class OCIOEXPORT FileTransform : public Transform
999999
*/
10001000
void setCDLStyle(CDLStyle);
10011001

1002+
/**
1003+
* The file parsers that care about interpolation (LUTs) will try to make use of the requested
1004+
* interpolation method when loading the file. In these cases, if the requested method could
1005+
* not be used, a warning is logged. If no method is provided, or a method cannot be used,
1006+
* INTERP_DEFAULT is used.
1007+
*/
10021008
Interpolation getInterpolation() const;
10031009
void setInterpolation(Interpolation interp);
10041010

src/OpenColorIO/OCIOYaml.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,7 @@ inline void load(const YAML::Node& node, FileTransformRcPtr& t)
14421442
}
14431443
}
14441444

1445-
inline void save(YAML::Emitter& out, ConstFileTransformRcPtr t)
1445+
inline void save(YAML::Emitter& out, ConstFileTransformRcPtr t, unsigned int majorVersion)
14461446
{
14471447
out << YAML::VerbatimTag("FileTransform");
14481448
out << YAML::Flow << YAML::BeginMap;
@@ -1456,11 +1456,20 @@ inline void save(YAML::Emitter& out, ConstFileTransformRcPtr t)
14561456
{
14571457
out << YAML::Key << "cdl_style" << YAML::Value << CDLStyleToString(t->getCDLStyle());
14581458
}
1459-
if (t->getInterpolation() != INTERP_UNKNOWN && t->getInterpolation() != INTERP_DEFAULT)
1459+
Interpolation interp = t->getInterpolation();
1460+
if (majorVersion == 1 && interp == INTERP_DEFAULT)
1461+
{
1462+
// The DEFAULT method is not available in a v1 library. If the v1 config is read by a v1
1463+
// library and the file is a LUT, a missing interp would end up set to UNKNOWN and a
1464+
// throw would happen when the processor is built. Setting to LINEAR to provide more
1465+
// robust compatibility.
1466+
interp = INTERP_LINEAR;
1467+
}
1468+
if (interp != INTERP_DEFAULT)
14601469
{
14611470
out << YAML::Key << "interpolation";
14621471
out << YAML::Value;
1463-
save(out, t->getInterpolation());
1472+
save(out, interp);
14641473
}
14651474

14661475
EmitBaseTransformKeyValues(out, t);
@@ -2356,7 +2365,7 @@ inline void save(YAML::Emitter & out, ConstGradingToneTransformRcPtr t)
23562365
// GroupTransform
23572366

23582367
void load(const YAML::Node& node, TransformRcPtr& t);
2359-
void save(YAML::Emitter& out, ConstTransformRcPtr t);
2368+
void save(YAML::Emitter& out, ConstTransformRcPtr t, unsigned int majorVersion);
23602369

23612370
inline void load(const YAML::Node& node, GroupTransformRcPtr& t)
23622371
{
@@ -2412,7 +2421,7 @@ inline void load(const YAML::Node& node, GroupTransformRcPtr& t)
24122421
}
24132422
}
24142423

2415-
inline void save(YAML::Emitter& out, ConstGroupTransformRcPtr t)
2424+
inline void save(YAML::Emitter& out, ConstGroupTransformRcPtr t, unsigned int majorVersion)
24162425
{
24172426
out << YAML::VerbatimTag("GroupTransform");
24182427
out << YAML::BeginMap;
@@ -2426,7 +2435,7 @@ inline void save(YAML::Emitter& out, ConstGroupTransformRcPtr t)
24262435
out << YAML::BeginSeq;
24272436
for(int i = 0; i < t->getNumTransforms(); ++i)
24282437
{
2429-
save(out, t->getTransform(i));
2438+
save(out, t->getTransform(i), majorVersion);
24302439
}
24312440
out << YAML::EndSeq;
24322441

@@ -3217,7 +3226,7 @@ void load(const YAML::Node& node, TransformRcPtr& t)
32173226
}
32183227
}
32193228

3220-
void save(YAML::Emitter& out, ConstTransformRcPtr t)
3229+
void save(YAML::Emitter& out, ConstTransformRcPtr t, unsigned int majorVersion)
32213230
{
32223231
if(ConstAllocationTransformRcPtr Allocation_tran = \
32233232
DynamicPtrCast<const AllocationTransform>(t))
@@ -3243,7 +3252,7 @@ void save(YAML::Emitter& out, ConstTransformRcPtr t)
32433252
else if(ConstFileTransformRcPtr File_tran = \
32443253
DynamicPtrCast<const FileTransform>(t))
32453254
// TODO: if (File_tran->getCDLStyle() != CDL_TRANSFORM_DEFAULT) should throw with config v1.
3246-
save(out, File_tran);
3255+
save(out, File_tran, majorVersion);
32473256
else if (ConstExposureContrastTransformRcPtr File_tran = \
32483257
DynamicPtrCast<const ExposureContrastTransform>(t))
32493258
save(out, File_tran);
@@ -3261,7 +3270,7 @@ void save(YAML::Emitter& out, ConstTransformRcPtr t)
32613270
save(out, GT_tran);
32623271
else if(ConstGroupTransformRcPtr Group_tran = \
32633272
DynamicPtrCast<const GroupTransform>(t))
3264-
save(out, Group_tran);
3273+
save(out, Group_tran, majorVersion);
32653274
else if(ConstLogAffineTransformRcPtr Log_tran = \
32663275
DynamicPtrCast<const LogAffineTransform>(t))
32673276
save(out, Log_tran);
@@ -3419,7 +3428,7 @@ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs)
34193428
}
34203429
}
34213430

3422-
inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs)
3431+
inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs, unsigned int majorVersion)
34233432
{
34243433
out << YAML::VerbatimTag("ColorSpace");
34253434
out << YAML::BeginMap;
@@ -3465,14 +3474,14 @@ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs)
34653474
if(toref)
34663475
{
34673476
out << YAML::Key << (isDisplay ? "to_display_reference" : "to_reference") << YAML::Value;
3468-
save(out, toref);
3477+
save(out, toref, majorVersion);
34693478
}
34703479

34713480
ConstTransformRcPtr fromref = cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE);
34723481
if(fromref)
34733482
{
34743483
out << YAML::Key << (isDisplay ? "from_display_reference" : "from_reference") << YAML::Value;
3475-
save(out, fromref);
3484+
save(out, fromref, majorVersion);
34763485
}
34773486

34783487
out << YAML::EndMap;
@@ -3533,7 +3542,7 @@ inline void load(const YAML::Node& node, LookRcPtr& look)
35333542
}
35343543
}
35353544

3536-
inline void save(YAML::Emitter& out, ConstLookRcPtr look)
3545+
inline void save(YAML::Emitter& out, ConstLookRcPtr look, unsigned int majorVersion)
35373546
{
35383547
out << YAML::VerbatimTag("Look");
35393548
out << YAML::BeginMap;
@@ -3545,14 +3554,14 @@ inline void save(YAML::Emitter& out, ConstLookRcPtr look)
35453554
{
35463555
out << YAML::Key << "transform";
35473556
out << YAML::Value;
3548-
save(out, look->getTransform());
3557+
save(out, look->getTransform(), majorVersion);
35493558
}
35503559

35513560
if(look->getInverseTransform())
35523561
{
35533562
out << YAML::Key << "inverse_transform";
35543563
out << YAML::Value;
3555-
save(out, look->getInverseTransform());
3564+
save(out, look->getInverseTransform(), majorVersion);
35563565
}
35573566

35583567
out << YAML::EndMap;
@@ -3694,7 +3703,7 @@ inline void load(const YAML::Node & node, ViewTransformRcPtr & vt)
36943703
}
36953704
}
36963705

3697-
inline void save(YAML::Emitter & out, ConstViewTransformRcPtr & vt)
3706+
inline void save(YAML::Emitter & out, ConstViewTransformRcPtr & vt, unsigned int majorVersion)
36983707
{
36993708
out << YAML::VerbatimTag("ViewTransform");
37003709
out << YAML::BeginMap;
@@ -3723,14 +3732,14 @@ inline void save(YAML::Emitter & out, ConstViewTransformRcPtr & vt)
37233732
if (toref)
37243733
{
37253734
out << YAML::Key << (isDisplay ? "to_display_reference" : "to_reference") << YAML::Value;
3726-
save(out, toref);
3735+
save(out, toref, majorVersion);
37273736
}
37283737

37293738
ConstTransformRcPtr fromref = vt->getTransform(VIEWTRANSFORM_DIR_FROM_REFERENCE);
37303739
if (fromref)
37313740
{
37323741
out << YAML::Key << (isDisplay ? "from_display_reference" : "from_reference") << YAML::Value;
3733-
save(out, fromref);
3742+
save(out, fromref, majorVersion);
37343743
}
37353744

37363745
out << YAML::EndMap;
@@ -4878,7 +4887,7 @@ inline void save(YAML::Emitter & out, const Config & config)
48784887
for(int i = 0; i < config.getNumLooks(); ++i)
48794888
{
48804889
const char* name = config.getLookNameByIndex(i);
4881-
save(out, config.getLook(name));
4890+
save(out, config.getLook(name), configMajorVersion);
48824891
}
48834892
out << YAML::EndSeq;
48844893
out << YAML::Newline;
@@ -4895,7 +4904,7 @@ inline void save(YAML::Emitter & out, const Config & config)
48954904
{
48964905
auto name = config.getViewTransformNameByIndex(i);
48974906
auto vt = config.getViewTransform(name);
4898-
save(out, vt);
4907+
save(out, vt, configMajorVersion);
48994908
}
49004909
out << YAML::EndSeq;
49014910
}
@@ -4933,7 +4942,7 @@ inline void save(YAML::Emitter & out, const Config & config)
49334942
out << YAML::Value << YAML::BeginSeq;
49344943
for (const auto & cs : displayCS)
49354944
{
4936-
save(out, cs);
4945+
save(out, cs, configMajorVersion);
49374946
}
49384947
out << YAML::EndSeq;
49394948
}
@@ -4945,7 +4954,7 @@ inline void save(YAML::Emitter & out, const Config & config)
49454954
out << YAML::Value << YAML::BeginSeq;
49464955
for (const auto & cs : sceneCS)
49474956
{
4948-
save(out, cs);
4957+
save(out, cs, configMajorVersion);
49494958
}
49504959
out << YAML::EndSeq;
49514960
}

src/OpenColorIO/transforms/FileTransform.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,8 @@ void FileTransform::validate() const
9797
throw Exception("FileTransform: empty file path");
9898
}
9999

100-
if (getInterpolation() == INTERP_UNKNOWN)
101-
{
102-
std::ostringstream oss;
103-
oss << "FileTransform can't use unknown interpolation. ";
104-
oss << "File: '" << std::string(getImpl()->m_src) << "'.";
105-
throw Exception(oss.str().c_str());
106-
}
100+
// NB: Not validating interpolation since v1 configs such as the spi examples use
101+
// interpolation=unknown. So that is a legal usage, even if it makes no sense.
107102
}
108103

109104
const char * FileTransform::getSrc() const

tests/cpu/Config_tests.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ OCIO_ADD_TEST(Config, simple_config)
162162
" children:\n"
163163
" - !<FileTransform>\n"
164164
" src: diffusemult.spimtx\n"
165-
" interpolation: best\n"
165+
" interpolation: unknown\n"
166166
" - !<ColorSpaceTransform>\n"
167167
" src: raw\n"
168168
" dst: lnh\n"
@@ -393,7 +393,7 @@ OCIO_ADD_TEST(Config, serialize_group_transform)
393393
" from_reference: !<GroupTransform>\n"
394394
" children:\n"
395395
" - !<FileTransform> {src: \"\"}\n"
396-
" - !<FileTransform> {src: \"\"}\n"
396+
" - !<FileTransform> {src: \"\", interpolation: unknown}\n"
397397
" - !<FileTransform> {src: \"\", interpolation: best}\n"
398398
" - !<FileTransform> {src: \"\", interpolation: nearest}\n"
399399
" - !<FileTransform> {src: \"\", interpolation: cubic}\n"
@@ -4333,6 +4333,55 @@ OCIO_ADD_TEST(Config, file_transform_serialization)
43334333
OCIO_CHECK_EQUAL(oss.str(), str);
43344334
}
43354335

4336+
OCIO_ADD_TEST(Config, file_transform_serialization_v1)
4337+
{
4338+
OCIO::ConfigRcPtr cfg;
4339+
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::Create());
4340+
OCIO_REQUIRE_ASSERT(cfg);
4341+
cfg->setMajorVersion(1);
4342+
auto ft = OCIO::FileTransform::Create();
4343+
ft->setSrc("file");
4344+
auto cs = OCIO::ColorSpace::Create();
4345+
// Note that ft has no interpolation set. In a v2 config, this is not a problem and is taken
4346+
// to mean default interpolation. However, in this case the config version is 1 and if the
4347+
// config were read by a v1 library (rather than v2), this could cause a failure. So the
4348+
// interp is set to linear during serialization to avoid problems.
4349+
cs->setTransform(ft, OCIO::COLORSPACE_DIR_TO_REFERENCE);
4350+
ft->setSrc("other");
4351+
ft->setInterpolation(OCIO::INTERP_TETRAHEDRAL);
4352+
cs->setTransform(ft, OCIO::COLORSPACE_DIR_FROM_REFERENCE);
4353+
cs->setName("cs");
4354+
cfg->addColorSpace(cs);
4355+
std::ostringstream os;
4356+
cfg->serialize(os);
4357+
OCIO_CHECK_EQUAL(os.str(), R"(ocio_profile_version: 1
4358+
4359+
search_path: ""
4360+
strictparsing: true
4361+
luma: [0.2126, 0.7152, 0.0722]
4362+
4363+
roles:
4364+
{}
4365+
4366+
displays:
4367+
{}
4368+
4369+
active_displays: []
4370+
active_views: []
4371+
4372+
colorspaces:
4373+
- !<ColorSpace>
4374+
name: cs
4375+
family: ""
4376+
equalitygroup: ""
4377+
bitdepth: unknown
4378+
isdata: false
4379+
allocation: uniform
4380+
to_reference: !<FileTransform> {src: file, interpolation: linear}
4381+
from_reference: !<FileTransform> {src: other, interpolation: tetrahedral}
4382+
)" );
4383+
}
4384+
43364385
OCIO_ADD_TEST(Config, add_color_space)
43374386
{
43384387
// The unit test validates that the color space is correctly added to the configuration.

tests/cpu/transforms/FileTransform_tests.cpp

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "ContextVariableUtils.h"
1010
#include "testutils/UnitTest.h"
11+
#include "UnitTestLogUtils.h"
1112
#include "UnitTestUtils.h"
1213

1314
namespace OCIO = OCIO_NAMESPACE;
@@ -296,16 +297,58 @@ OCIO_ADD_TEST(FileTransform, validate)
296297
tr->setSrc("lut3d_17x17x17_32f_12i.clf");
297298
OCIO_CHECK_NO_THROW(tr->validate());
298299

299-
tr->setInterpolation(OCIO::INTERP_UNKNOWN);
300+
tr->setSrc("");
300301
OCIO_CHECK_THROW_WHAT(tr->validate(), OCIO::Exception,
301-
"FileTransform can't use unknown interpolation");
302+
"FileTransform: empty file path");
303+
}
304+
305+
OCIO_ADD_TEST(FileTransform, interpolation_validity)
306+
{
307+
OCIO::ConfigRcPtr cfg;
308+
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateRaw()->createEditableCopy());
309+
cfg->setSearchPath(OCIO::GetTestFilesDir().c_str());
310+
OCIO_CHECK_NO_THROW(cfg->validate());
311+
312+
OCIO::FileTransformRcPtr tr = OCIO::FileTransform::Create();
313+
tr->setSrc("lut1d_1.spi1d");
302314

303-
tr->setInterpolation(OCIO::INTERP_BEST);
304315
OCIO_CHECK_NO_THROW(tr->validate());
305316

306-
tr->setSrc("");
307-
OCIO_CHECK_THROW_WHAT(tr->validate(), OCIO::Exception,
308-
"FileTransform: empty file path");
317+
// File transform with format requiring a valid interpolation using default interpolation.
318+
OCIO_CHECK_NO_THROW(cfg->getProcessor(tr));
319+
320+
// UNKNOWN can't be used by a LUT file, so the interp on the LUT is set to DEFAULT and a
321+
// warning is logged.
322+
323+
tr->setInterpolation(OCIO::INTERP_UNKNOWN);
324+
OCIO_CHECK_NO_THROW(tr->validate());
325+
{
326+
OCIO::LogGuard log;
327+
OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_WARNING);
328+
OCIO_CHECK_NO_THROW(cfg->getProcessor(tr));
329+
OCIO_CHECK_EQUAL(log.output(), "[OpenColorIO Warning]: Interpolation specified by "
330+
"FileTransform 'unknown' is not allowed with the "
331+
"given file: 'lut1d_1.spi1d'.\n");
332+
}
333+
334+
// TETRAHEDRAL can't be used for Spi1d, default is used instead (and a warning is logged).
335+
336+
tr->setInterpolation(OCIO::INTERP_TETRAHEDRAL);
337+
{
338+
OCIO::LogGuard log;
339+
OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_WARNING);
340+
OCIO_CHECK_NO_THROW(cfg->getProcessor(tr));
341+
OCIO_CHECK_EQUAL(log.output(), "[OpenColorIO Warning]: Interpolation specified by "
342+
"FileTransform 'tetrahedral' is not allowed with the "
343+
"given file: 'lut1d_1.spi1d'.\n");
344+
}
345+
346+
// Matrices ignore interpolation, so UNKNOWN is ignored and not even logged. Note that the
347+
// spi example configs use interpolation=unknown for matrix files.
348+
349+
tr->setInterpolation(OCIO::INTERP_UNKNOWN);
350+
tr->setSrc("camera_to_aces.spimtx");
351+
OCIO_CHECK_NO_THROW(cfg->getProcessor(tr));
309352
}
310353

311354
OCIO_ADD_TEST(FileTransform, context_variables)

tests/python/CDLTransformTest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,14 @@ def test_createfromfile_cdl(self):
241241
# Try env var first to get test file path.
242242
test_file = '%s/cdl_test1.cdl' % TEST_DATAFILES_DIR
243243

244+
# Mute warnings being logged.
245+
curLogLevel = OCIO.GetLoggingLevel()
246+
OCIO.SetLoggingLevel(OCIO.LOGGING_LEVEL_NONE)
247+
244248
# Test a specified id member of the cdl file.
245249
cdl = OCIO.CDLTransform.CreateFromFile(test_file, 'cc0003')
250+
OCIO.SetLoggingLevel(curLogLevel)
251+
246252
self.assertEqual(cdl.getID(), 'cc0003')
247253
self.assertEqual(cdl.getDescription(), 'golden')
248254
self.assertListEqual(cdl.getSlope(), [1.2, 1.1, 1.0])

0 commit comments

Comments
 (0)