void OCIOColorSpace::_validate(bool for_real) { input0().validate(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 { const char * inputName = m_inputColorSpaceCstrNames[m_inputColorSpaceIndex]; const char * outputName = m_outputColorSpaceCstrNames[m_outputColorSpaceIndex]; OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); config->sanityCheck(); OCIO::ConstContextRcPtr context = getLocalContext(); m_processor = config->getProcessor(context, inputName, outputName); } catch(OCIO::Exception &e) { error(e.what()); return; } if(m_processor->isNoOp()) { // TODO or call disable() ? set_out_channels(DD::Image::Mask_None); // prevents engine() from being called copy_info(); return; } set_out_channels(DD::Image::Mask_All); DD::Image::PixelIop::_validate(for_real); }
void Generate(int cubesize, int maxwidth, const std::string & outputfile, const std::string & configfile, const std::string & incolorspace, const std::string & outcolorspace) { int width = 0; int height = 0; int numchannels = 3; GetLutImageSize(width, height, cubesize, maxwidth); std::vector<float> img; img.resize(width*height*numchannels, 0); GenerateIdentityLut3D(&img[0], cubesize, numchannels, LUT3DORDER_FAST_RED); if(!incolorspace.empty() || !outcolorspace.empty()) { OCIO::ConstConfigRcPtr config = OCIO::Config::Create(); if(!configfile.empty()) { config = OCIO::Config::CreateFromFile(configfile.c_str()); } else if(getenv("OCIO")) { config = OCIO::Config::CreateFromEnv(); } else { std::ostringstream os; os << "You must specify an ocio configuration "; os << "(either with --config or $OCIO)."; throw Exception(os.str().c_str()); } OCIO::ConstProcessorRcPtr processor = config->getProcessor(incolorspace.c_str(), outcolorspace.c_str()); OCIO::PackedImageDesc imgdesc(&img[0], width, height, 3); processor->apply(imgdesc); } OIIO::ImageOutput* f = OIIO::ImageOutput::create(outputfile); if(!f) { throw Exception( "Could not create output image."); } OIIO::ImageSpec spec(width, height, numchannels, OIIO::TypeDesc::TypeFloat); // TODO: If DPX, force 16-bit output? f->open(outputfile, spec); f->write_image(OIIO::TypeDesc::FLOAT, &img[0]); f->close(); delete f; }
void OCIOFileTransform::_validate(bool for_real) { input0().validate(for_real); if(!src) { error("The source file must be specified."); return; } try { OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); config->sanityCheck(); OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create(); transform->setSrc(src); // TODO: For some reason, cccid is NOT incorporated in this node's hash. // Until then, cccid is considered broken. Figure out why. transform->setCCCId(cccid.c_str()); if(dirindex == 0) transform->setDirection(OCIO::TRANSFORM_DIR_FORWARD); else transform->setDirection(OCIO::TRANSFORM_DIR_INVERSE); if(interpindex == 0) transform->setInterpolation(OCIO::INTERP_NEAREST); else transform->setInterpolation(OCIO::INTERP_LINEAR); processor = config->getProcessor(transform, OCIO::TRANSFORM_DIR_FORWARD); } catch(OCIO::Exception &e) { error(e.what()); return; } if(processor->isNoOp()) { // TODO or call disable() ? set_out_channels(DD::Image::Mask_None); // prevents engine() from being called copy_info(); return; } set_out_channels(DD::Image::Mask_All); DD::Image::PixelIop::_validate(for_real); }
void OCIOFileTransform::_validate(bool for_real) { if(!m_file) { error("The source file must be specified."); return; } try { OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create(); transform->setSrc(m_file); transform->setCCCId(m_cccid.c_str()); if(m_dirindex == 0) transform->setDirection(OCIO::TRANSFORM_DIR_FORWARD); else transform->setDirection(OCIO::TRANSFORM_DIR_INVERSE); if(m_interpindex == 0) transform->setInterpolation(OCIO::INTERP_NEAREST); else if(m_interpindex == 1) transform->setInterpolation(OCIO::INTERP_LINEAR); else if(m_interpindex == 2) transform->setInterpolation(OCIO::INTERP_TETRAHEDRAL); else if(m_interpindex == 3) transform->setInterpolation(OCIO::INTERP_BEST); else { // Should never happen error("Interpolation value out of bounds"); return; } m_processor = config->getProcessor(transform, OCIO::TRANSFORM_DIR_FORWARD); } catch(OCIO::Exception &e) { error(e.what()); 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); }
void OCIOCDLTransform::_validate(bool for_real) { input0().validate(for_real); try { OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); config->sanityCheck(); OCIO::CDLTransformRcPtr cc = OCIO::CDLTransform::Create(); cc->setSlope(m_slope); cc->setOffset(m_offset); cc->setPower(m_power); cc->setSat(m_saturation); if(m_dirindex == 0) cc->setDirection(OCIO::TRANSFORM_DIR_FORWARD); else cc->setDirection(OCIO::TRANSFORM_DIR_INVERSE); m_processor = config->getProcessor(cc); } catch(OCIO::Exception &e) { error(e.what()); return; } if(m_processor->isNoOp()) { // TODO or call disable() ? set_out_channels(DD::Image::Mask_None); // prevents engine() from being called copy_info(); return; } set_out_channels(DD::Image::Mask_All); DD::Image::PixelIop::_validate(for_real); }
ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace) { #ifdef WITH_OCIO /* Only use this for OpenColorIO color spaces, not the builtin ones. */ assert(colorspace != u_colorspace_srgb && colorspace != u_colorspace_auto); if (colorspace == u_colorspace_raw) { return NULL; } OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); if (!config) { return NULL; } /* Cache processor until free_memory(), memory overhead is expected to be * small and the processor is likely to be reused. */ thread_scoped_lock cache_processors_lock(cache_processors_mutex); if (cached_processors.find(colorspace) == cached_processors.end()) { try { cached_processors[colorspace] = config->getProcessor(colorspace.c_str(), "scene_linear"); } catch (OCIO::Exception &exception) { cached_processors[colorspace] = OCIO::ConstProcessorRcPtr(); VLOG(1) << "Colorspace " << colorspace.c_str() << " can't be converted to scene_linear: " << exception.what(); } } const OCIO::Processor *processor = cached_processors[colorspace].get(); return (ColorSpaceProcessor *)processor; #else /* No OpenColorIO. */ (void)colorspace; return NULL; #endif }
void OCIOLogConvert::_validate(bool for_real) { try { OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); const char * src = 0; const char * dst = 0; if(modeindex == 0) { src = OCIO::ROLE_COMPOSITING_LOG; dst = OCIO::ROLE_SCENE_LINEAR; } else { src = OCIO::ROLE_SCENE_LINEAR; dst = OCIO::ROLE_COMPOSITING_LOG; } processor = config->getProcessor(src, dst); } catch(OCIO::Exception &e) { error(e.what()); return; } if(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); }
int main(int argc, char **argv) { if(argc<5) { std::cerr << USAGE_TEXT << std::endl; exit(0); } const char * inputimage = argv[1]; const char * inputcolorspace = argv[2]; const char * outputimage = argv[3]; const char * outputcolorspace = argv[4]; OIIO::ImageSpec spec; std::vector<float> img; int imgwidth = 0; int imgheight = 0; int components = 0; // Load the image std::cerr << "Loading " << inputimage << std::endl; try { OIIO::ImageInput* f = OIIO::ImageInput::create(inputimage); if(!f) { std::cerr << "Could not create image input." << std::endl; exit(1); } f->open(inputimage, spec); std::string error = f->geterror(); if(!error.empty()) { std::cerr << "Error loading image " << error << std::endl; exit(1); } imgwidth = spec.width; imgheight = spec.height; components = spec.nchannels; img.resize(imgwidth*imgheight*components); memset(&img[0], 0, imgwidth*imgheight*components*sizeof(float)); f->read_image(OIIO::TypeDesc::TypeFloat, &img[0]); delete f; } catch(...) { std::cerr << "Error loading file."; exit(1); } // Process the image try { // Load the current config. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); // Get the processor OCIO::ConstProcessorRcPtr processor = config->getProcessor(inputcolorspace, outputcolorspace); // Wrap the image in a light-weight ImageDescription OCIO::PackedImageDesc imageDesc(&img[0], imgwidth, imgheight, components); // Apply the color transformation (in place) processor->apply(imageDesc); } catch(OCIO::Exception & exception) { std::cerr << "OCIO Error: " << exception.what() << std::endl; } catch(...) { std::cerr << "Unknown OCIO error encountered." << std::endl; } // Write out the result try { OIIO::ImageOutput* f = OIIO::ImageOutput::create(outputimage); if(!f) { std::cerr << "Could not create output input." << std::endl; exit(1); } f->open(outputimage, spec); f->write_image(OIIO::TypeDesc::FLOAT, &img[0]); f->close(); delete f; } catch(...) { std::cerr << "Error loading file."; exit(1); } std::cerr << "Wrote " << outputimage << std::endl; return 0; }
void OCIOProcessor::setValues(const OCIO_NAMESPACE::ConstConfigRcPtr &config, const OCIO_NAMESPACE::ConstContextRcPtr &context, const OCIO_NAMESPACE::ConstTransformRcPtr& transform, OCIO_NAMESPACE::TransformDirection direction) { _proc = config->getProcessor(context, transform, direction); }
void OCIOProcessor::setValues(const OCIO_NAMESPACE::ConstConfigRcPtr &config, const OCIO_NAMESPACE::ConstTransformRcPtr& transform) { _proc = config->getProcessor(transform); }
void OCIOProcessor::setValues(const OCIO_NAMESPACE::ConstConfigRcPtr &config, const OCIO_NAMESPACE::ConstContextRcPtr &context, const std::string& inputSpace, const std::string& outputSpace) { _proc = config->getProcessor(context, inputSpace.c_str(), outputSpace.c_str()); }
int main(int argc, const char **argv) { bool help = false; int errorcount = 0; std::string inputconfig; std::string outputconfig; ArgParse ap; ap.options("ociocheck -- validate an OpenColorIO configuration\n\n" "usage: ociocheck [options]\n", "--help", &help, "Print help message", "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)", "--oconfig %s", &outputconfig, "Output .ocio file", NULL); if (ap.parse(argc, argv) < 0) { std::cout << ap.geterror() << std::endl; ap.usage(); std::cout << DESC_STRING; return 1; } if (help) { ap.usage(); std::cout << DESC_STRING; return 1; } try { OCIO::ConstConfigRcPtr config; std::cout << std::endl; std::cout << "OpenColorIO Library Version: " << OCIO::GetVersion() << std::endl; std::cout << "OpenColorIO Library VersionHex: " << OCIO::GetVersionHex() << std::endl; if(!inputconfig.empty()) { std::cout << "Loading " << inputconfig << std::endl; config = OCIO::Config::CreateFromFile(inputconfig.c_str()); } else if(getenv("OCIO")) { std::cout << "Loading $OCIO " << getenv("OCIO") << std::endl; config = OCIO::Config::CreateFromEnv(); } else { std::cout << "ERROR: You must specify an input OCIO configuration "; std::cout << "(either with --iconfig or $OCIO).\n"; ap.usage (); std::cout << DESC_STRING; return 1; } std::cout << std::endl; std::cout << "** General **" << std::endl; std::cout << "Search Path: " << config->getSearchPath() << std::endl; std::cout << "Working Dir: " << config->getWorkingDir() << std::endl; std::cout << std::endl; std::cout << "Default Display: " << config->getDefaultDisplay() << std::endl; std::cout << "Default View: " << config->getDefaultView(config->getDefaultDisplay()) << std::endl; { std::cout << std::endl; std::cout << "** Roles **" << std::endl; std::set<std::string> usedroles; const char * allroles[] = { OCIO::ROLE_DEFAULT, OCIO::ROLE_SCENE_LINEAR, OCIO::ROLE_DATA, OCIO::ROLE_REFERENCE, OCIO::ROLE_COMPOSITING_LOG, OCIO::ROLE_COLOR_TIMING, OCIO::ROLE_COLOR_PICKING, OCIO::ROLE_TEXTURE_PAINT, OCIO::ROLE_MATTE_PAINT, NULL }; int MAXROLES=256; for(int i=0;i<MAXROLES; ++i) { const char * role = allroles[i]; if(!role) break; usedroles.insert(role); OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(role); if(cs) { std::cout << cs->getName() << " (" << role << ")" << std::endl; } else { std::cout << "ERROR: NOT DEFINED" << " (" << role << ")" << std::endl; errorcount += 1; } } for(int i=0; i<config->getNumRoles(); ++i) { const char * role = config->getRoleName(i); if(usedroles.find(role) != usedroles.end()) continue; OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(role); if(cs) { std::cout << cs->getName() << " (" << role << ": user)" << std::endl; } else { std::cout << "ERROR: NOT DEFINED" << " (" << role << ")" << std::endl; errorcount += 1; } } } std::cout << std::endl; std::cout << "** ColorSpaces **" << std::endl; OCIO::ConstColorSpaceRcPtr lin = config->getColorSpace(OCIO::ROLE_SCENE_LINEAR); if(!lin) { std::cout << "Error: scene_linear role must be defined." << std::endl; errorcount += 1; } else { for(int i=0; i<config->getNumColorSpaces(); ++i) { OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(config->getColorSpaceNameByIndex(i)); bool convertsToLinear = true; std::string convertsToLinearErrorText; bool convertsFromLinear = true; std::string convertsFromLinearErrorText; try { OCIO::ConstProcessorRcPtr p = config->getProcessor(cs, lin); } catch(OCIO::Exception & exception) { convertsToLinear = false; convertsToLinearErrorText = exception.what(); } try { OCIO::ConstProcessorRcPtr p = config->getProcessor(lin, cs); } catch(OCIO::Exception & exception) { convertsFromLinear = false; convertsFromLinearErrorText = exception.what(); } if(convertsToLinear && convertsFromLinear) { std::cout << cs->getName() << std::endl; } else if(!convertsToLinear && !convertsFromLinear) { std::cout << cs->getName(); std::cout << " -- error" << std::endl; std::cout << "\t" << convertsToLinearErrorText << std::endl; std::cout << "\t" << convertsFromLinearErrorText << std::endl; errorcount += 1; } else if(convertsToLinear) { std::cout << cs->getName(); std::cout << " -- input only" << std::endl; } else if(convertsFromLinear) { std::cout << cs->getName(); std::cout << " -- output only" << std::endl; } } } std::cout << std::endl; std::cout << "** Looks **" << std::endl; if(config->getNumLooks()>0) { for(int i=0; i<config->getNumLooks(); ++i) { std::cout << config->getLookNameByIndex(i) << std::endl; } } else { std::cout << "no looks defined" << std::endl; } std::cout << std::endl; std::cout << "** Sanity Check **" << std::endl; try { config->sanityCheck(); std::cout << "passed" << std::endl; } catch(OCIO::Exception & exception) { std::cout << "ERROR" << std::endl; errorcount += 1; std::cout << exception.what() << std::endl; } if(!outputconfig.empty()) { std::ofstream output; output.open(outputconfig.c_str()); if(!output.is_open()) { std::cout << "Error opening " << outputconfig << " for writing." << std::endl; } else { config->serialize(output); output.close(); std::cout << "Wrote " << outputconfig << std::endl; } } } catch(OCIO::Exception & exception) { std::cout << "ERROR: " << exception.what() << std::endl; return 1; } catch (std::exception& exception) { std::cout << "ERROR: " << exception.what() << "\n"; return 1; } catch(...) { std::cout << "Unknown error encountered." << std::endl; return 1; } std::cout << std::endl; if(errorcount == 0) { std::cout << "Tests complete." << std::endl << std::endl; return 0; } else { std::cout << errorcount << " tests failed." << std::endl << std::endl; return 1; } }
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); }
void UpdateOCIOGLState() { // Step 0: Get the processor using any of the pipelines mentioned above. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setInputColorSpaceName( g_inputColorSpace.c_str() ); transform->setDisplay( g_display.c_str() ); transform->setView( g_transformName.c_str() ); // Add optional transforms to create a full-featured, "canonical" display pipeline // Fstop exposure control (in SCENE_LINEAR) { float gain = powf(2.0f, g_exposure_fstop); const float slope4f[] = { gain, gain, gain, gain }; float m44[16]; float offset4[4]; OCIO::MatrixTransform::Scale(m44, offset4, slope4f); OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create(); mtx->setValue(m44, offset4); transform->setLinearCC(mtx); } // Channel swizzling { float lumacoef[3]; config->getDefaultLumaCoefs(lumacoef); float m44[16]; float offset[4]; OCIO::MatrixTransform::View(m44, offset, g_channelHot, lumacoef); OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create(); swizzle->setValue(m44, offset); transform->setChannelView(swizzle); } // Post-display transform gamma { float exponent = 1.0f/std::max(1e-6f, static_cast<float>(g_display_gamma)); const float exponent4f[] = { exponent, exponent, exponent, exponent }; OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create(); expTransform->setValue(exponent4f); transform->setDisplayCC(expTransform); } OCIO::ConstProcessorRcPtr processor; try { processor = config->getProcessor(transform); } catch(OCIO::Exception & e) { std::cerr << e.what() << std::endl; return; } catch(...) { return; } // Step 1: Create a GPU Shader Description OCIO::GpuShaderDesc shaderDesc; shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE); // Step 2: Compute the 3D LUT std::string lut3dCacheID = processor->getGpuLut3DCacheID(shaderDesc); if(lut3dCacheID != g_lut3dcacheid) { //std::cerr << "Computing 3DLut " << g_lut3dcacheid << std::endl; g_lut3dcacheid = lut3dCacheID; processor->getGpuLut3D(&g_lut3d[0], shaderDesc); glBindTexture(GL_TEXTURE_3D, g_lut3dTexID); glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, GL_RGB,GL_FLOAT, &g_lut3d[0]); } // Step 3: Compute the Shader std::string shaderCacheID = processor->getGpuShaderTextCacheID(shaderDesc); if(g_program == 0 || shaderCacheID != g_shadercacheid) { //std::cerr << "Computing Shader " << g_shadercacheid << std::endl; g_shadercacheid = shaderCacheID; std::ostringstream os; os << processor->getGpuShaderText(shaderDesc) << "\n"; os << g_fragShaderText; //std::cerr << os.str() << std::endl; if(g_fragShader) glDeleteShader(g_fragShader); g_fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str()); if(g_program) glDeleteProgram(g_program); g_program = LinkShaders(g_fragShader); } glUseProgram(g_program); glUniform1i(glGetUniformLocation(g_program, "tex1"), 1); glUniform1i(glGetUniformLocation(g_program, "tex2"), 2); }
std::string HdxColorCorrectionTask::_CreateOpenColorIOResources() { #ifdef PXR_OCIO_PLUGIN_ENABLED // Use client provided OCIO values, or use default fallback values OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); const char* display = _displayOCIO.empty() ? config->getDefaultDisplay() : _displayOCIO.c_str(); const char* view = _viewOCIO.empty() ? config->getDefaultView(display) : _viewOCIO.c_str(); std::string inputColorSpace = _colorspaceOCIO; if (inputColorSpace.empty()) { OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace("default"); if (cs) { inputColorSpace = cs->getName(); } else { inputColorSpace = OCIO::ROLE_SCENE_LINEAR; } } // Setup the transformation we need to apply OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setDisplay(display); transform->setView(view); transform->setInputColorSpaceName(inputColorSpace.c_str()); if (!_looksOCIO.empty()) { transform->setLooksOverride(_looksOCIO.c_str()); transform->setLooksOverrideEnabled(true); } else { transform->setLooksOverrideEnabled(false); } OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform); // Create a GPU Shader Description OCIO::GpuShaderDesc shaderDesc; shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); shaderDesc.setFunctionName("OCIODisplay"); shaderDesc.setLut3DEdgeLen(_lut3dSizeOCIO); // Compute and the 3D LUT int num3Dentries = 3 * _lut3dSizeOCIO*_lut3dSizeOCIO*_lut3dSizeOCIO; std::vector<float> lut3d; lut3d.resize(num3Dentries); processor->getGpuLut3D(&lut3d[0], shaderDesc); // Load the data into an OpenGL 3D Texture if (_texture3dLUT != 0) { glDeleteTextures(1, &_texture3dLUT); } GLint restoreTexture; glGetIntegerv(GL_TEXTURE_BINDING_3D, &restoreTexture); glGenTextures(1, &_texture3dLUT); glBindTexture(GL_TEXTURE_3D, _texture3dLUT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, _lut3dSizeOCIO, _lut3dSizeOCIO, _lut3dSizeOCIO, 0, GL_RGB, GL_FLOAT, &lut3d[0]); glBindTexture(GL_TEXTURE_3D, restoreTexture); const char* gpuShaderText = processor->getGpuShaderText(shaderDesc); GLF_POST_PENDING_GL_ERRORS(); return std::string(gpuShaderText); #else return std::string(); #endif }
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 UpdateOCIOGLState() { // Step 0: Get the processor using any of the pipelines mentioned above. OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); transform->setInputColorSpaceName( g_inputColorSpace.c_str() ); transform->setDisplay( g_display.c_str() ); transform->setView( g_transformName.c_str() ); transform->setLooksOverride( g_look.c_str() ); if(g_verbose) { std::cout << std::endl; std::cout << "Color transformation composed of:" << std::endl; std::cout << " Image ColorSpace is:\t" << g_inputColorSpace << std::endl; std::cout << " Transform is:\t\t" << g_transformName << std::endl; std::cout << " Device is:\t\t" << g_display << std::endl; std::cout << " Looks Override is:\t'" << g_look << "'" << std::endl; std::cout << " with:" << std::endl; std::cout << " exposure_fstop = " << g_exposure_fstop << std::endl; std::cout << " display_gamma = " << g_display_gamma << std::endl; std::cout << " channels = " << (g_channelHot[0] ? "R" : "") << (g_channelHot[1] ? "G" : "") << (g_channelHot[2] ? "B" : "") << (g_channelHot[3] ? "A" : "") << std::endl; } // Add optional transforms to create a full-featured, "canonical" display pipeline // Fstop exposure control (in SCENE_LINEAR) { float gain = powf(2.0f, g_exposure_fstop); const float slope4f[] = { gain, gain, gain, gain }; float m44[16]; float offset4[4]; OCIO::MatrixTransform::Scale(m44, offset4, slope4f); OCIO::MatrixTransformRcPtr mtx = OCIO::MatrixTransform::Create(); mtx->setValue(m44, offset4); transform->setLinearCC(mtx); } // Channel swizzling { float lumacoef[3]; config->getDefaultLumaCoefs(lumacoef); float m44[16]; float offset[4]; OCIO::MatrixTransform::View(m44, offset, g_channelHot, lumacoef); OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create(); swizzle->setValue(m44, offset); transform->setChannelView(swizzle); } // Post-display transform gamma { float exponent = 1.0f/std::max(1e-6f, static_cast<float>(g_display_gamma)); const float exponent4f[] = { exponent, exponent, exponent, exponent }; OCIO::ExponentTransformRcPtr expTransform = OCIO::ExponentTransform::Create(); expTransform->setValue(exponent4f); transform->setDisplayCC(expTransform); } OCIO::ConstProcessorRcPtr processor; try { processor = config->getProcessor(transform); } catch(OCIO::Exception & e) { std::cerr << e.what() << std::endl; return; } catch(...) { return; } // Step 1: Create the appropriate GPU shader description OCIO::GpuShaderDescRcPtr shaderDesc = g_gpulegacy ? OCIO::GpuShaderDesc::CreateLegacyShaderDesc(LUT3D_EDGE_SIZE) : OCIO::GpuShaderDesc::CreateShaderDesc(); shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); shaderDesc->setFunctionName("OCIODisplay"); shaderDesc->setResourcePrefix("ocio_"); // Step 2: Collect the shader program information for a specific processor processor->extractGpuShaderInfo(shaderDesc); // Step 3: Use the helper OpenGL builder g_oglBuilder = OpenGLBuilder::Create(shaderDesc); g_oglBuilder->setVerbose(g_gpuinfo); // Step 4: Allocate & upload all the LUTs // // NB: The start index for the texture indices is 1 as one texture // was already created for the input image. // g_oglBuilder->allocateAllTextures(1); // Step 5: Build the fragment shader program g_oglBuilder->buildProgram(g_fragShaderText); // Step 6: Enable the fragment shader program, and all needed textures g_oglBuilder->useProgram(); // The image texture glUniform1i(glGetUniformLocation(g_oglBuilder->getProgramHandle(), "tex1"), 0); // The LUT textures g_oglBuilder->useAllTextures(); }