/src/core/Config.cpp
http://github.com/imageworks/OpenColorIO · C++ · 1957 lines · 1514 code · 336 blank · 107 comment · 189 complexity · 86cd1be9ee9af0728bff52be00b4832d MD5 · raw file
Large files are truncated click here to view the full file
- /*
- Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
- All Rights Reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of Sony Pictures Imageworks nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <cstdlib>
- #include <cstring>
- #include <set>
- #include <sstream>
- #include <fstream>
- #include <utility>
- #include <vector>
- #include <OpenColorIO/OpenColorIO.h>
- #include "HashUtils.h"
- #include "Logging.h"
- #include "LookParse.h"
- #include "Display.h"
- #include "MathUtils.h"
- #include "Mutex.h"
- #include "OpBuilders.h"
- #include "PathUtils.h"
- #include "ParseUtils.h"
- #include "Processor.h"
- #include "PrivateTypes.h"
- #include "pystring/pystring.h"
- #include "OCIOYaml.h"
- OCIO_NAMESPACE_ENTER
- {
- namespace
- {
- const char * OCIO_CONFIG_ENVVAR = "OCIO";
- const char * OCIO_ACTIVE_DISPLAYS_ENVVAR = "OCIO_ACTIVE_DISPLAYS";
- const char * OCIO_ACTIVE_VIEWS_ENVVAR = "OCIO_ACTIVE_VIEWS";
-
- enum Sanity
- {
- SANITY_UNKNOWN = 0,
- SANITY_SANE,
- SANITY_INSANE
- };
-
- // These are the 709 primaries specified by the ASC.
- const float DEFAULT_LUMA_COEFF_R = 0.2126f;
- const float DEFAULT_LUMA_COEFF_G = 0.7152f;
- const float DEFAULT_LUMA_COEFF_B = 0.0722f;
-
- const char * INTERNAL_RAW_PROFILE =
- "ocio_profile_version: 1\n"
- "strictparsing: false\n"
- "roles:\n"
- " default: raw\n"
- "displays:\n"
- " sRGB:\n"
- " - !<View> {name: Raw, colorspace: raw}\n"
- "colorspaces:\n"
- " - !<ColorSpace>\n"
- " name: raw\n"
- " family: raw\n"
- " equalitygroup:\n"
- " bitdepth: 32f\n"
- " isdata: true\n"
- " allocation: uniform\n"
- " description: 'A raw color space. Conversions to and from this space are no-ops.'\n";
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- const char * GetVersion()
- {
- return OCIO_VERSION;
- }
-
- int GetVersionHex()
- {
- return OCIO_VERSION_HEX;
- }
-
- namespace
- {
- ConstConfigRcPtr g_currentConfig;
- Mutex g_currentConfigLock;
- }
-
- ConstConfigRcPtr GetCurrentConfig()
- {
- AutoMutex lock(g_currentConfigLock);
-
- if(!g_currentConfig)
- {
- g_currentConfig = Config::CreateFromEnv();
- }
-
- return g_currentConfig;
- }
-
- void SetCurrentConfig(const ConstConfigRcPtr & config)
- {
- AutoMutex lock(g_currentConfigLock);
-
- g_currentConfig = config->createEditableCopy();
- }
-
- namespace
- {
-
- // Environment
- std::string LookupEnvironment(const StringMap & env, const std::string & name)
- {
- StringMap::const_iterator iter = env.find(name);
- if(iter == env.end()) return "";
- return iter->second;
- }
-
- // Roles
- // (lower case role name: colorspace name)
- std::string LookupRole(const StringMap & roles, const std::string & rolename)
- {
- StringMap::const_iterator iter = roles.find(pystring::lower(rolename));
- if(iter == roles.end()) return "";
- return iter->second;
- }
-
-
- void GetFileReferences(std::set<std::string> & files,
- const ConstTransformRcPtr & transform)
- {
- if(!transform) return;
-
- if(ConstGroupTransformRcPtr groupTransform = \
- DynamicPtrCast<const GroupTransform>(transform))
- {
- for(int i=0; i<groupTransform->size(); ++i)
- {
- GetFileReferences(files, groupTransform->getTransform(i));
- }
- }
- else if(ConstFileTransformRcPtr fileTransform = \
- DynamicPtrCast<const FileTransform>(transform))
- {
- files.insert(fileTransform->getSrc());
- }
- }
-
- void GetColorSpaceReferences(std::set<std::string> & colorSpaceNames,
- const ConstTransformRcPtr & transform)
- {
- if(!transform) return;
-
- if(ConstGroupTransformRcPtr groupTransform = \
- DynamicPtrCast<const GroupTransform>(transform))
- {
- for(int i=0; i<groupTransform->size(); ++i)
- {
- GetColorSpaceReferences(colorSpaceNames, groupTransform->getTransform(i));
- }
- }
- else if(ConstColorSpaceTransformRcPtr colorSpaceTransform = \
- DynamicPtrCast<const ColorSpaceTransform>(transform))
- {
- colorSpaceNames.insert(colorSpaceTransform->getSrc());
- colorSpaceNames.insert(colorSpaceTransform->getDst());
- }
- else if(ConstDisplayTransformRcPtr displayTransform = \
- DynamicPtrCast<const DisplayTransform>(transform))
- {
- colorSpaceNames.insert(displayTransform->getInputColorSpaceName());
- }
- else if(ConstLookTransformRcPtr lookTransform = \
- DynamicPtrCast<const LookTransform>(transform))
- {
- colorSpaceNames.insert(colorSpaceTransform->getSrc());
- colorSpaceNames.insert(colorSpaceTransform->getDst());
- }
- }
-
-
- bool FindColorSpaceIndex(int * index,
- const ColorSpaceVec & colorspaces,
- const std::string & csname)
- {
- if(csname.empty()) return false;
-
- std::string csnamelower = pystring::lower(csname);
- for(unsigned int i = 0; i < colorspaces.size(); ++i)
- {
- if(csnamelower == pystring::lower(colorspaces[i]->getName()))
- {
- if(index) *index = i;
- return true;
- }
- }
-
- return false;
- }
-
- } // namespace
-
- class Config::Impl
- {
- public:
- StringMap env_;
- ContextRcPtr context_;
- std::string description_;
- ColorSpaceVec colorspaces_;
- StringMap roles_;
- LookVec looksList_;
-
- DisplayMap displays_;
- StringVec activeDisplays_;
- StringVec activeDisplaysEnvOverride_;
- StringVec activeViews_;
- StringVec activeViewsEnvOverride_;
-
- mutable std::string activeDisplaysStr_;
- mutable std::string activeViewsStr_;
- mutable StringVec displayCache_;
-
- // Misc
- std::vector<float> defaultLumaCoefs_;
- bool strictParsing_;
-
- mutable Sanity sanity_;
- mutable std::string sanitytext_;
-
- mutable Mutex cacheidMutex_;
- mutable StringMap cacheids_;
- mutable std::string cacheidnocontext_;
-
- OCIOYaml io_;
-
- Impl() :
- context_(Context::Create()),
- strictParsing_(true),
- sanity_(SANITY_UNKNOWN)
- {
- char* activeDisplays = std::getenv(OCIO_ACTIVE_DISPLAYS_ENVVAR);
- SplitStringEnvStyle(activeDisplaysEnvOverride_, activeDisplays);
-
- char * activeViews = std::getenv(OCIO_ACTIVE_VIEWS_ENVVAR);
- SplitStringEnvStyle(activeViewsEnvOverride_, activeViews);
-
- defaultLumaCoefs_.resize(3);
- defaultLumaCoefs_[0] = DEFAULT_LUMA_COEFF_R;
- defaultLumaCoefs_[1] = DEFAULT_LUMA_COEFF_G;
- defaultLumaCoefs_[2] = DEFAULT_LUMA_COEFF_B;
- }
-
- ~Impl()
- {
-
- }
-
- Impl& operator= (const Impl & rhs)
- {
- env_ = rhs.env_;
- context_ = rhs.context_->createEditableCopy();
- description_ = rhs.description_;
-
- // Deep copy the colorspaces
- colorspaces_.clear();
- colorspaces_.reserve(rhs.colorspaces_.size());
- for(unsigned int i=0; i<rhs.colorspaces_.size(); ++i)
- {
- colorspaces_.push_back(rhs.colorspaces_[i]->createEditableCopy());
- }
-
- // Deep copy the looks
- looksList_.clear();
- looksList_.reserve(rhs.looksList_.size());
- for(unsigned int i=0; i<rhs.looksList_.size(); ++i)
- {
- looksList_.push_back(rhs.looksList_[i]->createEditableCopy());
- }
-
- // Assignment operator will suffice for these
- roles_ = rhs.roles_;
-
- displays_ = rhs.displays_;
- activeDisplays_ = rhs.activeDisplays_;
- activeViews_ = rhs.activeViews_;
- activeViewsEnvOverride_ = rhs.activeViewsEnvOverride_;
- activeDisplaysEnvOverride_ = rhs.activeDisplaysEnvOverride_;
- activeDisplaysStr_ = rhs.activeDisplaysStr_;
- displayCache_ = rhs.displayCache_;
-
- defaultLumaCoefs_ = rhs.defaultLumaCoefs_;
- strictParsing_ = rhs.strictParsing_;
-
- sanity_ = rhs.sanity_;
- sanitytext_ = rhs.sanitytext_;
-
- cacheids_ = rhs.cacheids_;
- cacheidnocontext_ = cacheidnocontext_;
- return *this;
- }
-
- // Any time you modify the state of the config, you must call this
- // to reset internal cache states. You also should do this in a
- // thread safe manner by acquiring the cacheidMutex_;
- void resetCacheIDs();
-
- // Get all internal transforms (to generate cacheIDs, validation, etc).
- // This currently crawls colorspaces + looks
- void getAllIntenalTransforms(ConstTransformVec & transformVec) const;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- ConfigRcPtr Config::Create()
- {
- return ConfigRcPtr(new Config(), &deleter);
- }
-
- void Config::deleter(Config* c)
- {
- delete c;
- }
-
- ConstConfigRcPtr Config::CreateFromEnv()
- {
- char* file = std::getenv(OCIO_CONFIG_ENVVAR);
- if(file) return CreateFromFile(file);
-
- std::ostringstream os;
- os << "Color management disabled. ";
- os << "(Specify the $OCIO environment variable to enable.)";
- LogInfo(os.str());
-
- std::istringstream istream;
- istream.str(INTERNAL_RAW_PROFILE);
-
- ConfigRcPtr config = Config::Create();
- config->getImpl()->io_.open(istream, config);
- return config;
- }
-
- ConstConfigRcPtr Config::CreateFromFile(const char * filename)
- {
- std::ifstream istream(filename);
- if(istream.fail()) {
- std::ostringstream os;
- os << "Error could not read '" << filename;
- os << "' OCIO profile.";
- throw Exception (os.str().c_str());
- }
-
- ConfigRcPtr config = Config::Create();
- config->getImpl()->io_.open(istream, config, filename);
- return config;
- }
-
- ConstConfigRcPtr Config::CreateFromStream(std::istream & istream)
- {
- ConfigRcPtr config = Config::Create();
- config->getImpl()->io_.open(istream, config);
- return config;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
-
-
- Config::Config()
- : m_impl(new Config::Impl)
- {
- }
-
- Config::~Config()
- {
- delete m_impl;
- m_impl = NULL;
- }
-
- ConfigRcPtr Config::createEditableCopy() const
- {
- ConfigRcPtr config = Config::Create();
- *config->m_impl = *m_impl;
- return config;
- }
-
- void Config::sanityCheck() const
- {
- if(getImpl()->sanity_ == SANITY_SANE) return;
- if(getImpl()->sanity_ == SANITY_INSANE)
- {
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- getImpl()->sanity_ = SANITY_INSANE;
- getImpl()->sanitytext_ = "";
-
-
- ///// COLORSPACES
- StringSet existingColorSpaces;
-
- // Confirm all ColorSpaces are valid
- for(unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
- {
- if(!getImpl()->colorspaces_[i])
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The colorspace at index " << i << " is null.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- const char * name = getImpl()->colorspaces_[i]->getName();
- if(!name || strlen(name) == 0)
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The colorspace at index " << i << " is not named.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- std::string namelower = pystring::lower(name);
- StringSet::const_iterator it = existingColorSpaces.find(namelower);
- if(it != existingColorSpaces.end())
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "Two colorspaces are defined with the same name, '";
- os << namelower << "'.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- existingColorSpaces.insert(namelower);
- }
-
- // Confirm all roles are valid
- {
- for(StringMap::const_iterator iter = getImpl()->roles_.begin(),
- end = getImpl()->roles_.end(); iter!=end; ++iter)
- {
- int csindex = -1;
- if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->second))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The role '" << iter->first << "' ";
- os << "refers to a colorspace, '" << iter->second << "', ";
- os << "which is not defined.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- // Confirm no name conflicts between colorspaces and roles
- if(FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, iter->first))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The role '" << iter->first << "' ";
- os << " is in conflict with a colorspace of the same name.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
- }
- }
-
- ///// DISPLAYS
-
- int numviews = 0;
-
- // Confirm all Displays transforms refer to colorspaces that exit
- for(DisplayMap::const_iterator iter = getImpl()->displays_.begin();
- iter != getImpl()->displays_.end();
- ++iter)
- {
- std::string display = iter->first;
- const ViewVec & views = iter->second;
- if(views.empty())
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The display '" << display << "' ";
- os << "does not define any views.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- for(unsigned int i=0; i<views.size(); ++i)
- {
- if(views[i].name.empty() || views[i].colorspace.empty())
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The display '" << display << "' ";
- os << "defines a view with an empty name and/or colorspace.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- int csindex = -1;
- if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, views[i].colorspace))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The display '" << display << "' ";
- os << "refers to a colorspace, '" << views[i].colorspace << "', ";
- os << "which is not defined.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- // Confirm looks references exist
- LookParseResult looks;
- const LookParseResult::Options & options = looks.parse(views[i].looks);
-
- for(unsigned int optionindex=0;
- optionindex<options.size();
- ++optionindex)
- {
- for(unsigned int tokenindex=0;
- tokenindex<options[optionindex].size();
- ++tokenindex)
- {
- std::string look = options[optionindex][tokenindex].name;
-
- if(!look.empty() && !getLook(look.c_str()))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The display '" << display << "' ";
- os << "refers to a look, '" << look << "', ";
- os << "which is not defined.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
- }
- }
-
- ++numviews;
- }
- }
-
- // Confirm at least one display entry exists.
- if(numviews == 0)
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "No displays are specified.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- // Confirm for all Transforms that reference internal colorspaces,
- // the named space exists
- {
- ConstTransformVec allTransforms;
- getImpl()->getAllIntenalTransforms(allTransforms);
-
- std::set<std::string> colorSpaceNames;
- for(unsigned int i=0; i<colorSpaceNames.size(); ++i)
- {
- GetColorSpaceReferences(colorSpaceNames, allTransforms[i]);
- }
-
- for(std::set<std::string>::iterator iter = colorSpaceNames.begin();
- iter != colorSpaceNames.end(); ++iter)
- {
- int csindex = -1;
- if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, *iter))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "This config references a ColorSpace, '" << *iter << "', ";
- os << "which is not defined.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
- }
- }
-
- ///// LOOKS
-
- // For all looks, confirm the process space exists and the look is named
- for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
- {
- std::string name = getImpl()->looksList_[i]->getName();
- if(name.empty())
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The look at index '" << i << "' ";
- os << "does not specify a name.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- std::string processSpace = getImpl()->looksList_[i]->getProcessSpace();
- if(processSpace.empty())
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The look '" << name << "' ";
- os << "does not specify a process space.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
-
- int csindex=0;
- if(!FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, processSpace))
- {
- std::ostringstream os;
- os << "Config failed sanitycheck. ";
- os << "The look '" << name << "' ";
- os << "specifies a process color space, '";
- os << processSpace << "', which is not defined.";
- getImpl()->sanitytext_ = os.str();
- throw Exception(getImpl()->sanitytext_.c_str());
- }
- }
-
-
-
- // Everything is groovy.
- getImpl()->sanity_ = SANITY_SANE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
- const char * Config::getDescription() const
- {
- return getImpl()->description_.c_str();
- }
-
- void Config::setDescription(const char * description)
- {
- getImpl()->description_ = description;
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
-
- // RESOURCES //////////////////////////////////////////////////////////////
-
- ConstContextRcPtr Config::getCurrentContext() const
- {
- return getImpl()->context_;
- }
-
- void Config::addEnvironmentVar(const char * name, const char * defaultValue)
- {
- if(defaultValue)
- {
- getImpl()->env_[std::string(name)] = std::string(defaultValue);
- getImpl()->context_->setStringVar(name, defaultValue);
- }
- else
- {
- StringMap::iterator iter = getImpl()->env_.find(std::string(name));
- if(iter != getImpl()->env_.end()) getImpl()->env_.erase(iter);
- }
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- int Config::getNumEnvironmentVars() const
- {
- return static_cast<int>(getImpl()->env_.size());
- }
-
- const char * Config::getEnvironmentVarNameByIndex(int index) const
- {
- if(index < 0 || index >= (int)getImpl()->env_.size()) return "";
- StringMap::const_iterator iter = getImpl()->env_.begin();
- for(int i = 0; i < index; ++i) ++iter;
- return iter->first.c_str();
- }
-
- const char * Config::getEnvironmentVarDefault(const char * name) const
- {
- return LookupEnvironment(getImpl()->env_, name).c_str();
- }
-
- void Config::clearEnvironmentVars()
- {
- getImpl()->env_.clear();
- getImpl()->context_->clearStringVars();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- void Config::setEnvironmentMode(EnvironmentMode mode)
- {
- getImpl()->context_->setEnvironmentMode(mode);
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- EnvironmentMode Config::getEnvironmentMode() const
- {
- return getImpl()->context_->getEnvironmentMode();
- }
-
- void Config::loadEnvironment()
- {
- getImpl()->context_->loadEnvironment();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- const char * Config::getSearchPath() const
- {
- return getImpl()->context_->getSearchPath();
- }
-
- void Config::setSearchPath(const char * path)
- {
- getImpl()->context_->setSearchPath(path);
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- const char * Config::getWorkingDir() const
- {
- return getImpl()->context_->getWorkingDir();
- }
-
- void Config::setWorkingDir(const char * dirname)
- {
- getImpl()->context_->setWorkingDir(dirname);
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- int Config::getNumColorSpaces() const
- {
- return static_cast<int>(getImpl()->colorspaces_.size());
- }
-
- const char * Config::getColorSpaceNameByIndex(int index) const
- {
- if(index<0 || index >= (int)getImpl()->colorspaces_.size())
- {
- return "";
- }
-
- return getImpl()->colorspaces_[index]->getName();
- }
-
- ConstColorSpaceRcPtr Config::getColorSpace(const char * name) const
- {
- int index = getIndexForColorSpace(name);
- if(index<0 || index >= (int)getImpl()->colorspaces_.size())
- {
- return ColorSpaceRcPtr();
- }
-
- return getImpl()->colorspaces_[index];
- }
-
- int Config::getIndexForColorSpace(const char * name) const
- {
- int csindex = -1;
-
- // Check to see if the name is a color space
- if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
- {
- return csindex;
- }
-
- // Check to see if the name is a role
- std::string csname = LookupRole(getImpl()->roles_, name);
- if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
- {
- return csindex;
- }
-
- // Is a default role defined?
- // (And, are we allowed to use it)
- if(!getImpl()->strictParsing_)
- {
- csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
- if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
- {
- return csindex;
- }
- }
-
- return -1;
- }
-
- void Config::addColorSpace(const ConstColorSpaceRcPtr & original)
- {
- ColorSpaceRcPtr cs = original->createEditableCopy();
-
- std::string name = cs->getName();
- if(name.empty())
- throw Exception("Cannot addColorSpace with an empty name.");
-
- // Check to see if the colorspace already exists
- int csindex = -1;
- if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, name) )
- {
- getImpl()->colorspaces_[csindex] = cs;
- }
- else
- {
- // Otherwise, add it
- getImpl()->colorspaces_.push_back( cs );
- }
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- void Config::clearColorSpaces()
- {
- getImpl()->colorspaces_.clear();
- }
-
-
-
-
-
-
- const char * Config::parseColorSpaceFromString(const char * str) const
- {
- if(!str) return "";
-
- // Search the entire filePath, including directory name (if provided)
- // convert the filename to lowercase.
- std::string fullstr = pystring::lower(std::string(str));
-
- // See if it matches a lut name.
- // This is the position of the RIGHT end of the colorspace substring, not the left
- int rightMostColorPos=-1;
- std::string rightMostColorspace = "";
- int rightMostColorSpaceIndex = -1;
-
- // Find the right-most occcurance within the string for each colorspace.
- for (unsigned int i=0; i<getImpl()->colorspaces_.size(); ++i)
- {
- std::string csname = pystring::lower(getImpl()->colorspaces_[i]->getName());
-
- // find right-most extension matched in filename
- int colorspacePos = pystring::rfind(fullstr, csname);
- if(colorspacePos < 0)
- continue;
-
- // If we have found a match, move the pointer over to the right end of the substring
- // This will allow us to find the longest name that matches the rightmost colorspace
- colorspacePos += (int)csname.size();
-
- if ( (colorspacePos > rightMostColorPos) ||
- ((colorspacePos == rightMostColorPos) && (csname.size() > rightMostColorspace.size()))
- )
- {
- rightMostColorPos = colorspacePos;
- rightMostColorspace = csname;
- rightMostColorSpaceIndex = i;
- }
- }
-
- if(rightMostColorSpaceIndex>=0)
- {
- return getImpl()->colorspaces_[rightMostColorSpaceIndex]->getName();
- }
-
- if(!getImpl()->strictParsing_)
- {
- // Is a default role defined?
- std::string csname = LookupRole(getImpl()->roles_, ROLE_DEFAULT);
- if(!csname.empty())
- {
- int csindex = -1;
- if( FindColorSpaceIndex(&csindex, getImpl()->colorspaces_, csname) )
- {
- // This is necessary to not return a reference to
- // a local variable.
- return getImpl()->colorspaces_[csindex]->getName();
- }
- }
- }
-
- return "";
- }
-
- bool Config::isStrictParsingEnabled() const
- {
- return getImpl()->strictParsing_;
- }
-
- void Config::setStrictParsingEnabled(bool enabled)
- {
- getImpl()->strictParsing_ = enabled;
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- // Roles
- void Config::setRole(const char * role, const char * colorSpaceName)
- {
- // Set the role
- if(colorSpaceName)
- {
- getImpl()->roles_[pystring::lower(role)] = std::string(colorSpaceName);
- }
- // Unset the role
- else
- {
- StringMap::iterator iter = getImpl()->roles_.find(pystring::lower(role));
- if(iter != getImpl()->roles_.end())
- {
- getImpl()->roles_.erase(iter);
- }
- }
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- int Config::getNumRoles() const
- {
- return static_cast<int>(getImpl()->roles_.size());
- }
-
- bool Config::hasRole(const char * role) const
- {
- return LookupRole(getImpl()->roles_, role) == "" ? false : true;
- }
-
- const char * Config::getRoleName(int index) const
- {
- if(index < 0 || index >= (int)getImpl()->roles_.size()) return "";
- StringMap::const_iterator iter = getImpl()->roles_.begin();
- for(int i = 0; i < index; ++i) ++iter;
- return iter->first.c_str();
- }
-
- ///////////////////////////////////////////////////////////////////////////
- //
- // Display/View Registration
-
-
- const char * Config::getDefaultDisplay() const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- int index = -1;
-
- if(!getImpl()->activeDisplaysEnvOverride_.empty())
- {
- StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplaysEnvOverride_,
- getImpl()->displayCache_);
- if(!orderedDisplays.empty())
- {
- index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
- }
- }
- else if(!getImpl()->activeDisplays_.empty())
- {
- StringVec orderedDisplays = IntersectStringVecsCaseIgnore(getImpl()->activeDisplays_,
- getImpl()->displayCache_);
- if(!orderedDisplays.empty())
- {
- index = FindInStringVecCaseIgnore(getImpl()->displayCache_, orderedDisplays[0]);
- }
- }
-
- if(index >= 0)
- {
- return getImpl()->displayCache_[index].c_str();
- }
-
- if(!getImpl()->displayCache_.empty())
- {
- return getImpl()->displayCache_[0].c_str();
- }
-
- return "";
- }
- int Config::getNumDisplays() const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- return static_cast<int>(getImpl()->displayCache_.size());
- }
- const char * Config::getDisplay(int index) const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- if(index>=0 || index < static_cast<int>(getImpl()->displayCache_.size()))
- {
- return getImpl()->displayCache_[index].c_str();
- }
-
- return "";
- }
-
- const char * Config::getDefaultView(const char * display) const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- if(!display) return "";
-
- DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
- if(iter == getImpl()->displays_.end()) return "";
-
- const ViewVec & views = iter->second;
-
- StringVec masterViews;
- for(unsigned int i=0; i<views.size(); ++i)
- {
- masterViews.push_back(views[i].name);
- }
-
- int index = -1;
-
- if(!getImpl()->activeViewsEnvOverride_.empty())
- {
- StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViewsEnvOverride_,
- masterViews);
- if(!orderedViews.empty())
- {
- index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
- }
- }
- else if(!getImpl()->activeViews_.empty())
- {
- StringVec orderedViews = IntersectStringVecsCaseIgnore(getImpl()->activeViews_,
- masterViews);
- if(!orderedViews.empty())
- {
- index = FindInStringVecCaseIgnore(masterViews, orderedViews[0]);
- }
- }
-
- if(index >= 0)
- {
- return views[index].name.c_str();
- }
-
- if(!views.empty())
- {
- return views[0].name.c_str();
- }
-
- return "";
- }
- int Config::getNumViews(const char * display) const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- if(!display) return 0;
-
- DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
- if(iter == getImpl()->displays_.end()) return 0;
-
- const ViewVec & views = iter->second;
- return static_cast<int>(views.size());
- }
- const char * Config::getView(const char * display, int index) const
- {
- if(getImpl()->displayCache_.empty())
- {
- ComputeDisplays(getImpl()->displayCache_,
- getImpl()->displays_,
- getImpl()->activeDisplays_,
- getImpl()->activeDisplaysEnvOverride_);
- }
-
- if(!display) return "";
-
- DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
- if(iter == getImpl()->displays_.end()) return "";
-
- const ViewVec & views = iter->second;
- return views[index].name.c_str();
- }
- const char * Config::getDisplayColorSpaceName(const char * display, const char * view) const
- {
- if(!display || !view) return "";
-
- DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
- if(iter == getImpl()->displays_.end()) return "";
-
- const ViewVec & views = iter->second;
- int index = find_view(views, view);
- if(index<0) return "";
-
- return views[index].colorspace.c_str();
- }
-
- const char * Config::getDisplayLooks(const char * display, const char * view) const
- {
- if(!display || !view) return "";
-
- DisplayMap::const_iterator iter = find_display_const(getImpl()->displays_, display);
- if(iter == getImpl()->displays_.end()) return "";
-
- const ViewVec & views = iter->second;
- int index = find_view(views, view);
- if(index<0) return "";
-
- return views[index].looks.c_str();
- }
-
- void Config::addDisplay(const char * display, const char * view,
- const char * colorSpaceName, const char * lookName)
- {
-
- if(!display || !view || !colorSpaceName || !lookName) return;
-
- AddDisplay(getImpl()->displays_,
- display, view, colorSpaceName, lookName);
- getImpl()->displayCache_.clear();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- void Config::clearDisplays()
- {
- getImpl()->displays_.clear();
- getImpl()->displayCache_.clear();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- void Config::setActiveDisplays(const char * displays)
- {
- getImpl()->activeDisplays_.clear();
- SplitStringEnvStyle(getImpl()->activeDisplays_, displays);
-
- getImpl()->displayCache_.clear();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
- const char * Config::getActiveDisplays() const
- {
- getImpl()->activeDisplaysStr_ = JoinStringEnvStyle(getImpl()->activeDisplays_);
- return getImpl()->activeDisplaysStr_.c_str();
- }
-
- void Config::setActiveViews(const char * views)
- {
- getImpl()->activeViews_.clear();
- SplitStringEnvStyle(getImpl()->activeViews_, views);
-
- getImpl()->displayCache_.clear();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
- const char * Config::getActiveViews() const
- {
- getImpl()->activeViewsStr_ = JoinStringEnvStyle(getImpl()->activeViews_);
- return getImpl()->activeViewsStr_.c_str();
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
-
- void Config::getDefaultLumaCoefs(float * c3) const
- {
- memcpy(c3, &getImpl()->defaultLumaCoefs_[0], 3*sizeof(float));
- }
-
- void Config::setDefaultLumaCoefs(const float * c3)
- {
- memcpy(&getImpl()->defaultLumaCoefs_[0], c3, 3*sizeof(float));
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
-
-
-
- ///////////////////////////////////////////////////////////////////////////
-
-
-
-
- ConstLookRcPtr Config::getLook(const char * name) const
- {
- std::string namelower = pystring::lower(name);
-
- for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
- {
- if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
- {
- return getImpl()->looksList_[i];
- }
- }
-
- return ConstLookRcPtr();
- }
-
- int Config::getNumLooks() const
- {
- return static_cast<int>(getImpl()->looksList_.size());
- }
-
- const char * Config::getLookNameByIndex(int index) const
- {
- if(index<0 || index>=static_cast<int>(getImpl()->looksList_.size()))
- {
- return "";
- }
-
- return getImpl()->looksList_[index]->getName();
- }
-
- void Config::addLook(const ConstLookRcPtr & look)
- {
- std::string name = look->getName();
- if(name.empty())
- throw Exception("Cannot addLook with an empty name.");
-
- std::string namelower = pystring::lower(name);
-
- // If the look exists, replace it
- for(unsigned int i=0; i<getImpl()->looksList_.size(); ++i)
- {
- if(pystring::lower(getImpl()->looksList_[i]->getName()) == namelower)
- {
- getImpl()->looksList_[i] = look->createEditableCopy();
- return;
- }
- }
-
- // Otherwise, add it
- getImpl()->looksList_.push_back(look->createEditableCopy());
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- void Config::clearLooks()
- {
- getImpl()->looksList_.clear();
-
- AutoMutex lock(getImpl()->cacheidMutex_);
- getImpl()->resetCacheIDs();
- }
-
- ///////////////////////////////////////////////////////////////////////////
-
-
-
- ConstProcessorRcPtr Config::getProcessor(const ConstColorSpaceRcPtr & src,
- const ConstColorSpaceRcPtr & dst) const
- {
- ConstContextRcPtr context = getCurrentContext();
- return getProcessor(context, src, dst);
- }
-
- ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
- const ConstColorSpaceRcPtr & src,
- const ConstColorSpaceRcPtr & dst) const
- {
- if(!src)
- {
- throw Exception("Config::GetProcessor failed. Source colorspace is null.");
- }
- if(!dst)
- {
- throw Exception("Config::GetProcessor failed. Destination colorspace is null.");
- }
-
- ProcessorRcPtr processor = Processor::Create();
- processor->getImpl()->addColorSpaceConversion(*this, context, src, dst);
- processor->getImpl()->finalize();
- return processor;
- }
-
- ConstProcessorRcPtr Config::getProcessor(const char * srcName,
- const char * dstName) const
- {
- ConstContextRcPtr context = getCurrentContext();
- return getProcessor(context, srcName, dstName);
- }
-
- //! Names can be colorspace name or role name
- ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
- const char * srcName,
- const char * dstName) const
- {
- ConstColorSpaceRcPtr src = getColorSpace(srcName);
- if(!src)
- {
- std::ostringstream os;
- os << "Could not find colorspace '" << srcName << "'.";
- throw Exception(os.str().c_str());
- }
-
- ConstColorSpaceRcPtr dst = getColorSpace(dstName);
- if(!dst)
- {
- std::ostringstream os;
- os << "Could not find colorspace '" << dstName << "'.";
- throw Exception(os.str().c_str());
- }
-
- return getProcessor(context, src, dst);
- }
-
-
- ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform) const
- {
- return getProcessor(transform, TRANSFORM_DIR_FORWARD);
- }
-
-
- ConstProcessorRcPtr Config::getProcessor(const ConstTransformRcPtr& transform,
- TransformDirection direction) const
- {
- ConstContextRcPtr context = getCurrentContext();
- return getProcessor(context, transform, direction);
- }
-
- ConstProcessorRcPtr Config::getProcessor(const ConstContextRcPtr & context,
- const ConstTransformRcPtr& transform,
- TransformDirection direction) const
- {
- ProcessorRcPtr processor = Processor::Create();
- processor->getImpl()->addTransform(*this, context, transform, direction);
- processor->getImpl()->finalize();
- return processor;
- }
-
- std::ostream& operator<< (std::ostream& os, const Config& config)
- {
- config.serialize(os);
- return os;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // CacheID
-
- const char * Config::getCacheID() const
- {
- return getCacheID(getCurrentContext());
- }
-
- const char * Config::getCacheID(const ConstContextRcPtr & context) const
- {
- AutoMutex lock(getImpl()->cacheidMutex_);
-
- // A null context will use the empty cacheid
- std::string contextcacheid = "";
- if(context) contextcacheid = context->getCacheID();
-
- StringMap::const_iterator cacheiditer = getImpl()->cacheids_.find(contextcacheid);
- if(cacheiditer != getImpl()->cacheids_.end())
- {
- return cacheiditer->second.c_str();
- }
-
- // Include the hash of the yaml config serialization
- if(getImpl()->cacheidnocontext_.empty())
- {
- std::stringstream cacheid;
- serialize(cacheid);
- std::string fullstr = cacheid.str();
- getImpl()->cacheidnocontext_ = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
- }
-
- // Also include all file references, using the context (if specified)
- std::string fileReferencesFashHash = "";
- if(context)
- {
- std::ostringstream filehash;
-
- ConstTransformVec allTransforms;
- getImpl()->getAllIntenalTransforms(allTransforms);
-
- std::set<std::string> files;
- for(unsigned int i=0; i<allTransforms.size(); ++i)
- {
- GetFileReferences(files, allTransforms[i]);
- }
-
- for(std::set<std::string>::iterator iter = files.begin();
- iter != files.end(); ++iter)
- {
- if(iter->empty()) continue;
- filehash << *iter << "=";
-
- try
- {
- std::string resolvedLocation = context->resolveFileLocation(iter->c_str());
- filehash << GetFastFileHash(resolvedLocation) << " ";
- }
- catch(...)
- {
- filehash << "? ";
- continue;
- }
- }
-
- std::string fullstr = filehash.str();
- fileReferencesFashHash = CacheIDHash(fullstr.c_str(), (int)fullstr.size());
- }
-
- getImpl()->cacheids_[contextcacheid] = getImpl()->cacheidnocontext_ + ":" + fileReferencesFashHash;
- return getImpl()->cacheids_[contextcacheid].c_str();
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Serialization
-
- void Config::serialize(std::ostream& os) const
- {
- try
- {
- getImpl()->io_.write(os, this);
- }
- catch( const std::exception & e)
- {
- std::ostringstream error;
- error << "Error building YAML: " << e.what();
- throw Exception(error.str().c_str());
- }
- }
-
- void Config::Impl::resetCacheIDs()
- {
- cacheids_.clear();
- cacheidnocontext_ = "";
- sanity_ = SANITY_UNKNO…