1 /*
2 Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
3 All Rights Reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of Sony Pictures Imageworks nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30 #include <cstdlib>
31 #include <cstring>
32 #include <set>
33 #include <sstream>
34 #include <fstream>
35 #include <utility>
36 #include <vector>
37
38 #include <OpenColorIO/OpenColorIO.h>
39
40 #include "HashUtils.h"
41 #include "Logging.h"
42 #include "LookParse.h"
43 #include "Display.h"
44 #include "MathUtils.h"
45 #include "Mutex.h"
46 #include "OpBuilders.h"
47 #include "PathUtils.h"
48 #include "ParseUtils.h"
49 #include "Processor.h"
50 #include "PrivateTypes.h"
51 #include "pystring/pystring.h"
52 #include "OCIOYaml.h"
53 #include "Platform.h"
54
55 OCIO_NAMESPACE_ENTER
56 {
57 namespace
58 {
59 const char * OCIO_CONFIG_ENVVAR = "OCIO";
60 const char * OCIO_ACTIVE_DISPLAYS_ENVVAR = "OCIO_ACTIVE_DISPLAYS";
61 const char * OCIO_ACTIVE_VIEWS_ENVVAR = "OCIO_ACTIVE_VIEWS";
62
63 enum Sanity
64 {
65 SANITY_UNKNOWN = 0,
66 SANITY_SANE,
67 SANITY_INSANE
68 };
69
70 // These are the 709 primaries specified by the ASC.
71 const float DEFAULT_LUMA_COEFF_R = 0.2126f;
72 const float DEFAULT_LUMA_COEFF_G = 0.7152f;
73 const float DEFAULT_LUMA_COEFF_B = 0.0722f;
74
75 const char * INTERNAL_RAW_PROFILE =
76 "ocio_profile_version: 1\n"
77 "strictparsing: false\n"
78 "roles:\n"
79 " default: raw\n"
80 "displays:\n"
81 " sRGB:\n"
82 " - !<View> {name: Raw, colorspace: raw}\n"
83 "colorspaces:\n"
84 " - !<ColorSpace>\n"
85 " name: raw\n"
86 " family: raw\n"
87 " equalitygroup:\n"
88 " bitdepth: 32f\n"
89 " isdata: true\n"
90 " allocation: uniform\n"
91 " description: 'A raw color space. Conversions to and from this space are no-ops.'\n";
92 }
93
94
95 ///////////////////////////////////////////////////////////////////////////
96
97 const char * GetVersion()
98 {
99 return OCIO_VERSION;
100 }
101
102 int GetVersionHex()
103 {
104 return OCIO_VERSION_HEX;
105 }
106
107 namespace
108 {
109 ConstConfigRcPtr g_currentConfig;
110 Mutex g_currentConfigLock;
111 }
112
113 ConstConfigRcPtr GetCurrentConfig()
114 {
115 AutoMutex lock(g_currentConfigLock);
116
117 if(!g_currentConfig)
118 {
119 g_currentConfig = Config::CreateFromEnv();
120 }
121
122 return g_currentConfig;
123 }
124
125 void SetCurrentConfig(const ConstConfigRcPtr & config)
126 {
127 AutoMutex lock(g_currentConfigLock);
128
129 g_currentConfig = config->createEditableCopy();
130 }
131
132 namespace
133 {
134
135 // Environment
136 const char* LookupEnvironment(const StringMap & env,
137 const std::string & name)
138 {
139 StringMap::const_iterator iter = env.find(name);
140 if(iter == env.end()) return "";
141 return iter->second.c_str();
142 }
143
144 // Roles
145 // (lower case role name: colorspace name)
146 const char* LookupRole(const StringMap & roles, const std::string & rolename)
147 {
148 StringMap::const_iterator iter = roles.find(pystring::lower(rolename));
149 if(iter == roles.end()) return "";
150 return iter->second.c_str();
151 }
152
153
154 void GetFileReferences(std::set<std::string> & files,
155 const ConstTransformRcPtr & transform)
156 {
157 if(!transform) return;
158
159 if(ConstGroupTransformRcPtr groupTransform = \
160 DynamicPtrCast<const GroupTransform>(transform))
161 {
162 for(int i=0; i<groupTransform->size(); ++i)
163 {
164 GetFileReferences(files, groupTransform->getTransform(i));
165 }
166 }
167 else if(ConstFileTransformRcPtr fileTransform = \
168 DynamicPtrCast<const FileTransform>(transform))
169 {
170 files.insert(fileTransform->getSrc());
171 }
172 }
173
174 void GetColorSpaceReferences(std::set<std::string> & colorSpaceNames,
175 const ConstTransformRcPtr & transform)
176 {
177 if(!transform) return;
178
179 if(ConstGroupTransformRcPtr groupTransform = \
180 DynamicPtrCast<const GroupTransform>(transform))
181 {
182 for(int i=0; i<groupTransform->size(); ++i)
183 {
184 GetColorSpaceReferences(colorSpaceNames, groupTransform->getTransform(i));
185 }
186 }
187 else if(ConstColorSpaceTransformRcPtr colorSpaceTransform = \
188 DynamicPtrCast<const ColorSpaceTransform>(transform))
189 {
190 colorSpaceNames.insert(colorSpaceTransform->getSrc());
191 colorSpaceNames.insert(colorSpaceTransform->getDst());
192 }
193 else if(ConstDisplayTransformRcPtr displayTransform = \
194 DynamicPtrCast<const DisplayTransform>(transform))
195 {
196 colorSpaceNames.insert(displayTransform->getInputColorSpaceName());
197 }
198 else if(ConstLookTransformRcPtr lookTransform = \
199 DynamicPtrCast<const LookTransform>(transform))
200 {
201 colorSpaceNames.insert(colorSpaceTransform->getSrc());
202 colorSpaceNames.insert(colorSpaceTransform->getDst());
203 }
204 }
205
206
207 bool FindColorSpaceIndex(int * index,
208 const ColorSpaceVec & colorspaces,
209 const std::string & csname)
210 {
211 if(csname.empty()) return false;
212
213 std::string csnamelower = pystring::lower(csname);
214 for(unsigned int i = 0; i < colorspaces.size(); ++i)
215 {
216 if(csnamelower == pystring::lower(colorspaces[i]->getName()))
217 {
218 if(index) *index = i;
219 return true;
220 }
221 }
222
223 return false;
224 }
225
226 } // namespace
227
228 class Config::Impl
229 {
230 public:
231 StringMap env_;
232 ContextRcPtr context_;
233 std::string description_;
234 ColorSpaceVec colorspaces_;
235 StringMap roles_;
236 LookVec looksList_;
237
238 DisplayMap displays_;
239 StringVec activeDisplays_;
240 StringVec activeDisplaysEnvOverride_;
241 StringVec activeViews_;
242 StringVec activeViewsEnvOverride_;
243
244 mutable std::string activeDisplaysStr_;
245 mutable std::string activeViewsStr_;
246 mutable StringVec displayCache_;
247
248 // Misc
249 std::vector<float> defaultLumaCoefs_;
250 bool strictParsing_;
251
252 mutable Sanity sanity_;
253 mutable std::string sanitytext_;
254
255 mutable Mutex cacheidMutex_;
256 mutable StringMap cacheids_;
257 mutable std::string cacheidnocontext_;
258
259 OCIOYaml io_;
260
261 Impl() :
262 context_(Context::Create()),
263 strictParsing_(true),
264 sanity_(SANITY_UNKNOWN)
265 {
266 std::string activeDisplays;
267 Platform::getenv(OCIO_ACTIVE_DISPLAYS_ENVVAR, activeDisplays);
268 activeDisplays = pystring::strip(activeDisplays);
269 if (!activeDisplays.empty()) {
270 SplitStringEnvStyle(activeDisplaysEnvOverride_, activeDisplays.c_str());
271 }
272
273 std::string activeViews;
274 Platform::getenv(OCIO_ACTIVE_VIEWS_ENVVAR, activeViews);
275 activeViews = pystring::strip(activeViews);
276 if (!activeViews.empty()) {
277 SplitStringEnvStyle(activeViewsEnvOverride_, activeViews.c_str());
278 }
279
280 defaultLumaCoefs_.resize(3);
281 defaultLumaCoefs_[0] = DEFAULT_LUMA_COEFF_R;
282 defaultLumaCoefs_[1] = DEFAULT_LUMA_COEFF_G;
283 defaultLumaCoefs_[2] = DEFAULT_LUMA_COEFF_B;
284 }
285
286 ~Impl()
287 {
288
289 }
290
291 Impl& operator= (const Impl & rhs)
292 {
293 if(this!=&rhs)
294 {
295 env_ = rhs.env_;
296 context_ = rhs.context_->createEditableCopy();
297 description_ = rhs.description_;
298
299 // Deep copy the colorspaces
300 colorspaces_.clear();
301 colorspaces_.reserve(rhs.colorspaces_.size());
302 for(unsigned int i=0; i<rhs.colorspaces_.size(); ++i)
303 {
304 colorspaces_.push_back(rhs.colorspaces_[i]->createEditableCopy());
305 }
306
307 // Deep copy the looks
308 looksList_.clear();
309 looksList_.reserve(rhs.looksList_.size());
310 for(unsigned int i=0; i<rhs.looksList_.size(); ++i)
311 {
312 looksList_.push_back(rhs.looksList_[i]->createEditableCopy());
313 }
314
315 // Assignment operator will suffice for these
316 roles_ = rhs.roles_;
317
318 displays_ = rhs.displays_;
319 activeDisplays_ = rhs.activeDisplays_;
320 activeViews_ = rhs.activeViews_;
321 activeViewsEnvOverride_ = rhs.activeViewsEnvOverride_;
322 activeDisplaysEnvOverride_ = rhs.activeDisplaysEnvOverride_;
323 activeDisplaysStr_ = rhs.activeDisplaysStr_;
324 displayCache_ = rhs.displayCache_;
325
326 defaultLumaCoefs_ = rhs.defaultLumaCoefs_;
327 strictParsing_ = rhs.strictParsing_;
328
329 sanity_ = rhs.sanity_;
330 sanitytext_ = rhs.sanitytext_;
331
332 cacheids_ = rhs.cacheids_;
333 cacheidnocontext_ = rhs.cacheidnocontext_;
334 }
335 return *this;
336 }
337
338 // Any time you modify the state of the config, you must call this
339 // to reset internal cache states. You also should do this in a
340 // thread safe manner by acquiring the cacheidMutex_;
341 void resetCacheIDs();
342
343 // Get all internal transforms (to generate cacheIDs, validation, etc).
344 // This currently crawls colorspaces + looks
345 void getAllIntenalTransforms(ConstTransformVec & transformVec) const;
346 };
347
348
349 ///////////////////////////////////////////////////////////////////////////
350
351 ConfigRcPtr Config::Create()
352 {
353 return ConfigRcPtr(new Config(), &deleter);
354 }
355
356 void Config::deleter(Config* c)
357 {
358 delete c;
359 }
360
361 ConstConfigRcPtr Config::CreateFromEnv()
362 {
363 std::string file;
364 Platform::getenv(OCIO_CONFIG_ENVVAR, file);
365 if(!file.empty()) return CreateFromFile(file.c_str());
366
367 std::ostringstream os;
368 os << "Color management disabled. ";
369 os << "(Specify the $OCIO environment variable to enable.)";
370 LogInfo(os.str());
371
372 std::istringstream istream;
373 istream.str(INTERNAL_RAW_PROFILE);
374
375 ConfigRcPtr config = Config::Create();
376 config->getImpl()->io_.open(istream, config);
377 return config;
378 }
379
380 ConstConfigRcPtr Config::CreateFromFile(const char * filename)
381 {
382 std::ifstream istream(filename);
383 if(istream.fail()) {
384 std::ostringstream os;
385 os << "Error could not read '" << filename;
386 os << "' OCIO profile.";
387 throw Exception (os.str().c_str());
388 }
389
390 ConfigRcPtr config = Config::Create();
391 config->getImpl()->io_.open(istream, config, filename);
392 return config;
393 }
394
395 ConstConfigRcPtr Config::CreateFromStream(std::istream & istream)
396 {
397 ConfigRcPtr config = Config::Create();
398 config->getImpl()->io_.open(istream, config);
399 return config;
400 }
401
402 ///////////////////////////////////////////////////////////////////////////
403
404
405
406 Config::Config()
407 : m_impl(new Config::Impl)
408 {
409 }
410
411 Config::~Config()
412 {
413 delete m_impl;
414 m_impl = NULL;
415 }
416
417 ConfigRcPtr Config::createEditableCopy() const
418 {
419 ConfigRcPtr config = Config::Create();
420 *config->m_impl = *m_impl;
421 return config;
422 }
423
424 void Config::sanityCheck() const
425 {
426 if(getImpl()->sanity_ == SANITY_SANE) return;
427 if(getImpl()->sanity_ == SANITY_INSANE)
428 {
429 throw Exception(getImpl()->sanitytext_.c_str());
430 }
431
432 getImpl()->sanity_ = SANITY_INSANE;
433 getImpl()->sanitytext_ = "";
434
435
436 ///// COLORSPACES
437 StringSet existingColorSpaces;
438
439 // Confirm all ColorSpaces are valid
440 for(unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
441 {
442 if(!getImpl()->colorspaces_[i])
443 {
444 std::ostringstream os;
445 os << "Config failed sanitycheck. ";
446 os << "The colorspace at index " << i << " is null.";
447 getImpl()->sanitytext_ = os.str();
448 throw Exception(getImpl()->sanitytext_.c_str());
449 }
450
451 const char * name = getImpl()->colorspaces_[i]->getName();
452 if(!name || strlen(name) == 0)
453 {
454 std::ostringstream os;
455 os << "Config failed sanitycheck. ";
456 os << "The colorspace at index " << i << " is not named.";
457 getImpl()->sanitytext_ = os.str();
458 throw Exception(getImpl()->sanitytext_.c_str());
459 }
460
461 std::string namelower = pystring::lower(name);
462 StringSet::const_iterator it = existingColorSpaces.find(namelower);
463 if(it != existingColorSpaces.end())
464 {
465 std::ostringstream os;
466 os << "Config failed sanitycheck. ";
467 os << "Two colorspaces are defined with the same name, '";
468 os << namelower << "'.";
469 getImpl()->sanitytext_ = os.str();
470 throw Exception(getImpl()->sanitytext_.c_str());
471 }
472
473 existingColorSpaces.insert(namelower);
474 }
475
476 // Confirm all roles are valid
477 {
478 for(StringMap::const_iterator iter = getImpl()->roles_.begin(),
479 end = getImpl()->roles_.end(); iter!=end; ++iter)
480 {
481 int csindex = -1;
482 if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->second))
483 {
484 std::ostringstream os;
485 os << "Config failed sanitycheck. ";
486 os << "The role '" << iter->first << "' ";
487 os << "refers to a colorspace, '" << iter->second << "', ";
488 os << "which is not defined.";
489 getImpl()->sanitytext_ = os.str();
490 throw Exception(getImpl()->sanitytext_.c_str());
491 }
492
493 // Confirm no name conflicts between colorspaces and roles
494 if(FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->first))
495 {
496 std::ostringstream os;
497 os << "Config failed sanitycheck. ";
498 os << "The role '" << iter->first << "' ";
499 os << " is in conflict with a colorspace of the same name.";
500 getImpl()->sanitytext_ = os.str();
501 throw Exception(getImpl()->sanitytext_.c_str());
502 }
503 }
504 }
505
506 ///// DISPLAYS
507
508 int numviews = 0;
509
510 // Confirm all Displays transforms refer to colorspaces that exit
511 for(DisplayMap::const_iterator iter = getImpl()->displays_.begin();
512 iter != getImpl()->displays_.end();
513 ++iter)
514 {
515 std::string display = iter->first;
516 const ViewVec & views = iter->second;
517 if(views.empty())
518 {
519 std::ostringstream os;
520 os << "Config failed sanitycheck. ";
521 os << "The display '" << display << "' ";
522 os << "does not define any views.";
523 getImpl()->sanitytext_ = os.str();
524 throw Exception(getImpl()->sanitytext_.c_str());
525 }
526
527 for(unsigned int i=0; i<views.size(); ++i)
528 {
529 if(views[i].name.empty() || views[i].colorspace.empty())
530 {
531 std::ostringstream os;
532 os << "Config failed sanitycheck. ";
533 os << "The display '" << display << "' ";
534 os << "defines a view with an empty name and/or colorspace.";
535 getImpl()->sanitytext_ = os.str();
536 throw Exception(getImpl()->sanitytext_.c_str());
537 }
538
539 int csindex = -1;
540 if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, views[i].colorspace))
541 {
542 std::ostringstream os;
543 os << "Config failed sanitycheck. ";
544 os << "The display '" << display << "' ";
545 os << "refers to a colorspace, '" << views[i].colorspace << "', ";
546 os << "which is not defined.";
547 getImpl()->sanitytext_ = os.str();
548 throw Exception(getImpl()->sanitytext_.c_str());
549 }
550
551 // Confirm looks references exist
552 LookParseResult looks;
553 const LookParseResult::Options & options = looks.parse(views[i].looks);
554
555 for(unsigned int optionindex=0;
556 optionindex<options.size();
557 ++optionindex)
558 {
559 for(unsigned int tokenindex=0;
560 tokenindex<options[optionindex].size();
561 ++tokenindex)
562 {
563 std::string look = options[optionindex][tokenindex].name;
564
565 if(!look.empty() && !getLook(look.c_str()))
566 {
567 std::ostringstream os;
568 os << "Config failed sanitycheck. ";
569 os << "The display '" << display << "' ";
570 os << "refers to a look, '" << look << "', ";
571 os << "which is not defined.";
572 getImpl()->sanitytext_ = os.str();
573 throw Exception(getImpl()->sanitytext_.c_str());
574 }
575 }
576 }
577
578 ++numviews;
579 }
580 }
581
582 // Confirm at least one display entry exists.
583 if(numviews == 0)
584 {
585 std::ostringstream os;
586 os << "Config failed sanitycheck. ";
587 os << "No displays are specified.";
588 getImpl()->sanitytext_ = os.str();
589 throw Exception(getImpl()->sanitytext_.c_str());
590 }
591
592 // Confirm for all Transforms that reference internal colorspaces,
593 // the named space exists
594 {
595 ConstTransformVec allTransforms;
596 getImpl()->getAllIntenalTransforms(allTransforms);
597
598 std::set<std::string> colorSpaceNames;
599 for(unsigned int i=0; i<colorSpaceNames.size(); ++i)
600 {
601 GetColorSpaceReferences(colorSpaceNames, allTransforms[i]);
602 }
603
604 for(std::set<std::string>::iterator iter = colorSpaceNames.begin();
605 iter != colorSpaceNames.end(); ++iter)
606 {
607 int csindex = -1;
608 if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, *iter))
609 {
610 std::ostringstream os;
611 os << "Config failed sanitycheck. ";
612 os << "This config references a ColorSpace, '" << *iter << "', ";
613 os << "which is not defined.";
614 getImpl()->sanitytext_ = os.str();
615 throw Exception(getImpl()->sanitytext_.c_str());
616 }
617 }
618 }
619
620 ///// LOOKS
621
622 // For all looks, confirm the process space exists and the look is named
623 for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
624 {
625 std::string name = getImpl()->looksList_[i]->getName();
626 if(name.empty())
627 {
628 std::ostringstream os;
629 os << "Config failed sanitycheck. ";
630 os << "The look at index '" << i << "' ";
631 os << "does not specify a name.";
632 getImpl()->sanitytext_ = os.str();
633 throw Exception(getImpl()->sanitytext_.c_str());
634 }
635
636 std::string processSpace = getImpl()->looksList_[i]->getProcessSpace();
637 if(processSpace.empty())
638 {
639 std::ostringstream os;
640 os << "Config failed sanitycheck. ";
641 os << "The look '" << name << "' ";
642 os << "does not specify a process space.";
643 getImpl()->sanitytext_ = os.str();
644 throw Exception(getImpl()->sanitytext_.c_str());
645 }
646
647 int csindex=0;
648 if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, processSpace))
649 {
650 std::ostringstream os;
651 os << "Config failed sanitycheck. ";
652 os << "The look '" << name << "' ";
653 os << "specifies a process color space, '";
654 os << processSpace << "', which is not defined.";
655 getImpl()->sanitytext_ = os.str();
656 throw Exception(getImpl()->sanitytext_.c_str());
657 }
658 }
659
660
661
662 // Everything is groovy.
663 getImpl()->sanity_ = SANITY_SANE;
664 }
665
666 ///////////////////////////////////////////////////////////////////////////
667
668 const char * Config::getDescription() const
669 {
670 return getImpl()->description_.c_str();
671 }
672
673 void Config::setDescription(const char * description)
674 {
675 getImpl()->description_ = description;
676
677 AutoMutex lock(getImpl()->cacheidMutex_);
678 getImpl()->resetCacheIDs();
679 }
680
681
682 // RESOURCES //////////////////////////////////////////////////////////////
683
684 ConstContextRcPtr Config::getCurrentContext() const
685 {
686 return getImpl()->context_;
687 }
688
689 void Config::addEnvironmentVar(const char * name, const char * defaultValue)
690 {
691 if(defaultValue)
692 {
693 getImpl()->env_[std::string(name)] = std::string(defaultValue);
694 getImpl()->context_->setStringVar(name, defaultValue);
695 }
696 else
697 {
698 StringMap::iterator iter = getImpl()->env_.find(std::string(name));
699 if(iter != getImpl()->env_.end()) getImpl()->env_.erase(iter);
700 }
701
702 AutoMutex lock(getImpl()->cacheidMutex_);
703 getImpl()->resetCacheIDs();
704 }
705
706 int Config::getNumEnvironmentVars() const
707 {
708 return static_cast<int>(getImpl()->env_.size());
709 }
710
711 const char * Config::getEnvironmentVarNameByIndex(int index) const
712 {
713 if(index < 0 || index >= (int)getImpl()->env_.size()) return "";
714 StringMap::const_iterator iter = getImpl()->env_.begin();
715 for(int i = 0; i < index; ++i) ++iter;
716 return iter->first.c_str();
717 }
718
719 const char * Config::getEnvironmentVarDefault(const char * name) const
720 {
721 return LookupEnvironment(getImpl()->env_, name);
722 }
723
724 void Config::clearEnvironmentVars()
725 {
726 getImpl()->env_.clear();
727 getImpl()->context_->clearStringVars();
728
729 AutoMutex lock(getImpl()->cacheidMutex_);
730 getImpl()->resetCacheIDs();
731 }
732
733 void Config::setEnvironmentMode(EnvironmentMode mode)
734 {
735 getImpl()->context_->setEnvironmentMode(mode);
736
737 AutoMutex lock(getImpl()->cacheidMutex_);
738 getImpl()->resetCacheIDs();
739 }
740
741 EnvironmentMode Config::getEnvironmentMode() const
742 {
743 return getImpl()->context_->getEnvironmentMode();
744 }
745
746 void Config::loadEnvironment()
747 {
748 getImpl()->context_->loadEnvironment();
749
750 AutoMutex lock(getImpl()->cacheidMutex_);
751 getImpl()->resetCacheIDs();
752 }
753
754 const char * Config::getSearchPath() const
755 {
756 return getImpl()->context_->getSearchPath();
757 }
758
759 void Config::setSearchPath(const char * path)
760 {
761 getImpl()->context_->setSearchPath(path);
762
763 AutoMutex lock(getImpl()->cacheidMutex_);
764 getImpl()->resetCacheIDs();
765 }
766
767 const char * Config::getWorkingDir() const
768 {
769 return getImpl()->context_->getWorkingDir();
770 }
771
772 void Config::setWorkingDir(const char * dirname)
773 {
774 getImpl()->context_->setWorkingDir(dirname);
775
776 AutoMutex lock(getImpl()->cacheidMutex_);
777 getImpl()->resetCacheIDs();
778 }
779
780
781 ///////////////////////////////////////////////////////////////////////////
782
783 int Config::getNumColorSpaces() const
784 {
785 return static_cast<int>(getImpl()->colorspaces_.size());
786 }
787
788 const char * Config::getColorSpaceNameByIndex(int index) const
789 {
790 if(index<0 || index >= (int)getImpl()->colorspaces_.size())
791 {
792 return "";
793 }
794
795 return getImpl()->colorspaces_[index]->getName();
796 }
797
798 ConstColorSpaceRcPtr Config::getColorSpace(const char * name) const
799 {
800 int index = getIndexForColorSpace(name);
801 if(index<0 || index >= (int)getImpl()->colorspaces_.size())
802 {
803 return ColorSpaceRcPtr();
804 }
805
806 return getImpl()->colorspaces_[index];
807 }
808
809 int Config::getIndexForColorSpace(const char * name) const
810 {
811 int csindex = -1;
812
813 // Check to see if the name is a color space
814 if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
815 {
816 return csindex;
817 }
818
819 // Check to see if the name is a role
820 const char* csname = LookupRole(getImpl()->roles_, name);
821 if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
822 {
823 return csindex;
824 }
825
826 // Is a default role defined?
827 // (And, are we allowed to use it)
828 if(!getImpl()->strictParsing_)
829 {
830 csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
831 if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
832 {
833 return csindex;
834 }
835 }
836
837 return -1;
838 }
839
840 void Config::addColorSpace(const ConstColorSpaceRcPtr & original)
841 {
842 ColorSpaceRcPtr cs = original->createEditableCopy();
843
844 std::string name = cs->getName();
845 if(name.empty())
846 throw Exception("Cannot addColorSpace with an empty name.");
847
848 // Check to see if the colorspace already exists
849 int csindex = -1;
850 if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
851 {
852 getImpl()->colorspaces_[csindex] = cs;
853 }
854 else
855 {
856 // Otherwise, add it
857 getImpl()->colorspaces_.push_back( cs );
858 }
859
860 AutoMutex lock(getImpl()->cacheidMutex_);
861 getImpl()->resetCacheIDs();
862 }
863
864 void Config::clearColorSpaces()
865 {
866 getImpl()->colorspaces_.clear();
867 }
868
869
870
871
872
873
874 const char * Config::parseColorSpaceFromString(const char * str) const
875 {
876 if(!str) return "";
877
878 // Search the entire filePath, including directory name (if provided)
879 // convert the filename to lowercase.
880 std::string fullstr = pystring::lower(std::string(str));
881
882 // See if it matches a lut name.
883 // This is the position of the RIGHT end of the colorspace substring, not the left
884 int rightMostColorPos=-1;
885 std::string rightMostColorspace = "";
886 int rightMostColorSpaceIndex = -1;
887
888 // Find the right-most occcurance within the string for each colorspace.
889 for (unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
890 {
891 std::string csname = pystring::lower(getImpl()->colorspaces_[i]->getName());
892
893 // find right-most extension matched in filename
894 int colorspacePos = pystring::rfind(fullstr, csname);
895 if(colorspacePos < 0)
896 continue;
897
898 // If we have found a match, move the pointer over to the right end of the substring
899 // This will allow us to find the longest name that matches the rightmost colorspace
900 colorspacePos += (int)csname.size();
901
902 if ( (colorspacePos > rightMostColorPos) ||
903 ((colorspacePos == rightMostColorPos) && (csname.size() > rightMostColorspace.size()))
904 )
905 {
906 rightMostColorPos = colorspacePos;
907 rightMostColorspace = csname;
908 rightMostColorSpaceIndex = i;
909 }
910 }
911
912 if(rightMostColorSpaceIndex>=0)
913 {
914 return getImpl()->colorspaces_[rightMostColorSpaceIndex]->getName();
915 }
916
917 if(!getImpl()->strictParsing_)
918 {
919 // Is a default role defined?
920 const char* csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
921 if(csname && *csname)
922 {
923 int csindex = -1;
924 if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
925 {
926 // This is necessary to not return a reference to
927 // a local variable.
928 return getImpl()->colorspaces_[csindex]->getName();
929 }
930 }
931 }
932
933 return "";
934 }
935
936 bool Config::isStrictParsingEnabled() const
937 {
938 return getImpl()->strictParsing_;
939 }
940
941 void Config::setStrictParsingEnabled(bool enabled)
942 {
943 getImpl()->strictParsing_ = enabled;
944
945 AutoMutex lock(getImpl()->cacheidMutex_);
946 getImpl()->resetCacheIDs();
947 }
948
949 // Roles
950 void Config::setRole(const char * role, const char * colorSpaceName)
951 {
952 // Set the role
953 if(colorSpaceName)
954 {
955 getImpl()->roles_[pystring::lower(role)] = std::string(colorSpaceName);
956 }
957 // Unset the role
958 else
959 {
960 StringMap::iterator iter = getImpl()->roles_.find(pystring::lower(role));
961 if(iter != getImpl()->roles_.end())
962 {
963 getImpl()->roles_.erase(iter);
964 }
965 }
966
967 AutoMutex lock(getImpl()->cacheidMutex_);
968 getImpl()->resetCacheIDs();
969 }
970
971 int Config::getNumRoles() const
972 {
973 return static_cast<int>(getImpl()->roles_.size());
974 }
975
976 bool Config::hasRole(const char * role) const
977 {
978 const char* rname = LookupRole(getImpl()->roles_, role);
979 return rname && *rname;
980 }
981
982 const char * Config::getRoleName(int index) const
983 {
984 if(index < 0 || index >= (int)getImpl()->roles_.size()) return "";
985 StringMap::const_iterator iter = getImpl()->roles_.begin();
986 for(int i = 0; i < index; ++i) ++iter;
987 return iter->first.c_str();
988 }
989
990 ///////////////////////////////////////////////////////////////////////////
991 //
992 // Display/View Registration
993
994
995 const char * Config::getDefaultDisplay() const
996 {
997 if(getImpl()->displayCache_.empty())
998 {
999 ComputeDisplays(getImpl()->displayCache_,
1000 getImpl()->displays_,
1001 getImpl()->activeDisplays_,
1002 getImpl()->activeDisplaysEnvOverride_);
1003 }
1004
1005 int index = -1;
1006
1007 if(!getImpl()->activeDisplaysEnvOverride_.empty())
1008 {
1009 StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplaysEnvOverride_,
1010 getImpl()->displayCache_);
1011 if(!orderedDisplays.empty())
1012 {
1013 index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
1014 }
1015 }
1016 else if(!getImpl()->activeDisplays_.empty())
1017 {
1018 StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplays_,
1019 getImpl()->displayCache_);
1020 if(!orderedDisplays.empty())
1021 {
1022 index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
1023 }
1024 }
1025
1026 if(index >= 0)
1027 {
1028 return getImpl()->displayCache_[index].c_str();
1029 }
1030
1031 if(!getImpl()->displayCache_.empty())
1032 {
1033 return getImpl()->displayCache_[0].c_str();
1034 }
1035
1036 return "";
1037 }
1038
1039
1040 int Config::getNumDisplays() const
1041 {
1042 if(getImpl()->displayCache_.empty())
1043 {
1044 ComputeDisplays(getImpl()->displayCache_,
1045 getImpl()->displays_,
1046 getImpl()->activeDisplays_,
1047 getImpl()->activeDisplaysEnvOverride_);
1048 }
1049
1050 return static_cast<int>(getImpl()->displayCache_.size());
1051 }
1052
1053 const char * Config::getDisplay(int index) const
1054 {
1055 if(getImpl()->displayCache_.empty())
1056 {
1057 ComputeDisplays(getImpl()->displayCache_,
1058 getImpl()->displays_,
1059 getImpl()->activeDisplays_,
1060 getImpl()->activeDisplaysEnvOverride_);
1061 }
1062
1063 if(index>=0 || index < static_cast<int>(getImpl()->displayCache_.size()))
1064 {
1065 return getImpl()->displayCache_[index].c_str();
1066 }
1067
1068 return "";
1069 }
1070
1071 const char * Config::getDefaultView(const char * display) const
1072 {
1073 if(getImpl()->displayCache_.empty())
1074 {
1075 ComputeDisplays(getImpl()->displayCache_,
1076 getImpl()->displays_,
1077 getImpl()->activeDisplays_,
1078 getImpl()->activeDisplaysEnvOverride_);
1079 }
1080
1081 if(!display) return "";
1082
1083 DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
1084 if(iter == getImpl()->displays_.end()) return "";
1085
1086 const ViewVec & views = iter->second;
1087
1088 StringVec masterViews;
1089 for(unsigned int i=0; i<views.size(); ++i)
1090 {
1091 masterViews.push_back(views[i].name);
1092 }
1093
1094 int index = -1;
1095
1096 if(!getImpl()->activeViewsEnvOverride_.empty())
1097 {
1098 StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViewsEnvOverride_,
1099 masterViews);
1100 if(!orderedViews.empty())
1101 {
1102 index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
1103 }
1104 }
1105 else if(!getImpl()->activeViews_.empty())
1106 {
1107 StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViews_,
1108 masterViews);
1109 if(!orderedViews.empty())
1110 {
1111 index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
1112 }
1113 }
1114
1115 if(index >= 0)
1116 {
1117 return views[index].name.c_str();
1118 }
1119
1120 if(!views.empty())
1121 {
1122 return views[0].name.c_str();
1123 }
1124
1125 return "";
1126 }
1127
1128 int Config::getNumViews(const char * display) const
1129 {
1130 if(getImpl()->displayCache_.empty())
1131 {
1132 ComputeDisplays(getImpl()->displayCache_,
1133 getImpl()->displays_,
1134 getImpl()->activeDisplays_,
1135 getImpl()->activeDisplaysEnvOverride_);
1136 }
1137
1138 if(!display) return 0;
1139
1140 DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
1141 if(iter == getImpl()->displays_.end()) return 0;
1142
1143 const ViewVec & views = iter->second;
1144 return static_cast<int>(views.size());
1145 }
1146
1147 const char * Config::getView(const char * display, int index) const
1148 {
1149 if(getImpl()->displayCache_.empty())
1150 {
1151 ComputeDisplays(getImpl()->displayCache_,
1152 getImpl()->displays_,
1153 getImpl()->activeDisplays_,
1154 getImpl()->activeDisplaysEnvOverride_);
1155 }
1156
1157 if(!display) return "";
1158
1159 DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
1160 if(iter == getImpl()->displays_.end()) return "";
1161
1162 const ViewVec & views = iter->second;
1163 return views[index].name.c_str();
1164 }
1165
1166 const char * Config::getDisplayColorSpaceName(const char * display, const char * view) const
1167 {
1168 if(!display || !view) return "";
1169
1170 DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
1171 if(iter == getImpl()->displays_.end()) return "";
1172
1173 const ViewVec & views = iter->second;
1174 int index = find_view(views, view);
1175 if(index<0) return "";
1176
1177 return views[index].colorspace.c_str();
1178 }
1179
1180 const char * Config::getDisplayLooks(const char * display, const char * view) const
1181 {
1182 if(!display || !view) return "";
1183
1184 DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
1185 if(iter == getImpl()->displays_.end()) return "";
1186
1187 const ViewVec & views = iter->second;
1188 int index = find_view(views, view);
1189 if(index<0) return "";
1190
1191 return views[index].looks.c_str();
1192 }
1193
1194 void Config::addDisplay(const char * display, const char * view,
1195 const char * colorSpaceName, const char * lookName)
1196 {
1197
1198 if(!display || !view || !colorSpaceName || !lookName) return;
1199
1200 AddDisplay(getImpl()->displays_,
1201 display, view, colorSpaceName, lookName);
1202 getImpl()->displayCache_.clear();
1203
1204 AutoMutex lock(getImpl()->cacheidMutex_);
1205 getImpl()->resetCacheIDs();
1206 }
1207
1208 void Config::clearDisplays()
1209 {
1210 getImpl()->displays_.clear();
1211 getImpl()->displayCache_.clear();
1212
1213 AutoMutex lock(getImpl()->cacheidMutex_);
1214 getImpl()->resetCacheIDs();
1215 }
1216
1217 void Config::setActiveDisplays(const char * displays)
1218 {
1219 getImpl()->activeDisplays_.clear();
1220 SplitStringEnvStyle(getImpl()->activeDisplays_, displays);
1221
1222 getImpl()->displayCache_.clear();
1223
1224 AutoMutex lock(getImpl()->cacheidMutex_);
1225 getImpl()->resetCacheIDs();
1226 }
1227
1228 const char * Config::getActiveDisplays() const
1229 {
1230 getImpl()->activeDisplaysStr_ = JoinStringEnvStyle(getImpl()->activeDisplays_);
1231 return getImpl()->activeDisplaysStr_.c_str();
1232 }
1233
1234 void Config::setActiveViews(const char * views)
1235 {
1236 getImpl()->activeViews_.clear();
1237 SplitStringEnvStyle(getImpl()->activeViews_, views);
1238
1239 getImpl()->displayCache_.clear();
1240
1241 AutoMutex lock(getImpl()->cacheidMutex_);
1242 getImpl()->resetCacheIDs();
1243 }
1244
1245 const char * Config::getActiveViews() const
1246 {
1247 getImpl()->activeViewsStr_ = JoinStringEnvStyle(getImpl()->activeViews_);
1248 return getImpl()->activeViewsStr_.c_str();
1249 }
1250
1251 ///////////////////////////////////////////////////////////////////////////
1252
1253
1254 void Config::getDefaultLumaCoefs(float * c3) const
1255 {
1256 memcpy(c3, &getImpl()->defaultLumaCoefs_[0], 3*sizeof(float));
1257 }
1258
1259 void Config::setDefaultLumaCoefs(const float * c3)
1260 {
1261 memcpy(&getImpl()->defaultLumaCoefs_[0], c3, 3*sizeof(float));
1262
1263 AutoMutex lock(getImpl()->cacheidMutex_);
1264 getImpl()->resetCacheIDs();
1265 }
1266
1267
1268
1269
1270 ///////////////////////////////////////////////////////////////////////////
1271
1272
1273
1274
1275 ConstLookRcPtr Config::getLook(const char * name) const
1276 {
1277 std::string namelower = pystring::lower(name);
1278
1279 for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
1280 {
1281 if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
1282 {
1283 return getImpl()->looksList_[i];
1284 }
1285 }
1286
1287 return ConstLookRcPtr();
1288 }
1289
1290 int Config::getNumLooks() const
1291 {
1292 return static_cast<int>(getImpl()->looksList_.size());
1293 }
1294
1295 const char * Config::getLookNameByIndex(int index) const
1296 {
1297 if(index<0 || index>=static_cast<int>(getImpl()->looksList_.size()))
1298 {
1299 return "";
1300 }
1301
1302 return getImpl()->looksList_[index]->getName();
1303 }
1304
1305 void Config::addLook(const ConstLookRcPtr & look)
1306 {
1307 std::string name = look->getName();
1308 if(name.empty())
1309 throw Exception("Cannot addLook with an empty name.");
1310
1311 std::string namelower = pystring::lower(name);
1312
1313 // If the look exists, replace it
1314 for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
1315 {
1316 if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
1317 {
1318 getImpl()->looksList_[i] = look->createEditableCopy();
1319 return;
1320 }
1321 }
1322
1323 // Otherwise, add it
1324 getImpl()->looksList_.push_back(look->createEditableCopy());
1325
1326 AutoMutex lock(getImpl()->cacheidMutex_);
1327 getImpl()->resetCacheIDs();
1328 }
1329
1330 void Config::clearLooks()
1331 {
1332 getImpl()->looksList_.clear();
1333
1334 AutoMutex lock(getImpl()->cacheidMutex_);
1335 getImpl()->resetCacheIDs();
1336 }
1337
1338 ///////////////////////////////////////////////////////////////////////////
1339
1340
1341
1342 ConstProcessorRcPtr Config::getProcessor(const ConstColorSpaceRcPtr & src,
1343 const ConstColorSpaceRcPtr & dst) const
1344 {
1345 ConstContextRcPtr context = getCurrentContext();
1346 return getProcessor(context, src, dst);
1347 }
1348
1349 ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
1350 const ConstColorSpaceRcPtr & src,
1351 const ConstColorSpaceRcPtr & dst) const
1352 {
1353 if(!src)
1354 {
1355 throw Exception("Config::GetProcessor failed. Source colorspace is null.");
1356 }
1357 if(!dst)
1358 {
1359 throw Exception("Config::GetProcessor failed. Destination colorspace is null.");
1360 }
1361
1362 ProcessorRcPtr processor = Processor::Create();
1363 processor->getImpl()->addColorSpaceConversion(*this, context, src, dst);
1364 processor->getImpl()->finalize();
1365 return processor;
1366 }
1367
1368 ConstProcessorRcPtr Config::getProcessor(const char * srcName,
1369 const char * dstName) const
1370 {
1371 ConstContextRcPtr context = getCurrentContext();
1372 return getProcessor(context, srcName, dstName);
1373 }
1374
1375 //! Names can be colorspace name or role name
1376 ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
1377 const char * srcName,
1378 const char * dstName) const
1379 {
1380 ConstColorSpaceRcPtr src = getColorSpace(srcName);
1381 if(!src)
1382 {
1383 std::ostringstream os;
1384 os << "Could not find colorspace '" << srcName << "'.";
1385 throw Exception(os.str().c_str());
1386 }
1387
1388 ConstColorSpaceRcPtr dst = getColorSpace(dstName);
1389 if(!dst)
1390 {
1391 std::ostringstream os;
1392 os << "Could not find colorspace '" << dstName << "'.";
1393 throw Exception(os.str().c_str());
1394 }
1395
1396 return getProcessor(context, src, dst);
1397 }
1398
1399
1400 ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform) const
1401 {
1402 return getProcessor(transform, TRANSFORM_DIR_FORWARD);
1403 }
1404
1405
1406 ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform,
1407 TransformDirection direction) const
1408 {
1409 ConstContextRcPtr context = getCurrentContext();
1410 return getProcessor(context, transform, direction);
1411 }
1412
1413 ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
1414 const ConstTransformRcPtr& transform,
1415 TransformDirection direction) const
1416 {
1417 ProcessorRcPtr processor = Processor::Create();
1418 processor->getImpl()->addTransform(*this, context, transform, direction);
1419 processor->getImpl()->finalize();
1420 return processor;
1421 }
1422
1423 std::ostream& operator<< (std::ostream& os, const Config& config)
1424 {
1425 config.serialize(os);
1426 return os;
1427 }
1428
1429 ///////////////////////////////////////////////////////////////////////////
1430 // CacheID
1431
1432 const char * Config::getCacheID() const
1433 {
1434 return getCacheID(getCurrentContext());
1435 }
1436
1437 const char * Config::getCacheID(const ConstContextRcPtr & context) const
1438 {
1439 AutoMutex lock(getImpl()->cacheidMutex_);
1440
1441 // A null context will use the empty cacheid
1442 std::string contextcacheid = "";
1443 if(context) contextcacheid = context->getCacheID();
1444
1445 StringMap::const_iterator cacheiditer = getImpl()->cacheids_.find(contextcacheid);
1446 if(cacheiditer != getImpl()->cacheids_.end())
1447 {
1448 return cacheiditer->second.c_str();
1449 }
1450
1451 // Include the hash of the yaml config serialization
1452 if(getImpl()->cacheidnocontext_.empty())
1453 {
1454 std::stringstream cacheid;
1455 serialize(cacheid);
1456 std::string fullstr = cacheid.str();
1457 getImpl()->cacheidnocontext_ = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
1458 }
1459
1460 // Also include all file references, using the context (if specified)
1461 std::string fileReferencesFashHash = "";
1462 if(context)
1463 {
1464 std::ostringstream filehash;
1465
1466 ConstTransformVec allTransforms;
1467 getImpl()->getAllIntenalTransforms(allTransforms);
1468
1469 std::set<std::string> files;
1470 for(unsigned int i=0; i<allTransforms.size(); ++i)
1471 {
1472 GetFileReferences(files, allTransforms[i]);
1473 }
1474
1475 for(std::set<std::string>::iterator iter = files.begin();
1476 iter != files.end(); ++iter)
1477 {
1478 if(iter->empty()) continue;
1479 filehash << *iter << "=";
1480
1481 try
1482 {
1483 std::string resolvedLocation = context->resolveFileLocation(iter->c_str());
1484 filehash << GetFastFileHash(resolvedLocation) << " ";
1485 }
1486 catch(...)
1487 {
1488 filehash << "? ";
1489 continue;
1490 }
1491 }
1492
1493 std::string fullstr = filehash.str();
1494 fileReferencesFashHash = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
1495 }
1496
1497 getImpl()->cacheids_[contextcacheid] = getImpl()->cacheidnocontext_ + ":" + fileReferencesFashHash;
1498 return getImpl()->cacheids_[contextcacheid].c_str();
1499 }
1500
1501
1502 ///////////////////////////////////////////////////////////////////////////
1503 // Serialization
1504
1505 void Config::serialize(std::ostream& os) const
1506 {
1507 try
1508 {
1509 getImpl()->io_.write(os, this);
1510 }
1511 catch( const std::exception & e)
1512 {
1513 std::ostringstream error;
1514 error << "Error building YAML: " << e.what();
1515 throw Exception(error.str().c_str());
1516 }
1517 }
1518
1519 void Config::Impl::resetCacheIDs()
1520 {
1521 cacheids_.clear();
1522 cacheidnocontext_ = "";
1523 sanity_ = SANITY_UNKNOWN;
1524 sanitytext_ = "";
1525 }
1526
1527 void Config::Impl::getAllIntenalTransforms(ConstTransformVec & transformVec) const
1528 {
1529 // Grab all transforms from the ColorSpaces
1530 for(unsigned int i=0; i<colorspaces_.size(); ++i)
1531 {
1532 if(colorspaces_[i]->getTransform(COLORSPACE_DIR_TO_REFERENCE))
1533 transformVec.push_back(colorspaces_[i]->getTransform(COLORSPACE_DIR_TO_REFERENCE));
1534 if(colorspaces_[i]->getTransform(COLORSPACE_DIR_FROM_REFERENCE))
1535 transformVec.push_back(colorspaces_[i]->getTransform(COLORSPACE_DIR_FROM_REFERENCE));
1536 }
1537
1538 // Grab all transforms from the Looks
1539 for(unsigned int i=0; i<looksList_.size(); ++i)
1540 {
1541 if(looksList_[i]->getTransform())
1542 transformVec.push_back(looksList_[i]->getTransform());
1543 if(looksList_[i]->getInverseTransform())
1544 transformVec.push_back(looksList_[i]->getInverseTransform());
1545 }
1546
1547 }
1548 }
1549 OCIO_NAMESPACE_EXIT
1550
1551 ///////////////////////////////////////////////////////////////////////////////
1552
1553 #ifdef OCIO_UNIT_TEST
1554
1555 namespace OCIO = OCIO_NAMESPACE;
1556 #include "UnitTest.h"
1557
1558 #include <sys/stat.h>
1559 #include "pystring/pystring.h"
1560
1561 #if 0
1562 OIIO_ADD_TEST(Config, test_searchpath_filesystem)
1563 {
1564
1565 OCIO::EnvMap env = OCIO::GetEnvMap();
1566 std::string OCIO_TEST_AREA("$OCIO_TEST_AREA");
1567 EnvExpand(&OCIO_TEST_AREA, &env);
1568
1569 OCIO::ConfigRcPtr config = OCIO::Config::Create();
1570
1571 // basic get/set/expand
1572 config->setSearchPath("."
1573 ":$OCIO_TEST1"
1574 ":/$OCIO_JOB/${OCIO_SEQ}/$OCIO_SHOT/ocio");
1575
1576 OIIO_CHECK_ASSERT(strcmp(config->getSearchPath(),
1577 ".:$OCIO_TEST1:/$OCIO_JOB/${OCIO_SEQ}/$OCIO_SHOT/ocio") == 0);
1578 OIIO_CHECK_ASSERT(strcmp(config->getSearchPath(true),
1579 ".:foobar:/meatballs/cheesecake/mb-cc-001/ocio") == 0);
1580
1581 // find some files
1582 config->setSearchPath(".."
1583 ":$OCIO_TEST1"
1584 ":${OCIO_TEST_AREA}/test_search/one"
1585 ":$OCIO_TEST_AREA/test_search/two");
1586
1587 // setup for search test
1588 std::string base_dir("$OCIO_TEST_AREA/test_search/");
1589 EnvExpand(&base_dir, &env);
1590 mkdir(base_dir.c_str(), 0777);
1591
1592 std::string one_dir("$OCIO_TEST_AREA/test_search/one/");
1593 EnvExpand(&one_dir, &env);
1594 mkdir(one_dir.c_str(), 0777);
1595
1596 std::string two_dir("$OCIO_TEST_AREA/test_search/two/");
1597 EnvExpand(&two_dir, &env);
1598 mkdir(two_dir.c_str(), 0777);
1599
1600 std::string lut1(one_dir+"somelut1.lut");
1601 std::ofstream somelut1(lut1.c_str());
1602 somelut1.close();
1603
1604 std::string lut2(two_dir+"somelut2.lut");
1605 std::ofstream somelut2(lut2.c_str());
1606 somelut2.close();
1607
1608 std::string lut3(two_dir+"somelut3.lut");
1609 std::ofstream somelut3(lut3.c_str());
1610 somelut3.close();
1611
1612 std::string lutdotdot(OCIO_TEST_AREA+"/lutdotdot.lut");
1613 std::ofstream somelutdotdot(lutdotdot.c_str());
1614 somelutdotdot.close();
1615
1616 // basic search test
1617 OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut1.lut"),
1618 lut1.c_str()) == 0);
1619 OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut2.lut"),
1620 lut2.c_str()) == 0);
1621 OIIO_CHECK_ASSERT(strcmp(config->findFile("somelut3.lut"),
1622 lut3.c_str()) == 0);
1623 OIIO_CHECK_ASSERT(strcmp(config->findFile("lutdotdot.lut"),
1624 lutdotdot.c_str()) == 0);
1625
1626 }
1627 #endif
1628
OIIO_ADD_TEST(Config,InternalRawProfile)1629 OIIO_ADD_TEST(Config, InternalRawProfile)
1630 {
1631 std::istringstream is;
1632 is.str(OCIO::INTERNAL_RAW_PROFILE);
1633 OIIO_CHECK_NO_THROW(OCIO::ConstConfigRcPtr config = OCIO::Config::CreateFromStream(is));
1634 }
1635
OIIO_ADD_TEST(Config,SimpleConfig)1636 OIIO_ADD_TEST(Config, SimpleConfig)
1637 {
1638
1639 std::string SIMPLE_PROFILE =
1640 "ocio_profile_version: 1\n"
1641 "resource_path: luts\n"
1642 "strictparsing: false\n"
1643 "luma: [0.2126, 0.7152, 0.0722]\n"
1644 "roles:\n"
1645 " compositing_log: lgh\n"
1646 " default: raw\n"
1647 " scene_linear: lnh\n"
1648 "displays:\n"
1649 " sRGB:\n"
1650 " - !<View> {name: Film1D, colorspace: vd8}\n"
1651 " - !<View> {name: Log, colorspace: lg10}\n"
1652 " - !<View> {name: Raw, colorspace: raw}\n"
1653 "colorspaces:\n"
1654 " - !<ColorSpace>\n"
1655 " name: raw\n"
1656 " family: raw\n"
1657 " equalitygroup: \n"
1658 " bitdepth: 32f\n"
1659 " description: |\n"
1660 " A raw color space. Conversions to and from this space are no-ops.\n"
1661 " isdata: true\n"
1662 " allocation: uniform\n"
1663 " - !<ColorSpace>\n"
1664 " name: lnh\n"
1665 " family: ln\n"
1666 " equalitygroup: \n"
1667 " bitdepth: 16f\n"
1668 " description: |\n"
1669 " The show reference space. This is a sensor referred linear\n"
1670 " representation of the scene with primaries that correspond to\n"
1671 " scanned film. 0.18 in this space corresponds to a properly\n"
1672 " exposed 18% grey card.\n"
1673 " isdata: false\n"
1674 " allocation: lg2\n"
1675 " - !<ColorSpace>\n"
1676 " name: loads_of_transforms\n"
1677 " family: vd8\n"
1678 " equalitygroup: \n"
1679 " bitdepth: 8ui\n"
1680 " description: 'how many transforms can we use?'\n"
1681 " isdata: false\n"
1682 " allocation: uniform\n"
1683 " to_reference: !<GroupTransform>\n"
1684 " direction: forward\n"
1685 " children:\n"
1686 " - !<FileTransform>\n"
1687 " src: diffusemult.spimtx\n"
1688 " interpolation: unknown\n"
1689 " - !<ColorSpaceTransform>\n"
1690 " src: vd8\n"
1691 " dst: lnh\n"
1692 " - !<ExponentTransform>\n"
1693 " value: [2.2, 2.2, 2.2, 1]\n"
1694 " - !<MatrixTransform>\n"
1695 " matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]\n"
1696 " offset: [0, 0, 0, 0]\n"
1697 " - !<CDLTransform>\n"
1698 " slope: [1, 1, 1]\n"
1699 " offset: [0, 0, 0]\n"
1700 " power: [1, 1, 1]\n"
1701 " saturation: 1\n"
1702 "\n";
1703
1704 std::istringstream is;
1705 is.str(SIMPLE_PROFILE);
1706 OCIO::ConstConfigRcPtr config;
1707 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
1708 }
1709
OIIO_ADD_TEST(Config,Roles)1710 OIIO_ADD_TEST(Config, Roles)
1711 {
1712
1713 std::string SIMPLE_PROFILE =
1714 "ocio_profile_version: 1\n"
1715 "strictparsing: false\n"
1716 "roles:\n"
1717 " compositing_log: lgh\n"
1718 " default: raw\n"
1719 " scene_linear: lnh\n"
1720 "colorspaces:\n"
1721 " - !<ColorSpace>\n"
1722 " name: raw\n"
1723 " - !<ColorSpace>\n"
1724 " name: lnh\n"
1725 " - !<ColorSpace>\n"
1726 " name: lgh\n"
1727 "\n";
1728
1729 std::istringstream is;
1730 is.str(SIMPLE_PROFILE);
1731 OCIO::ConstConfigRcPtr config;
1732 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
1733
1734 OIIO_CHECK_EQUAL(config->getNumRoles(), 3);
1735
1736 OIIO_CHECK_ASSERT(config->hasRole("compositing_log") == true);
1737 OIIO_CHECK_ASSERT(config->hasRole("cheese") == false);
1738 OIIO_CHECK_ASSERT(config->hasRole("") == false);
1739
1740 OIIO_CHECK_ASSERT(strcmp(config->getRoleName(2), "scene_linear") == 0);
1741 OIIO_CHECK_ASSERT(strcmp(config->getRoleName(0), "compositing_log") == 0);
1742 OIIO_CHECK_ASSERT(strcmp(config->getRoleName(1), "default") == 0);
1743 OIIO_CHECK_ASSERT(strcmp(config->getRoleName(10), "") == 0);
1744 OIIO_CHECK_ASSERT(strcmp(config->getRoleName(-4), "") == 0);
1745
1746 }
1747
OIIO_ADD_TEST(Config,Serialize)1748 OIIO_ADD_TEST(Config, Serialize)
1749 {
1750
1751 OCIO::ConfigRcPtr config = OCIO::Config::Create();
1752 {
1753 OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
1754 cs->setName("testing");
1755 cs->setFamily("test");
1756 OCIO::FileTransformRcPtr transform1 = \
1757 OCIO::FileTransform::Create();
1758 OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();
1759 groupTransform->push_back(transform1);
1760 cs->setTransform(groupTransform, OCIO::COLORSPACE_DIR_TO_REFERENCE);
1761 config->addColorSpace(cs);
1762 config->setRole( OCIO::ROLE_COMPOSITING_LOG, cs->getName() );
1763 }
1764 {
1765 OCIO::ColorSpaceRcPtr cs = OCIO::ColorSpace::Create();
1766 cs->setName("testing2");
1767 cs->setFamily("test");
1768 OCIO::ExponentTransformRcPtr transform1 = \
1769 OCIO::ExponentTransform::Create();
1770 OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();
1771 groupTransform->push_back(transform1);
1772 cs->setTransform(groupTransform, OCIO::COLORSPACE_DIR_TO_REFERENCE);
1773 config->addColorSpace(cs);
1774 config->setRole( OCIO::ROLE_COMPOSITING_LOG, cs->getName() );
1775 }
1776
1777 // for testing
1778 //std::ofstream outfile("/tmp/test.ocio");
1779 //config->serialize(outfile);
1780 //outfile.close();
1781
1782 std::ostringstream os;
1783 config->serialize(os);
1784
1785 std::string PROFILE_OUT =
1786 "ocio_profile_version: 1\n"
1787 "\n"
1788 "search_path: \"\"\n"
1789 "strictparsing: true\n"
1790 "luma: [0.2126, 0.7152, 0.0722]\n"
1791 "\n"
1792 "roles:\n"
1793 " compositing_log: testing2\n"
1794 "\n"
1795 "displays:\n"
1796 " {}\n"
1797 "\n"
1798 "active_displays: []\n"
1799 "active_views: []\n"
1800 "\n"
1801 "colorspaces:\n"
1802 " - !<ColorSpace>\n"
1803 " name: testing\n"
1804 " family: test\n"
1805 " equalitygroup: \"\"\n"
1806 " bitdepth: unknown\n"
1807 " isdata: false\n"
1808 " allocation: uniform\n"
1809 " to_reference: !<GroupTransform>\n"
1810 " children:\n"
1811 " - !<FileTransform> {src: \"\", interpolation: unknown}\n"
1812 "\n"
1813 " - !<ColorSpace>\n"
1814 " name: testing2\n"
1815 " family: test\n"
1816 " equalitygroup: \"\"\n"
1817 " bitdepth: unknown\n"
1818 " isdata: false\n"
1819 " allocation: uniform\n"
1820 " to_reference: !<GroupTransform>\n"
1821 " children:\n"
1822 " - !<ExponentTransform> {value: [1, 1, 1, 1]}\n";
1823
1824 std::vector<std::string> osvec;
1825 OCIO::pystring::splitlines(os.str(), osvec);
1826 std::vector<std::string> PROFILE_OUTvec;
1827 OCIO::pystring::splitlines(PROFILE_OUT, PROFILE_OUTvec);
1828
1829 OIIO_CHECK_EQUAL(osvec.size(), PROFILE_OUTvec.size());
1830 for(unsigned int i = 0; i < PROFILE_OUTvec.size(); ++i)
1831 OIIO_CHECK_EQUAL(osvec[i], PROFILE_OUTvec[i]);
1832 }
1833
1834
OIIO_ADD_TEST(Config,SanityCheck)1835 OIIO_ADD_TEST(Config, SanityCheck)
1836 {
1837 {
1838 std::string SIMPLE_PROFILE =
1839 "ocio_profile_version: 1\n"
1840 "colorspaces:\n"
1841 " - !<ColorSpace>\n"
1842 " name: raw\n"
1843 " - !<ColorSpace>\n"
1844 " name: raw\n"
1845 "strictparsing: false\n"
1846 "roles:\n"
1847 " default: raw\n"
1848 "displays:\n"
1849 " sRGB:\n"
1850 " - !<View> {name: Raw, colorspace: raw}\n"
1851 "\n";
1852
1853 std::istringstream is;
1854 is.str(SIMPLE_PROFILE);
1855 OCIO::ConstConfigRcPtr config;
1856 OIIO_CHECK_THROW(config = OCIO::Config::CreateFromStream(is), OCIO::Exception);
1857 }
1858
1859 {
1860 std::string SIMPLE_PROFILE =
1861 "ocio_profile_version: 1\n"
1862 "colorspaces:\n"
1863 " - !<ColorSpace>\n"
1864 " name: raw\n"
1865 "strictparsing: false\n"
1866 "roles:\n"
1867 " default: raw\n"
1868 "displays:\n"
1869 " sRGB:\n"
1870 " - !<View> {name: Raw, colorspace: raw}\n"
1871 "\n";
1872
1873 std::istringstream is;
1874 is.str(SIMPLE_PROFILE);
1875 OCIO::ConstConfigRcPtr config;
1876 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
1877
1878 OIIO_CHECK_NO_THROW(config->sanityCheck());
1879 }
1880 }
1881
1882
OIIO_ADD_TEST(Config,EnvCheck)1883 OIIO_ADD_TEST(Config, EnvCheck)
1884 {
1885 {
1886 std::string SIMPLE_PROFILE =
1887 "ocio_profile_version: 1\n"
1888 "environment:\n"
1889 " SHOW: super\n"
1890 " SHOT: test\n"
1891 " SEQ: foo\n"
1892 " test: bar${cheese}\n"
1893 " cheese: chedder\n"
1894 "colorspaces:\n"
1895 " - !<ColorSpace>\n"
1896 " name: raw\n"
1897 "strictparsing: false\n"
1898 "roles:\n"
1899 " default: raw\n"
1900 "displays:\n"
1901 " sRGB:\n"
1902 " - !<View> {name: Raw, colorspace: raw}\n"
1903 "\n";
1904
1905 std::string SIMPLE_PROFILE2 =
1906 "ocio_profile_version: 1\n"
1907 "colorspaces:\n"
1908 " - !<ColorSpace>\n"
1909 " name: raw\n"
1910 "strictparsing: false\n"
1911 "roles:\n"
1912 " default: raw\n"
1913 "displays:\n"
1914 " sRGB:\n"
1915 " - !<View> {name: Raw, colorspace: raw}\n"
1916 "\n";
1917
1918
1919 std::string test("SHOW=bar");
1920 putenv((char *)test.c_str());
1921 std::string test2("TASK=lighting");
1922 putenv((char *)test2.c_str());
1923
1924 std::istringstream is;
1925 is.str(SIMPLE_PROFILE);
1926 OCIO::ConstConfigRcPtr config;
1927 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
1928 OIIO_CHECK_EQUAL(config->getNumEnvironmentVars(), 5);
1929 OIIO_CHECK_ASSERT(strcmp(config->getCurrentContext()->resolveStringVar("test${test}"),
1930 "testbarchedder") == 0);
1931 OIIO_CHECK_ASSERT(strcmp(config->getCurrentContext()->resolveStringVar("${SHOW}"),
1932 "bar") == 0);
1933 OIIO_CHECK_ASSERT(strcmp(config->getEnvironmentVarDefault("SHOW"), "super") == 0);
1934
1935 OCIO::ConfigRcPtr edit = config->createEditableCopy();
1936 edit->clearEnvironmentVars();
1937 OIIO_CHECK_EQUAL(edit->getNumEnvironmentVars(), 0);
1938
1939 edit->addEnvironmentVar("testing", "dupvar");
1940 edit->addEnvironmentVar("testing", "dupvar");
1941 edit->addEnvironmentVar("foobar", "testing");
1942 edit->addEnvironmentVar("blank", "");
1943 edit->addEnvironmentVar("dontadd", NULL);
1944 OIIO_CHECK_EQUAL(edit->getNumEnvironmentVars(), 3);
1945 edit->addEnvironmentVar("foobar", NULL); // remove
1946 OIIO_CHECK_EQUAL(edit->getNumEnvironmentVars(), 2);
1947 edit->clearEnvironmentVars();
1948
1949 edit->addEnvironmentVar("SHOW", "super");
1950 edit->addEnvironmentVar("SHOT", "test");
1951 edit->addEnvironmentVar("SEQ", "foo");
1952 edit->addEnvironmentVar("test", "bar${cheese}");
1953 edit->addEnvironmentVar("cheese", "chedder");
1954
1955 //Test
1956 OCIO::LoggingLevel loglevel = OCIO::GetLoggingLevel();
1957 OCIO::SetLoggingLevel(OCIO::LOGGING_LEVEL_DEBUG);
1958 is.str(SIMPLE_PROFILE2);
1959 OCIO::ConstConfigRcPtr noenv;
1960 OIIO_CHECK_NO_THROW(noenv = OCIO::Config::CreateFromStream(is));
1961 OIIO_CHECK_ASSERT(strcmp(noenv->getCurrentContext()->resolveStringVar("${TASK}"),
1962 "lighting") == 0);
1963 OCIO::SetLoggingLevel(loglevel);
1964
1965 OIIO_CHECK_EQUAL(edit->getEnvironmentMode(), OCIO::ENV_ENVIRONMENT_LOAD_PREDEFINED);
1966 edit->setEnvironmentMode(OCIO::ENV_ENVIRONMENT_LOAD_ALL);
1967 OIIO_CHECK_EQUAL(edit->getEnvironmentMode(), OCIO::ENV_ENVIRONMENT_LOAD_ALL);
1968
1969 }
1970 }
1971
OIIO_ADD_TEST(Config,RoleWithoutColorSpace)1972 OIIO_ADD_TEST(Config, RoleWithoutColorSpace)
1973 {
1974 OCIO::ConfigRcPtr config = OCIO::Config::Create()->createEditableCopy();
1975 config->setRole("reference", "UnknownColorSpace");
1976
1977 std::ostringstream os;
1978 OIIO_CHECK_THROW(config->serialize(os), OCIO::Exception);
1979 }
1980
OIIO_ADD_TEST(Config,Env_colorspace_name)1981 OIIO_ADD_TEST(Config, Env_colorspace_name)
1982 {
1983 const std::string MY_OCIO_CONFIG =
1984 "ocio_profile_version: 1\n"
1985 "\n"
1986 "search_path: luts\n"
1987 "strictparsing: true\n"
1988 "luma: [0.2126, 0.7152, 0.0722]\n"
1989 "\n"
1990 "roles:\n"
1991 " compositing_log: lgh\n"
1992 " default: raw\n"
1993 " scene_linear: lnh\n"
1994 "\n"
1995 "displays:\n"
1996 " sRGB:\n"
1997 " - !<View> {name: Raw, colorspace: raw}\n"
1998 "\n"
1999 "active_displays: []\n"
2000 "active_views: []\n"
2001 "\n"
2002 "colorspaces:\n"
2003 " - !<ColorSpace>\n"
2004 " name: raw\n"
2005 " family: \"\"\n"
2006 " equalitygroup: \"\"\n"
2007 " bitdepth: unknown\n"
2008 " isdata: false\n"
2009 " allocation: uniform\n"
2010 "\n"
2011 " - !<ColorSpace>\n"
2012 " name: lnh\n"
2013 " family: \"\"\n"
2014 " equalitygroup: \"\"\n"
2015 " bitdepth: unknown\n"
2016 " isdata: false\n"
2017 " allocation: uniform\n"
2018 "\n"
2019 " - !<ColorSpace>\n"
2020 " name: lgh\n"
2021 " family: \"\"\n"
2022 " equalitygroup: \"\"\n"
2023 " bitdepth: unknown\n"
2024 " isdata: false\n"
2025 " allocation: uniform\n"
2026 " allocationvars: [-0.125, 1.125]\n"
2027 " from_reference: !<ColorSpaceTransform> {src: raw, dst: $CAMERARAW}\n";
2028
2029
2030 {
2031 // Test when the env. variable is missing
2032
2033 std::istringstream is;
2034 is.str(MY_OCIO_CONFIG);
2035
2036 OCIO::ConstConfigRcPtr config;
2037 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2038 OIIO_CHECK_NO_THROW(config->sanityCheck());
2039 OIIO_CHECK_THROW(config->getProcessor("raw", "lgh"), OCIO::Exception);
2040 }
2041
2042 {
2043 char * env = (char *)"CAMERARAW=lnh";
2044 putenv(env);
2045
2046 std::istringstream is;
2047 is.str(MY_OCIO_CONFIG);
2048
2049 OCIO::ConstConfigRcPtr config;
2050 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2051 OIIO_CHECK_NO_THROW(config->sanityCheck());
2052 OIIO_CHECK_NO_THROW(config->getProcessor("raw", "lgh"));
2053 }
2054
2055 {
2056 // Test when the env. variable content is wrong
2057
2058 char * env = (char *)"CAMERARAW=FaultyColorSpaceName";
2059 putenv(env);
2060
2061 std::istringstream is;
2062 is.str(MY_OCIO_CONFIG);
2063
2064 OCIO::ConstConfigRcPtr config;
2065 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2066 OIIO_CHECK_NO_THROW(config->sanityCheck());
2067 OIIO_CHECK_THROW(config->getProcessor("raw", "lgh"), OCIO::Exception);
2068 }
2069
2070 {
2071 // Check that the serialization preserves the env. variable
2072
2073 std::istringstream is;
2074 is.str(MY_OCIO_CONFIG);
2075
2076 OCIO::ConstConfigRcPtr config;
2077 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2078 OIIO_CHECK_NO_THROW(config->sanityCheck());
2079
2080 std::stringstream ss;
2081 ss << *config.get();
2082 OIIO_CHECK_EQUAL(ss.str(), MY_OCIO_CONFIG);
2083 }
2084 }
2085
OIIO_ADD_TEST(Config,display)2086 OIIO_ADD_TEST(Config, display)
2087 {
2088 static const std::string SIMPLE_PROFILE_HEADER =
2089 "ocio_profile_version: 1\n"
2090 "\n"
2091 "search_path: luts\n"
2092 "strictparsing: true\n"
2093 "luma: [0.2126, 0.7152, 0.0722]\n"
2094 "\n"
2095 "roles:\n"
2096 " default: raw\n"
2097 " scene_linear: lnh\n"
2098 "\n"
2099 "displays:\n"
2100 " sRGB_1:\n"
2101 " - !<View> {name: Raw, colorspace: raw}\n"
2102 " sRGB_2:\n"
2103 " - !<View> {name: Raw, colorspace: raw}\n"
2104 " sRGB_3:\n"
2105 " - !<View> {name: Raw, colorspace: raw}\n"
2106 "\n";
2107
2108 static const std::string SIMPLE_PROFILE_FOOTER =
2109 "\n"
2110 "colorspaces:\n"
2111 " - !<ColorSpace>\n"
2112 " name: raw\n"
2113 " family: \"\"\n"
2114 " equalitygroup: \"\"\n"
2115 " bitdepth: unknown\n"
2116 " isdata: false\n"
2117 " allocation: uniform\n"
2118 "\n"
2119 " - !<ColorSpace>\n"
2120 " name: lnh\n"
2121 " family: \"\"\n"
2122 " equalitygroup: \"\"\n"
2123 " bitdepth: unknown\n"
2124 " isdata: false\n"
2125 " allocation: uniform\n";
2126
2127 {
2128 std::string myProfile =
2129 SIMPLE_PROFILE_HEADER
2130 +
2131 "active_displays: []\n"
2132 "active_views: []\n"
2133 + SIMPLE_PROFILE_FOOTER;
2134
2135 std::istringstream is(myProfile);
2136 OCIO::ConstConfigRcPtr config;
2137 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2138 OIIO_CHECK_EQUAL(config->getNumDisplays(), 3);
2139 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_1"));
2140 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_2"));
2141 OIIO_CHECK_EQUAL(std::string(config->getDisplay(2)), std::string("sRGB_3"));
2142 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_1");
2143 }
2144
2145 {
2146 std::string myProfile =
2147 SIMPLE_PROFILE_HEADER
2148 +
2149 "active_displays: [sRGB_1]\n"
2150 "active_views: []\n"
2151 + SIMPLE_PROFILE_FOOTER;
2152
2153 std::istringstream is(myProfile);
2154 OCIO::ConstConfigRcPtr config;
2155 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2156 OIIO_CHECK_EQUAL(config->getNumDisplays(), 1);
2157 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_1"));
2158 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_1");
2159 }
2160
2161 {
2162 std::string myProfile =
2163 SIMPLE_PROFILE_HEADER
2164 +
2165 "active_displays: [sRGB_2, sRGB_1]\n"
2166 "active_views: []\n"
2167 + SIMPLE_PROFILE_FOOTER;
2168
2169 std::istringstream is(myProfile);
2170 OCIO::ConstConfigRcPtr config;
2171 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2172 OIIO_CHECK_EQUAL(config->getNumDisplays(), 2);
2173 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_2"));
2174 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_1"));
2175 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_2");
2176 }
2177
2178 {
2179 std::string myProfile =
2180 SIMPLE_PROFILE_HEADER
2181 +
2182 "active_displays: []\n"
2183 "active_views: []\n"
2184 + SIMPLE_PROFILE_FOOTER;
2185
2186 const std::string active_displays(
2187 std::string(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR) + "= sRGB_3, sRGB_2");
2188 putenv(const_cast<char *>(active_displays.c_str()));
2189
2190 std::istringstream is(myProfile);
2191 OCIO::ConstConfigRcPtr config;
2192 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2193 OIIO_CHECK_EQUAL(config->getNumDisplays(), 2);
2194 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_3"));
2195 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_2"));
2196 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_3");
2197 }
2198
2199 {
2200 std::string myProfile =
2201 SIMPLE_PROFILE_HEADER
2202 +
2203 "active_displays: [sRGB_2, sRGB_1]\n"
2204 "active_views: []\n"
2205 + SIMPLE_PROFILE_FOOTER;
2206
2207 const std::string active_displays(
2208 std::string(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR) + "= sRGB_3, sRGB_2");
2209 putenv(const_cast<char *>(active_displays.c_str()));
2210
2211 std::istringstream is(myProfile);
2212 OCIO::ConstConfigRcPtr config;
2213 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2214 OIIO_CHECK_EQUAL(config->getNumDisplays(), 2);
2215 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_3"));
2216 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_2"));
2217 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_3");
2218 }
2219
2220 {
2221 const std::string active_displays(
2222 std::string(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR) + "="); // No value
2223 putenv(const_cast<char *>(active_displays.c_str()));
2224
2225 std::string myProfile =
2226 SIMPLE_PROFILE_HEADER
2227 +
2228 "active_displays: [sRGB_2, sRGB_1]\n"
2229 "active_views: []\n"
2230 + SIMPLE_PROFILE_FOOTER;
2231
2232 std::istringstream is(myProfile);
2233 OCIO::ConstConfigRcPtr config;
2234 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2235 OIIO_CHECK_EQUAL(config->getNumDisplays(), 2);
2236 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_2"));
2237 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_1"));
2238 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_2");
2239 }
2240
2241 {
2242 const std::string active_displays(
2243 std::string(OCIO::OCIO_ACTIVE_DISPLAYS_ENVVAR) + "= "); // No value, but misleading space
2244 putenv(const_cast<char *>(active_displays.c_str()));
2245
2246 std::string myProfile =
2247 SIMPLE_PROFILE_HEADER
2248 +
2249 "active_displays: [sRGB_2, sRGB_1]\n"
2250 "active_views: []\n"
2251 + SIMPLE_PROFILE_FOOTER;
2252
2253 std::istringstream is(myProfile);
2254 OCIO::ConstConfigRcPtr config;
2255 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2256 OIIO_CHECK_EQUAL(config->getNumDisplays(), 2);
2257 OIIO_CHECK_EQUAL(std::string(config->getDisplay(0)), std::string("sRGB_2"));
2258 OIIO_CHECK_EQUAL(std::string(config->getDisplay(1)), std::string("sRGB_1"));
2259 OIIO_CHECK_EQUAL(std::string(config->getDefaultDisplay()), "sRGB_2");
2260 }
2261 }
2262
OIIO_ADD_TEST(Config,view)2263 OIIO_ADD_TEST(Config, view)
2264 {
2265 static const std::string SIMPLE_PROFILE_HEADER =
2266 "ocio_profile_version: 1\n"
2267 "\n"
2268 "search_path: luts\n"
2269 "strictparsing: true\n"
2270 "luma: [0.2126, 0.7152, 0.0722]\n"
2271 "\n"
2272 "roles:\n"
2273 " default: raw\n"
2274 " scene_linear: lnh\n"
2275 "\n"
2276 "displays:\n"
2277 " sRGB_1:\n"
2278 " - !<View> {name: View_1, colorspace: raw}\n"
2279 " - !<View> {name: View_2, colorspace: raw}\n"
2280 " sRGB_2:\n"
2281 " - !<View> {name: View_2, colorspace: raw}\n"
2282 " - !<View> {name: View_3, colorspace: raw}\n"
2283 " sRGB_3:\n"
2284 " - !<View> {name: View_3, colorspace: raw}\n"
2285 " - !<View> {name: View_1, colorspace: raw}\n"
2286 "\n";
2287
2288 static const std::string SIMPLE_PROFILE_FOOTER =
2289 "\n"
2290 "colorspaces:\n"
2291 " - !<ColorSpace>\n"
2292 " name: raw\n"
2293 " family: \"\"\n"
2294 " equalitygroup: \"\"\n"
2295 " bitdepth: unknown\n"
2296 " isdata: false\n"
2297 " allocation: uniform\n"
2298 "\n"
2299 " - !<ColorSpace>\n"
2300 " name: lnh\n"
2301 " family: \"\"\n"
2302 " equalitygroup: \"\"\n"
2303 " bitdepth: unknown\n"
2304 " isdata: false\n"
2305 " allocation: uniform\n";
2306
2307 {
2308 std::string myProfile =
2309 SIMPLE_PROFILE_HEADER
2310 +
2311 "active_displays: []\n"
2312 "active_views: []\n"
2313 + SIMPLE_PROFILE_FOOTER;
2314
2315 std::istringstream is(myProfile);
2316 OCIO::ConstConfigRcPtr config;
2317 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2318 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_1");
2319 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2320 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2321 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_2");
2322 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2323 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2324 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2325 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2326 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2327 }
2328
2329 {
2330 std::string myProfile =
2331 SIMPLE_PROFILE_HEADER
2332 +
2333 "active_displays: []\n"
2334 "active_views: [View_3]\n"
2335 + SIMPLE_PROFILE_FOOTER;
2336
2337 std::istringstream is(myProfile);
2338 OCIO::ConstConfigRcPtr config;
2339 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2340 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_1");
2341 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2342 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2343 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_3");
2344 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2345 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2346 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2347 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2348 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2349 }
2350
2351 {
2352 std::string myProfile =
2353 SIMPLE_PROFILE_HEADER
2354 +
2355 "active_displays: []\n"
2356 "active_views: [View_3, View_2, View_1]\n"
2357 + SIMPLE_PROFILE_FOOTER;
2358
2359 std::istringstream is(myProfile);
2360 OCIO::ConstConfigRcPtr config;
2361 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2362 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_2");
2363 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2364 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2365 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_3");
2366 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2367 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2368 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2369 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2370 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2371 }
2372
2373 {
2374 std::string myProfile =
2375 SIMPLE_PROFILE_HEADER
2376 +
2377 "active_displays: []\n"
2378 "active_views: []\n"
2379 + SIMPLE_PROFILE_FOOTER;
2380
2381 const std::string active_displays(
2382 std::string(OCIO::OCIO_ACTIVE_VIEWS_ENVVAR) + "= View_3, View_2");
2383 putenv(const_cast<char *>(active_displays.c_str()));
2384
2385 std::istringstream is(myProfile);
2386 OCIO::ConstConfigRcPtr config;
2387 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2388 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_2");
2389 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2390 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2391 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_3");
2392 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2393 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2394 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2395 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2396 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2397 }
2398
2399 {
2400 std::string myProfile =
2401 SIMPLE_PROFILE_HEADER
2402 +
2403 "active_displays: []\n"
2404 "active_views: []\n"
2405 + SIMPLE_PROFILE_FOOTER;
2406
2407 const std::string active_displays(
2408 std::string(OCIO::OCIO_ACTIVE_VIEWS_ENVVAR) + "="); // No value.
2409 putenv(const_cast<char *>(active_displays.c_str()));
2410
2411 std::istringstream is(myProfile);
2412 OCIO::ConstConfigRcPtr config;
2413 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2414 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_1");
2415 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2416 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2417 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_2");
2418 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2419 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2420 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2421 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2422 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2423 }
2424
2425 {
2426 std::string myProfile =
2427 SIMPLE_PROFILE_HEADER
2428 +
2429 "active_displays: []\n"
2430 "active_views: []\n"
2431 + SIMPLE_PROFILE_FOOTER;
2432
2433 const std::string active_displays(
2434 std::string(OCIO::OCIO_ACTIVE_VIEWS_ENVVAR) + "= "); // No value, but misleading space
2435 putenv(const_cast<char *>(active_displays.c_str()));
2436
2437 std::istringstream is(myProfile);
2438 OCIO::ConstConfigRcPtr config;
2439 OIIO_CHECK_NO_THROW(config = OCIO::Config::CreateFromStream(is));
2440 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_1")), "View_1");
2441 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 0)), "View_1");
2442 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_1", 1)), "View_2");
2443 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_2")), "View_2");
2444 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 0)), "View_2");
2445 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_2", 1)), "View_3");
2446 OIIO_CHECK_EQUAL(std::string(config->getDefaultView("sRGB_3")), "View_3");
2447 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 0)), "View_3");
2448 OIIO_CHECK_EQUAL(std::string(config->getView("sRGB_3", 1)), "View_1");
2449 }
2450 }
2451
2452 #endif // OCIO_UNIT_TEST
2453