ColorProcessor* ColorConfig::createLookTransform (string_view looks, string_view inputColorSpace, string_view outputColorSpace, bool inverse, string_view context_key, string_view context_val) const { #ifdef USE_OCIO // Ask OCIO to make a Processor that can handle the requested // transformation. if (getImpl()->config_) { OCIO::ConstConfigRcPtr config = getImpl()->config_; OCIO::LookTransformRcPtr transform = OCIO::LookTransform::Create(); transform->setLooks (looks.c_str()); OCIO::TransformDirection dir; if (inverse) { // The TRANSFORM_DIR_INVERSE applies an inverse for the // end-to-end transform, which would otherwise do dst->inv // look -> src. This is an unintuitive result for the // artist (who would expect in, out to remain unchanged), so // we account for that here by flipping src/dst transform->setSrc (outputColorSpace.c_str()); transform->setDst (inputColorSpace.c_str()); dir = OCIO::TRANSFORM_DIR_INVERSE; } else { // forward transform->setSrc (inputColorSpace.c_str()); transform->setDst (outputColorSpace.c_str()); dir = OCIO::TRANSFORM_DIR_FORWARD; } OCIO::ConstContextRcPtr context = config->getCurrentContext(); if (context_key.size() && context_val.size()) { OCIO::ContextRcPtr ctx = context->createEditableCopy(); ctx->setStringVar (context_key.c_str(), context_val.c_str()); context = ctx; } OCIO::ConstProcessorRcPtr p; try { // Get the processor corresponding to this transform. p = getImpl()->config_->getProcessor (context, transform, dir); } catch(OCIO::Exception &e) { getImpl()->error_ = e.what(); return NULL; } catch(...) { getImpl()->error_ = "An unknown error occurred in OpenColorIO, getProcessor"; return NULL; } getImpl()->error_ = ""; return new ColorProcessor_OCIO(p); } #endif return NULL; // if we get this far, we've failed }
int main (int argc, const char* argv[]) { bool help = false; int cubesize = -1; int shapersize = -1; // cubsize^2 std::string format; std::string inputconfig; std::string inputspace; std::string shaperspace; std::string looks; std::string outputspace; bool usestdout = false; bool verbose = false; int whitepointtemp = 6505; std::string displayicc; std::string description; std::string copyright = "No copyright. Use freely."; // What are the allowed baker output formats? std::ostringstream formats; formats << "the LUT format to bake: "; for(int i=0; i<OCIO::Baker::getNumFormats(); ++i) { if(i!=0) formats << ", "; formats << OCIO::Baker::getFormatNameByIndex(i); formats << " (." << OCIO::Baker::getFormatExtensionByIndex(i) << ")"; } formats << ", icc (.icc)"; std::string formatstr = formats.str(); std::string dummystr; float dummyf1, dummyf2, dummyf3; ArgParse ap; ap.options("ociobakelut -- create a new LUT or ICC profile from an OCIO config or LUT file(s)\n\n" "usage: ociobakelut [options] <OUTPUTFILE.LUT>\n\n" "example: ociobakelut --inputspace lg10 --outputspace srgb8 --format flame lg_to_srgb.3dl\n" "example: ociobakelut --lut filmlut.3dl --lut calibration.3dl --format flame display.3dl\n" "example: ociobakelut --cccid 0 --lut cdlgrade.ccc --lut calibration.3dl --format flame graded_display.3dl\n" "example: ociobakelut --lut look.3dl --offset 0.01 -0.02 0.03 --lut display.3dl --format flame display_with_look.3dl\n" "example: ociobakelut --inputspace lg10 --outputspace srgb8 --format icc ~/Library/ColorSync/Profiles/test.icc\n" "example: ociobakelut --lut filmlut.3dl --lut calibration.3dl --format icc ~/Library/ColorSync/Profiles/test.icc\n\n", "%*", parse_end_args, "", "<SEPARATOR>", "Using Existing OCIO Configurations", "--inputspace %s", &inputspace, "Input OCIO ColorSpace (or Role)", "--outputspace %s", &outputspace, "Output OCIO ColorSpace (or Role)", "--shaperspace %s", &shaperspace, "the OCIO ColorSpace or Role, for the shaper", "--looks %s", &looks, "the OCIO looks to apply", "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)\n", "<SEPARATOR>", "Config-Free LUT Baking", "<SEPARATOR>", " (all options can be specified multiple times, each is applied in order)", "--cccid %s", &dummystr, "Specify a CCCId for any following LUTs", "--lut %s", &dummystr, "Specify a LUT (forward direction)", "--invlut %s", &dummystr, "Specify a LUT (inverse direction)", "--slope %f %f %f", &dummyf1, &dummyf2, &dummyf3, "slope", "--offset %f %f %f", &dummyf1, &dummyf2, &dummyf3, "offset (float)", "--offset10 %f %f %f", &dummyf1, &dummyf2, &dummyf3, "offset (10-bit)", "--power %f %f %f", &dummyf1, &dummyf2, &dummyf3, "power", "--sat %f", &dummyf1, "saturation (ASC-CDL luma coefficients)\n", "<SEPARATOR>", "Baking Options", "--format %s", &format, formatstr.c_str(), "--shapersize %d", &shapersize, "size of the shaper (default: format specific)", "--cubesize %d", &cubesize, "size of the cube (default: format specific)", "--stdout", &usestdout, "Write to stdout (rather than file)", "--v", &verbose, "Verbose", "--help", &help, "Print help message\n", "<SEPARATOR>", "ICC Options", //"--cubesize %d", &cubesize, "size of the ICC CLUT cube (default: 32)", "--whitepoint %d", &whitepointtemp, "whitepoint for the profile (default: 6505)", "--displayicc %s", &displayicc , "an ICC profile which matches the OCIO profiles target display", "--description %s", &description , "a meaningful description, this will show up in UI like photoshop (defaults to \"filename.icc\")", "--copyright %s", ©right , "a copyright field (default: \"No copyright. Use freely.\"\n", // TODO: add --metadata option NULL); if (ap.parse(argc, argv) < 0) { std::cout << ap.geterror() << std::endl; ap.usage(); std::cout << "\n"; return 1; } if (help || (argc == 1 )) { ap.usage(); std::cout << "\n"; return 1; } // If we're printing to stdout, disable verbose printouts if(usestdout) { verbose = false; } // Create the OCIO processor for the specified transform. OCIO::ConstConfigRcPtr config; OCIO::GroupTransformRcPtr groupTransform; try { groupTransform = parse_luts(argc, argv); } catch(const OCIO::Exception & e) { std::cerr << "\nERROR: " << e.what() << std::endl; std::cerr << "See --help for more info." << std::endl; return 1; } catch(...) { std::cerr << "\nERROR: An unknown error occurred in parse_luts" << std::endl; std::cerr << "See --help for more info." << std::endl; return 1; } if(!groupTransform) { std::cerr << "\nERROR: parse_luts returned null transform" << std::endl; std::cerr << "See --help for more info." << std::endl; return 1; } // If --luts have been specified, synthesize a new (temporary) configuration // with the transformation embedded in a colorspace. if(!groupTransform->empty()) { if(!inputspace.empty()) { std::cerr << "\nERROR: --inputspace is not allowed when using --lut\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(!outputspace.empty()) { std::cerr << "\nERROR: --outputspace is not allowed when using --lut\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(!looks.empty()) { std::cerr << "\nERROR: --looks is not allowed when using --lut\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(!shaperspace.empty()) { std::cerr << "\nERROR: --shaperspace is not allowed when using --lut\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } OCIO::ConfigRcPtr editableConfig = OCIO::Config::Create(); OCIO::ColorSpaceRcPtr inputColorSpace = OCIO::ColorSpace::Create(); inputspace = "RawInput"; inputColorSpace->setName(inputspace.c_str()); editableConfig->addColorSpace(inputColorSpace); OCIO::ColorSpaceRcPtr outputColorSpace = OCIO::ColorSpace::Create(); outputspace = "ProcessedOutput"; outputColorSpace->setName(outputspace.c_str()); outputColorSpace->setTransform(groupTransform, OCIO::COLORSPACE_DIR_FROM_REFERENCE); if(verbose) { std::cout << "[OpenColorIO DEBUG]: Specified Transform:"; std::cout << *groupTransform; std::cout << "\n"; } editableConfig->addColorSpace(outputColorSpace); config = editableConfig; } else { if(inputspace.empty()) { std::cerr << "\nERROR: You must specify the --inputspace.\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(outputspace.empty()) { std::cerr << "\nERROR: You must specify the --outputspace.\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(format.empty()) { std::cerr << "\nERROR: You must specify the LUT format using --format.\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(!inputconfig.empty()) { if(!usestdout && verbose) std::cout << "[OpenColorIO INFO]: Loading " << inputconfig << std::endl; config = OCIO::Config::CreateFromFile(inputconfig.c_str()); } else if(getenv("OCIO")) { if(!usestdout && verbose) std::cout << "[OpenColorIO INFO]: Loading $OCIO " << getenv("OCIO") << std::endl; config = OCIO::Config::CreateFromEnv(); } else { std::cerr << "ERROR: You must specify an input OCIO configuration "; std::cerr << "(either with --iconfig or $OCIO).\n\n"; ap.usage (); return 1; } } if(outputfile.empty() && !usestdout) { std::cerr << "\nERROR: You must specify the outputfile or --stdout.\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } try { if(format == "icc") { if(description.empty()) { description = outputfile; if(verbose) std::cout << "[OpenColorIO INFO]: \"--description\" set to default value of filename.icc: " << outputfile << "" << std::endl; } if(usestdout) { std::cerr << "\nERROR: --stdout not supported when writing ICC profiles.\n\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(outputfile.empty()) { std::cerr << "ERROR: you need to specify a output ICC path\n"; std::cerr << "See --help for more info." << std::endl; return 1; } if(cubesize<2) cubesize = 32; // default OCIO::ConstProcessorRcPtr processor; if (!looks.empty()) { OCIO::LookTransformRcPtr transform = OCIO::LookTransform::Create(); transform->setLooks(looks.c_str()); transform->setSrc(inputspace.c_str()); transform->setDst(outputspace.c_str()); processor = config->getProcessor(transform, OCIO::TRANSFORM_DIR_FORWARD); } else { processor = config->getProcessor(inputspace.c_str(), outputspace.c_str()); } SaveICCProfileToFile(outputfile, processor, cubesize, whitepointtemp, displayicc, description, copyright, verbose); } else { OCIO::BakerRcPtr baker = OCIO::Baker::Create(); // setup the baker for our LUT type baker->setConfig(config); baker->setFormat(format.c_str()); baker->setInputSpace(inputspace.c_str()); baker->setShaperSpace(shaperspace.c_str()); baker->setLooks(looks.c_str()); baker->setTargetSpace(outputspace.c_str()); if(shapersize!=-1) baker->setShaperSize(shapersize); if(cubesize!=-1) baker->setCubeSize(cubesize); // output LUT std::ostringstream output; if(!usestdout && verbose) std::cout << "[OpenColorIO INFO]: Baking '" << format << "' LUT" << std::endl; if(usestdout) { baker->bake(std::cout); } else { std::ofstream f(outputfile.c_str()); baker->bake(f); if(verbose) std::cout << "[OpenColorIO INFO]: Wrote '" << outputfile << "'" << std::endl; } } } catch(OCIO::Exception & exception) { std::cerr << "OCIO Error: " << exception.what() << std::endl; std::cerr << "See --help for more info." << std::endl; return 1; } catch (std::exception& exception) { std::cerr << "Error: " << exception.what() << "\n"; std::cerr << "See --help for more info." << std::endl; return 1; } catch(...) { std::cerr << "Unknown OCIO error encountered." << std::endl; std::cerr << "See --help for more info." << std::endl; return 1; } return 0; }
void OCIOLookTransform::_validate(bool for_real) { if(!m_hasColorSpaces) { error("No colorspaces available for input and/or output."); return; } int inputColorSpaceCount = static_cast<int>(m_inputColorSpaceCstrNames.size()) - 1; if(m_inputColorSpaceIndex < 0 || m_inputColorSpaceIndex >= inputColorSpaceCount) { std::ostringstream err; err << "Input colorspace index (" << m_inputColorSpaceIndex << ") out of range."; error(err.str().c_str()); return; } int outputColorSpaceCount = static_cast<int>(m_outputColorSpaceCstrNames.size()) - 1; if(m_outputColorSpaceIndex < 0 || m_outputColorSpaceIndex >= outputColorSpaceCount) { std::ostringstream err; err << "Output colorspace index (" << m_outputColorSpaceIndex << ") out of range."; error(err.str().c_str()); return; } try { OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); const char * inputName = config->getColorSpaceNameByIndex(m_inputColorSpaceIndex); const char * outputName = config->getColorSpaceNameByIndex(m_outputColorSpaceIndex); OCIO::LookTransformRcPtr transform = OCIO::LookTransform::Create(); const char * look = m_lookCstrNames[m_lookIndex]; if(look != NULL) { transform->setLooks(look); } OCIO::ConstContextRcPtr context = getLocalContext(); OCIO::TransformDirection direction = OCIO::TRANSFORM_DIR_UNKNOWN; bool invertTransform = (m_dirIndex == 0) ? false : true; // Forward if(!invertTransform) { transform->setSrc(inputName); transform->setDst(outputName); direction = OCIO::TRANSFORM_DIR_FORWARD; } else { // The TRANSFORM_DIR_INVERSE applies an inverse for the end-to-end transform, // which would otherwise do dst->inv look -> src. // This is an unintuitive result for the artist (who would expect in, out to // remain unchanged), so we account for that here by flipping src/dst transform->setSrc(outputName); transform->setDst(inputName); direction = OCIO::TRANSFORM_DIR_INVERSE; } try { m_processor = config->getProcessor(context, transform, direction); } // We only catch the exceptions for missing files, and try to succeed // in this case. All other errors represent more serious problems and // should fail through. catch(const OCIO::ExceptionMissingFile &e) { if(!m_ignoreErrors) throw; m_processor = config->getProcessor(context, inputName, outputName); } } catch(const OCIO::Exception &e) { error(e.what()); return; } catch (...) { error("OCIOLookTransform: Unknown exception during _validate."); return; } if(m_processor->isNoOp()) { set_out_channels(DD::Image::Mask_None); // prevents engine() from being called } else { set_out_channels(DD::Image::Mask_All); } DD::Image::PixelIop::_validate(for_real); }