bool GenericOCIO::isIdentity(double time) { assert(_created); #ifdef OFX_IO_USING_OCIO if (!_config) { return true; } std::string inputSpace; getInputColorspaceAtTime(time, inputSpace); std::string outputSpace; getOutputColorspaceAtTime(time, outputSpace); if (inputSpace == outputSpace) { return true; } // must clear persistent message in isIdentity, or render() is not called by Nuke after an error _parent->clearPersistentMessage(); try { // maybe the names are not the same, but it's still a no-op (e.g. "scene_linear" and "linear") OCIO::ConstContextRcPtr context = getLocalContext(time);//_config->getCurrentContext(); OCIO_NAMESPACE::ConstProcessorRcPtr proc = _config->getProcessor(context, inputSpace.c_str(), outputSpace.c_str()); return proc->isNoOp(); } catch (const std::exception& e) { _parent->setPersistentMessage(OFX::Message::eMessageError, "", e.what()); OFX::throwSuiteStatusException(kOfxStatFailed); return false; } #else return true; #endif }
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; }
ColorProcessor* ColorConfig::createColorProcessor (string_view inputColorSpace, string_view outputColorSpace, string_view context_key, string_view context_value) const { string_view inputrole, outputrole; std::string pending_error; #ifdef USE_OCIO // Ask OCIO to make a Processor that can handle the requested // transformation. OCIO::ConstProcessorRcPtr p; if (getImpl()->config_) { // If the names are roles, convert them to color space names string_view name; name = getColorSpaceNameByRole (inputColorSpace); if (! name.empty()) { inputrole = inputColorSpace; inputColorSpace = name; } name = getColorSpaceNameByRole (outputColorSpace); if (! name.empty()) { outputrole = outputColorSpace; outputColorSpace = name; } OCIO::ConstConfigRcPtr config = getImpl()->config_; OCIO::ConstContextRcPtr context = config->getCurrentContext(); std::vector<string_view> keys, values; Strutil::split (context_key, keys, ","); Strutil::split (context_value, values, ","); if (keys.size() && values.size() && keys.size() == values.size()) { OCIO::ContextRcPtr ctx = context->createEditableCopy(); for (size_t i = 0; i < keys.size(); ++i) ctx->setStringVar (keys[i].c_str(), values[i].c_str()); context = ctx; } try { // Get the processor corresponding to this transform. p = getImpl()->config_->getProcessor(context, inputColorSpace.c_str(), outputColorSpace.c_str()); } catch(OCIO::Exception &e) { // Don't quit yet, remember the error and see if any of our // built-in knowledge of some generic spaces will save us. p.reset(); pending_error = e.what(); } catch(...) { getImpl()->error_ = "An unknown error occurred in OpenColorIO, getProcessor"; return NULL; } getImpl()->error_ = ""; if (p && ! p->isNoOp()) { // If we got a valid processor that does something useful, // return it now. If it boils down to a no-op, give a second // chance below to recognize it as a special case. return new ColorProcessor_OCIO(p); } } #endif // Either not compiled with OCIO support, or no OCIO configuration // was found at all. There are a few color conversions we know // about even in such dire conditions. using namespace Strutil; if (iequals(inputColorSpace,outputColorSpace)) { return new ColorProcessor_Ident; } if ((iequals(inputColorSpace,"linear") || iequals(inputrole,"linear") || iequals(inputColorSpace,"lnf") || iequals(inputColorSpace,"lnh")) && iequals(outputColorSpace,"sRGB")) { return new ColorProcessor_linear_to_sRGB; } if (iequals(inputColorSpace,"sRGB") && (iequals(outputColorSpace,"linear") || iequals(outputrole,"linear") || iequals(outputColorSpace,"lnf") || iequals(outputColorSpace,"lnh"))) { return new ColorProcessor_sRGB_to_linear; } if ((iequals(inputColorSpace,"linear") || iequals(inputrole,"linear") || iequals(inputColorSpace,"lnf") || iequals(inputColorSpace,"lnh")) && iequals(outputColorSpace,"Rec709")) { return new ColorProcessor_linear_to_Rec709; } if (iequals(inputColorSpace,"Rec709") && (iequals(outputColorSpace,"linear") || iequals(outputrole,"linear") || iequals(outputColorSpace,"lnf") || iequals(outputColorSpace,"lnh"))) { return new ColorProcessor_Rec709_to_linear; } #ifdef USE_OCIO if (p) { // If we found a procesor from OCIO, even if it was a NoOp, and we // still don't have a better idea, return it. return new ColorProcessor_OCIO(p); } #endif if (pending_error.size()) getImpl()->error_ = pending_error; return NULL; // if we get this far, we've failed }
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, 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; }
ColorProcessor* ColorConfig::createColorProcessor (string_view inputColorSpace, string_view outputColorSpace) const { string_view inputrole, outputrole; #ifdef USE_OCIO // Ask OCIO to make a Processor that can handle the requested // transformation. OCIO::ConstProcessorRcPtr p; if (getImpl()->config_) { // If the names are roles, convert them to color space names string_view name; name = getColorSpaceNameByRole (inputColorSpace); if (! name.empty()) { inputrole = inputColorSpace; inputColorSpace = name; } name = getColorSpaceNameByRole (outputColorSpace); if (! name.empty()) { outputrole = outputColorSpace; outputColorSpace = name; } try { // Get the processor corresponding to this transform. p = getImpl()->config_->getProcessor(inputColorSpace.c_str(), outputColorSpace.c_str()); } catch(OCIO::Exception &e) { getImpl()->error_ = e.what(); return NULL; } catch(...) { getImpl()->error_ = "An unknown error occurred in OpenColorIO, getProcessor"; return NULL; } getImpl()->error_ = ""; if (p && ! p->isNoOp()) { // If we got a valid processor that does something useful, // return it now. If it boils down to a no-op, give a second // chance below to recognize it as a special case. return new ColorProcessor_OCIO(p); } } #endif // Either not compiled with OCIO support, or no OCIO configuration // was found at all. There are a few color conversions we know // about even in such dire conditions. using namespace Strutil; if ((iequals(inputColorSpace,"linear") || iequals(inputrole,"linear")) && iequals(outputColorSpace,"sRGB")) { return new ColorProcessor_linear_to_sRGB; } if (iequals(inputColorSpace,"sRGB") && (iequals(outputColorSpace,"linear") || iequals(outputrole,"linear"))) { return new ColorProcessor_sRGB_to_linear; } if ((iequals(inputColorSpace,"linear") || iequals(inputrole,"linear")) && iequals(outputColorSpace,"Rec709")) { return new ColorProcessor_linear_to_Rec709; } if (iequals(inputColorSpace,"Rec709") && (iequals(outputColorSpace,"linear") || iequals(outputrole,"linear"))) { // No OCIO, or the OCIO config doesn't know linear->sRGB return new ColorProcessor_Rec709_to_linear; } if (iequals(inputColorSpace, outputColorSpace)) { // Color spaces are equal, and nothing found by OCIO return new ColorProcessor_pass_through; } #ifdef USE_OCIO if (p) { // If we found a procesor from OCIO, even if it was a NoOp, and we // still don't have a better idea, return it. return new ColorProcessor_OCIO(p); } #endif return NULL; // if we get this far, we've failed }
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); }
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(); }