5 sys.path.append( "/path/to/script" )
6 import create_aces_config as cac
7 acesReleaseCTLDir = "/path/to/github/checkout/releases/v0.7.1/transforms/ctl"
8 configDir = "/path/to/config/dir"
9 cac.createACESConfig(acesReleaseCTLDir, configDir, 1024, 33, True)
11 usage from command line, from the directory with 'create_aces_config.py'
12 python create_aces_config.py -a "/path/to/github/checkout/releases/v0.7.1/transforms/ctl" -c "/path/to/config/dir" --lutResolution1d 1024 --lutResolution3d 33 --keepTempImages
16 build instructions for osx for needed packages.
19 brew install -vd opencolorio --with-python
22 brew tap homebrew/science
25 brew install -vd libRaw
26 brew install -vd OpenCV
28 brew install -vd openimageio --with-python
34 # this time, 'ociolutimage' will build because openimageio is installed
35 brew uninstall -vd opencolorio
36 brew install -vd opencolorio --with-python
48 import OpenImageIO as oiio
49 import PyOpenColorIO as OCIO
56 def setConfigDefaultRoles( config,
68 if color_picking: config.setRole( OCIO.Constants.ROLE_COLOR_PICKING, color_picking )
69 if color_timing: config.setRole( OCIO.Constants.ROLE_COLOR_TIMING, color_timing )
70 if compositing_log: config.setRole( OCIO.Constants.ROLE_COMPOSITING_LOG, compositing_log )
71 if data: config.setRole( OCIO.Constants.ROLE_DATA, data )
72 if default: config.setRole( OCIO.Constants.ROLE_DEFAULT, default )
73 if matte_paint: config.setRole( OCIO.Constants.ROLE_MATTE_PAINT, matte_paint )
74 if reference: config.setRole( OCIO.Constants.ROLE_REFERENCE, reference )
75 if scene_linear: config.setRole( OCIO.Constants.ROLE_SCENE_LINEAR, scene_linear )
76 if texture_paint: config.setRole( OCIO.Constants.ROLE_TEXTURE_PAINT, texture_paint )
80 # Write config to disk
81 def writeConfig( config, configPath, sanityCheck=True ):
87 print "Configuration was not written due to a failed Sanity Check"
91 fileHandle = open( configPath, mode='w' )
92 fileHandle.write( config.serialize() )
96 # Functions used to generate LUTs using CTL transforms
98 def generate1dLUTImage(ramp1dPath, resolution=1024, minValue=0.0, maxValue=1.0):
99 #print( "Generate 1d LUT image - %s" % ramp1dPath)
102 format = os.path.splitext(ramp1dPath)[1]
103 ramp = oiio.ImageOutput.create(ramp1dPath)
106 spec = oiio.ImageSpec()
107 spec.set_format( oiio.FLOAT )
108 #spec.format.basetype = oiio.FLOAT
109 spec.width = resolution
113 ramp.open (ramp1dPath, spec, oiio.Create)
115 data = array.array("f", "\0" * spec.width * spec.height * spec.nchannels * 4)
116 for i in range(resolution):
117 value = float(i)/(resolution-1) * (maxValue - minValue) + minValue
118 data[i*spec.nchannels +0] = value
119 data[i*spec.nchannels +1] = value
120 data[i*spec.nchannels +2] = value
122 ramp.write_image(spec.format, data)
125 # Credit to Alex Fry for the original single channel version of the spi1d writer
126 def WriteSPI1D(filename, fromMin, fromMax, data, entries, channels):
127 f = file(filename,'w')
128 f.write("Version 1\n")
129 f.write("From %f %f\n" % (fromMin, fromMax))
130 f.write("Length %d\n" % entries)
131 f.write("Components %d\n" % (min(3, channels)) )
133 for i in range(0, entries):
135 for j in range(0, min(3, channels)):
136 entry = "%s %s" % (entry, data[i*channels + j])
137 f.write(" %s\n" % entry)
141 def generate1dLUTFromImage(ramp1dPath, outputPath=None, minValue=0.0, maxValue=1.0):
142 if outputPath == None:
143 outputPath = ramp1dPath + ".spi1d"
146 ramp = oiio.ImageInput.open( ramp1dPath )
150 type = spec.format.basetype
153 channels = spec.nchannels
156 # Force data to be read as float. The Python API doesn't handle half-floats well yet.
158 data = ramp.read_image(type)
160 WriteSPI1D(outputPath, minValue, maxValue, data, width, channels)
162 def generate3dLUTImage(ramp3dPath, resolution=32):
163 args = ["--generate", "--cubesize", str(resolution), "--maxwidth", str(resolution*resolution), "--output", ramp3dPath]
164 lutExtract = process.Process(description="generate a 3d LUT image", cmd="ociolutimage", args=args)
167 def generate3dLUTFromImage(ramp3dPath, outputPath=None, resolution=32):
168 if outputPath == None:
169 outputPath = ramp3dPath + ".spi3d"
171 args = ["--extract", "--cubesize", str(resolution), "--maxwidth", str(resolution*resolution), "--input", ramp3dPath, "--output", outputPath]
172 lutExtract = process.Process(description="extract a 3d LUT", cmd="ociolutimage", args=args)
175 def applyCTLToImage(inputImage,
181 acesCTLReleaseDir=None):
182 if len(ctlPaths) > 0:
184 if acesCTLReleaseDir != None:
185 ctlModulePath = "%s/utilities" % acesCTLReleaseDir
186 ctlenv['CTL_MODULE_PATH'] = ctlModulePath
190 args += ['-ctl', ctl]
192 #args += ["-verbose"]
193 args += ["-input_scale", str(inputScale)]
194 args += ["-output_scale", str(outputScale)]
195 args += ["-global_param1", "aIn", "1.0"]
196 for key, value in globalParams.iteritems():
197 args += ["-global_param1", key, str(value)]
199 args += [outputImage]
201 #print( "args : %s" % args )
203 ctlp = process.Process(description="a ctlrender process", cmd="ctlrender", args=args, env=ctlenv )
207 def convertBitDepth(inputImage, outputImage, depth):
208 args = [inputImage, "-d", depth, "-o", outputImage]
209 convert = process.Process(description="convert image bit depth", cmd="oiiotool", args=args)
212 def generate1dLUTFromCTL(lutPath,
215 identityLutBitDepth='half',
220 acesCTLReleaseDir=None,
226 lutPathBase = os.path.splitext(lutPath)[0]
228 identityLUTImageFloat = lutPathBase + ".float.tiff"
229 generate1dLUTImage(identityLUTImageFloat, lutResolution, minValue, maxValue)
231 if identityLutBitDepth != 'half':
232 identityLUTImage = lutPathBase + ".uint16.tiff"
233 convertBitDepth(identityLUTImageFloat, identityLUTImage, identityLutBitDepth)
235 identityLUTImage = identityLUTImageFloat
237 transformedLUTImage = lutPathBase + ".transformed.exr"
238 applyCTLToImage(identityLUTImage, transformedLUTImage, ctlPaths, inputScale, outputScale, globalParams, acesCTLReleaseDir)
240 generate1dLUTFromImage(transformedLUTImage, lutPath, minValue, maxValue)
243 os.remove(identityLUTImage)
244 if identityLUTImage != identityLUTImageFloat:
245 os.remove(identityLUTImageFloat)
246 os.remove(transformedLUTImage)
248 def correctLUTImage(transformedLUTImage, correctedLUTImage, lutResolution):
250 transformed = oiio.ImageInput.open( transformedLUTImage )
253 transformedSpec = transformed.spec()
254 type = transformedSpec.format.basetype
255 width = transformedSpec.width
256 height = transformedSpec.height
257 channels = transformedSpec.nchannels
260 if width != lutResolution * lutResolution or height != lutResolution:
261 print( "Correcting image as resolution is off. Found %d x %d. Expected %d x %d" % (width, height, lutResolution * lutResolution, lutResolution) )
262 print( "Generating %s" % correctedLUTImage)
265 # We're going to generate a new correct image
268 # Get the source data
269 # Force data to be read as float. The Python API doesn't handle half-floats well yet.
271 sourceData = transformed.read_image(type)
273 format = os.path.splitext(correctedLUTImage)[1]
274 correct = oiio.ImageOutput.create(correctedLUTImage)
277 correctSpec = oiio.ImageSpec()
278 correctSpec.set_format( oiio.FLOAT )
279 correctSpec.width = height
280 correctSpec.height = width
281 correctSpec.nchannels = channels
283 correct.open (correctedLUTImage, correctSpec, oiio.Create)
285 destData = array.array("f", "\0" * correctSpec.width * correctSpec.height * correctSpec.nchannels * 4)
286 for j in range(0, correctSpec.height):
287 for i in range(0, correctSpec.width):
288 for c in range(0, correctSpec.nchannels):
290 destData[correctSpec.nchannels*correctSpec.width*j + correctSpec.nchannels*i + c] = sourceData[correctSpec.nchannels*correctSpec.width*j + correctSpec.nchannels*i + c]
292 correct.write_image(correctSpec.format, destData)
295 #shutil.copy(transformedLUTImage, correctedLUTImage)
296 correctedLUTImage = transformedLUTImage
300 return correctedLUTImage
302 def generate3dLUTFromCTL(lutPath,
305 identityLutBitDepth='half',
310 acesCTLReleaseDir=None):
314 lutPathBase = os.path.splitext(lutPath)[0]
316 identityLUTImageFloat = lutPathBase + ".float.tiff"
317 generate3dLUTImage(identityLUTImageFloat, lutResolution)
320 if identityLutBitDepth != 'half':
321 identityLUTImage = lutPathBase + "." + identityLutBitDepth + ".tiff"
322 convertBitDepth(identityLUTImageFloat, identityLUTImage, identityLutBitDepth)
324 identityLUTImage = identityLUTImageFloat
326 transformedLUTImage = lutPathBase + ".transformed.exr"
327 applyCTLToImage(identityLUTImage, transformedLUTImage, ctlPaths, inputScale, outputScale, globalParams, acesCTLReleaseDir)
329 correctedLUTImage = lutPathBase + ".correct.exr"
330 correctedLUTImage = correctLUTImage(transformedLUTImage, correctedLUTImage, lutResolution)
332 generate3dLUTFromImage(correctedLUTImage, lutPath, lutResolution)
335 os.remove(identityLUTImage)
336 if identityLUTImage != identityLUTImageFloat:
337 os.remove(identityLUTImageFloat)
338 os.remove(transformedLUTImage)
339 if correctedLUTImage != transformedLUTImage:
340 os.remove(correctedLUTImage)
341 #os.remove(correctedLUTImage)
343 def generateOCIOTransform(transforms):
344 #print( "Generating transforms")
346 interpolationOptions = {
347 'linear':OCIO.Constants.INTERP_LINEAR,
348 'nearest':OCIO.Constants.INTERP_NEAREST,
349 'tetrahedral':OCIO.Constants.INTERP_TETRAHEDRAL
352 'forward':OCIO.Constants.TRANSFORM_DIR_FORWARD,
353 'inverse':OCIO.Constants.TRANSFORM_DIR_INVERSE
358 for transform in transforms:
359 if transform['type'] == 'lutFile':
361 ocioTransform = OCIO.FileTransform( src=transform['path'],
362 interpolation=interpolationOptions[transform['interpolation']],
363 direction=directionOptions[transform['direction']] )
365 ocioTransforms.append(ocioTransform)
366 elif transform['type'] == 'matrix':
367 ocioTransform = OCIO.MatrixTransform()
368 # MatrixTransform member variables can't be initialized directly. Each must be set individually
369 ocioTransform.setMatrix( transform['matrix'] )
371 if 'offset' in transform:
372 ocioTransform.setOffset( transform['offset'] )
373 if 'direction' in transform:
374 ocioTransform.setDirection( directionOptions[transform['direction']] )
376 ocioTransforms.append(ocioTransform)
377 elif transform['type'] == 'exponent':
378 ocioTransform = OCIO.ExponentTransform()
379 ocioTransform.setValue( transform['value'] )
381 ocioTransforms.append(ocioTransform)
382 elif transform['type'] == 'log':
383 ocioTransform = OCIO.LogTransform(base=transform['base'],
384 direction=directionOptions[transform['direction']])
386 ocioTransforms.append(ocioTransform)
388 print( "Ignoring unknown transform type : %s" % transform['type'] )
390 # Build a group transform if necessary
391 if len(ocioTransforms) > 1:
392 transformG = OCIO.GroupTransform()
393 for transform in ocioTransforms:
394 transformG.push_back( transform )
395 transform = transformG
397 # Or take the first transform from the list
399 transform = ocioTransforms[0]
403 def createConfig(configData, nuke=False):
405 config = OCIO.Config()
408 # Set config wide values
410 config.setDescription( "An ACES config generated from python" )
411 config.setSearchPath( "luts" )
414 # Define the reference color space
416 referenceData = configData['referenceColorSpace']
417 print( "Adding the reference color space : %s" % referenceData.name)
419 # Create a color space
420 reference = OCIO.ColorSpace( name=referenceData.name,
421 bitDepth=referenceData.bitDepth,
422 description=referenceData.description,
423 equalityGroup=referenceData.equalityGroup,
424 family=referenceData.family,
425 isData=referenceData.isData,
426 allocation=referenceData.allocationType,
427 allocationVars=referenceData.allocationVars )
430 config.addColorSpace( reference )
433 # Create the rest of the color spaces
435 #sortedColorspaces = sorted(configData['colorSpaces'], key=lambda x: x.name)
436 #print( sortedColorspaces )
437 #for colorspace in sortedColorspaces:
438 for colorspace in sorted(configData['colorSpaces']):
439 print( "Creating new color space : %s" % colorspace.name)
441 ocioColorspace = OCIO.ColorSpace( name=colorspace.name,
442 bitDepth=colorspace.bitDepth,
443 description=colorspace.description,
444 equalityGroup=colorspace.equalityGroup,
445 family=colorspace.family,
446 isData=colorspace.isData,
447 allocation=colorspace.allocationType,
448 allocationVars=colorspace.allocationVars )
450 if colorspace.toReferenceTransforms != []:
451 print( "Generating To-Reference transforms")
452 ocioTransform = generateOCIOTransform(colorspace.toReferenceTransforms)
453 ocioColorspace.setTransform( ocioTransform, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE )
455 if colorspace.fromReferenceTransforms != []:
456 print( "Generating From-Reference transforms")
457 ocioTransform = generateOCIOTransform(colorspace.fromReferenceTransforms)
458 ocioColorspace.setTransform( ocioTransform, OCIO.Constants.COLORSPACE_DIR_FROM_REFERENCE )
460 config.addColorSpace(ocioColorspace)
465 # Define the views and displays
470 # Generic display and view setup
472 for display, viewList in configData['displays'].iteritems():
473 for viewName, colorspace in viewList.iteritems():
474 config.addDisplay( display, viewName, colorspace.name )
475 if not (viewName in views):
476 views.append(viewName)
477 displays.append(display)
478 # A Nuke specific set of views and displays
481 # A few names: Output Transform, ACES, ACEScc, are hard-coded here. Would be better to automate
484 for display, viewList in configData['displays'].iteritems():
485 for viewName, colorspace in viewList.iteritems():
486 if( viewName == 'Output Transform'):
488 config.addDisplay( display, viewName, colorspace.name )
489 if not (viewName in views):
490 views.append(viewName)
491 displays.append(display)
493 config.addDisplay( 'linear', 'View', 'ACES2065-1' )
494 displays.append('linear')
495 config.addDisplay( 'log', 'View', 'ACEScc' )
496 displays.append('log')
498 # Set active displays and views
499 config.setActiveDisplays( ','.join(sorted(displays)) )
500 config.setActiveViews( ','.join(views) )
503 # Need to generalize this at some point
507 setConfigDefaultRoles( config,
508 color_picking=reference.getName(),
509 color_timing=reference.getName(),
510 compositing_log=reference.getName(),
511 data=reference.getName(),
512 default=reference.getName(),
513 matte_paint=reference.getName(),
514 reference=reference.getName(),
515 scene_linear=reference.getName(),
516 texture_paint=reference.getName() )
518 # Check to make sure we didn't screw something up
524 # Functions to generate color space definitions and LUTs for transforms for a specific ACES release
527 "A container for data needed to define an OCIO 'Color Space' "
532 bitDepth=OCIO.Constants.BIT_DEPTH_F32,
536 toReferenceTransforms=[],
537 fromReferenceTransforms=[],
538 allocationType=OCIO.Constants.ALLOCATION_UNIFORM,
539 allocationVars=[0.0, 1.0]):
540 "Initialize the standard class variables"
542 self.bitDepth=bitDepth
543 self.description = description
544 self.equalityGroup=equalityGroup
547 self.toReferenceTransforms=toReferenceTransforms
548 self.fromReferenceTransforms=fromReferenceTransforms
549 self.allocationType=allocationType
550 self.allocationVars=allocationVars
552 # Create a 4x4 matrix (list) based on a 3x3 matrix (list) input
553 def mat44FromMat33(mat33):
554 return [mat33[0], mat33[1], mat33[2], 0.0,
555 mat33[3], mat33[4], mat33[5], 0.0,
556 mat33[6], mat33[7], mat33[8], 0.0,
560 # Output is a list of colorspaces and transforms that convert between those
561 # colorspaces and reference color space, ACES
562 def generateLUTs(odtInfo, lmtInfo, shaperName, acesCTLReleaseDir, lutDir, lutResolution1d=4096, lutResolution3d=64, cleanup=True):
563 print( "generateLUTs - begin" )
567 # Define the reference color space
569 ACES = ColorSpace('ACES2065-1')
570 ACES.description = "The Academy Color Encoding System reference color space"
571 ACES.equalityGroup = ''
574 ACES.allocationType=OCIO.Constants.ALLOCATION_LG2
575 ACES.allocationVars=[-15, 6]
577 configData['referenceColorSpace'] = ACES
580 # Define the displays
582 configData['displays'] = {}
585 # Define the other color spaces
587 configData['colorSpaces'] = []
589 # Matrix converting ACES AP1 primaries to AP0
590 acesAP1toAP0 = [ 0.6954522414, 0.1406786965, 0.1638690622,
591 0.0447945634, 0.8596711185, 0.0955343182,
592 -0.0055258826, 0.0040252103, 1.0015006723]
594 # Matrix converting ACES AP0 primaries to XYZ
595 acesAP0toXYZ = [0.9525523959, 0.0000000000, 0.0000936786,
596 0.3439664498, 0.7281660966, -0.0721325464,
597 0.0000000000, 0.0000000000, 1.0088251844]
602 def createACEScc(name='ACEScc', minValue=0.0, maxValue=1.0, inputScale=1.0):
603 cs = ColorSpace(name)
604 cs.description = "The %s color space" % name
605 cs.equalityGroup = ''
610 '%s/ACEScc/ACEScsc.ACEScc_to_ACES.a1.0.0.ctl' % acesCTLReleaseDir,
611 # This transform gets back to the AP1 primaries
612 # Useful as the 1d LUT is only covering the transfer function
613 # The primaries switch is covered by the matrix below
614 '%s/ACEScg/ACEScsc.ACES_to_ACEScg.a1.0.0.ctl' % acesCTLReleaseDir
616 lut = "%s_to_ACES.spi1d" % name
617 generate1dLUTFromCTL( lutDir + "/" + lut,
629 cs.toReferenceTransforms = []
630 cs.toReferenceTransforms.append( {
633 'interpolation':'linear',
634 'direction':'forward'
637 # AP1 primaries to AP0 primaries
638 cs.toReferenceTransforms.append( {
640 'matrix':mat44FromMat33(acesAP1toAP0),
641 'direction':'forward'
644 cs.fromReferenceTransforms = []
647 ACEScc = createACEScc()
648 configData['colorSpaces'].append(ACEScc)
653 def createACESProxy(name='ACESproxy'):
654 cs = ColorSpace(name)
655 cs.description = "The %s color space" % name
656 cs.equalityGroup = ''
661 '%s/ACESproxy/ACEScsc.ACESproxy10i_to_ACES.a1.0.0.ctl' % acesCTLReleaseDir,
662 # This transform gets back to the AP1 primaries
663 # Useful as the 1d LUT is only covering the transfer function
664 # The primaries switch is covered by the matrix below
665 '%s/ACEScg/ACEScsc.ACES_to_ACEScg.a1.0.0.ctl' % acesCTLReleaseDir
667 lut = "%s_to_aces.spi1d" % name
668 generate1dLUTFromCTL( lutDir + "/" + lut,
678 cs.toReferenceTransforms = []
679 cs.toReferenceTransforms.append( {
682 'interpolation':'linear',
683 'direction':'forward'
686 # AP1 primaries to AP0 primaries
687 cs.toReferenceTransforms.append( {
689 'matrix':mat44FromMat33(acesAP1toAP0),
690 'direction':'forward'
694 cs.fromReferenceTransforms = []
697 ACESproxy = createACESProxy()
698 configData['colorSpaces'].append(ACESproxy)
703 def createACEScg(name='ACEScg'):
704 cs = ColorSpace(name)
705 cs.description = "The %s color space" % name
706 cs.equalityGroup = ''
710 cs.toReferenceTransforms = []
712 # AP1 primaries to AP0 primaries
713 cs.toReferenceTransforms.append( {
715 'matrix':mat44FromMat33(acesAP1toAP0),
716 'direction':'forward'
719 cs.fromReferenceTransforms = []
722 ACEScg = createACEScg()
723 configData['colorSpaces'].append(ACEScg)
728 def createADX(bitdepth=10, name='ADX'):
729 name = "%s%s" % (name, bitdepth)
730 cs = ColorSpace(name)
731 cs.description = "%s color space - used for film scans" % name
732 cs.equalityGroup = ''
737 cs.bitDepth = bitDepth=OCIO.Constants.BIT_DEPTH_UINT10
738 adx_to_cdd = [1023.0/500.0, 0.0, 0.0, 0.0,
739 0.0, 1023.0/500.0, 0.0, 0.0,
740 0.0, 0.0, 1023.0/500.0, 0.0,
742 offset = [-95.0/500.0, -95.0/500.0, -95.0/500.0, 0.0]
744 cs.bitDepth = bitDepth=OCIO.Constants.BIT_DEPTH_UINT16
745 adx_to_cdd = [65535.0/8000.0, 0.0, 0.0, 0.0,
746 0.0, 65535.0/8000.0, 0.0, 0.0,
747 0.0, 0.0, 65535.0/8000.0, 0.0,
749 offset = [-1520.0/8000.0, -1520.0/8000.0, -1520.0/8000.0, 0.0]
751 cs.toReferenceTransforms = []
753 # Convert from ADX to Channel-Dependent Density
754 cs.toReferenceTransforms.append( {
758 'direction':'forward'
761 # Convert from Channel-Dependent Density to Channel-Independent Density
762 cs.toReferenceTransforms.append( {
764 'matrix':[0.75573, 0.22197, 0.02230, 0,
765 0.05901, 0.96928, -0.02829, 0,
766 0.16134, 0.07406, 0.76460, 0,
768 'direction':'forward'
771 # Copied from Alex Fry's adx_cid_to_rle.py
772 def createCIDtoRLELUT():
773 def interpolate1D(x, xp, fp):
774 return numpy.interp(x, xp, fp)
776 LUT_1D_xp = [-0.190000000000000,
788 LUT_1D_fp = [-6.000000000000000,
800 REF_PT = (7120.0 - 1520.0) / 8000.0 * (100.0 / 55.0) - math.log(0.18, 10.0)
804 return interpolate1D(x, LUT_1D_xp, LUT_1D_fp)
805 return (100.0 / 55.0) * x - REF_PT
807 def Fit(value, fromMin, fromMax, toMin, toMax):
808 if fromMin == fromMax:
809 raise ValueError("fromMin == fromMax")
810 return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin
815 for i in xrange(NUM_SAMPLES):
816 x = i/(NUM_SAMPLES-1.0)
817 x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
818 data.append(cid_to_rle(x))
820 lut = 'ADX_CID_to_RLE.spi1d'
821 WriteSPI1D(lutDir + "/" + lut, RANGE[0], RANGE[1], data, NUM_SAMPLES, 1)
825 # Convert Channel Independent Density values to Relative Log Exposure values
826 lut = createCIDtoRLELUT()
827 cs.toReferenceTransforms.append( {
830 'interpolation':'linear',
831 'direction':'forward'
834 # Convert Relative Log Exposure values to Relative Exposure values
835 cs.toReferenceTransforms.append( {
838 'direction':'inverse'
841 # Convert Relative Exposure values to ACES values
842 cs.toReferenceTransforms.append( {
844 'matrix':[0.72286, 0.12630, 0.15084, 0,
845 0.11923, 0.76418, 0.11659, 0,
846 0.01427, 0.08213, 0.90359, 0,
848 'direction':'forward'
851 cs.fromReferenceTransforms = []
854 ADX10 = createADX(bitdepth=10)
855 configData['colorSpaces'].append(ADX10)
857 ADX16 = createADX(bitdepth=16)
858 configData['colorSpaces'].append(ADX16)
864 def createREDlogFilm(gamut, transferFunction, name='REDlogFilm'):
865 name = "%s - %s" % (transferFunction, gamut)
866 if transferFunction == "":
867 name = "Linear - %s" % gamut
869 name = "%s" % transferFunction
871 cs = ColorSpace(name)
872 cs.description = name
873 cs.equalityGroup = ''
877 def cineonToLinear(codeValue):
881 codeValueToDensity = 0.002
883 blackLinear = pow(10.0, (blackPoint - whitePoint) * (codeValueToDensity / nGamma))
884 codeLinear = pow(10.0, (codeValue - whitePoint) * (codeValueToDensity / nGamma))
886 return (codeLinear - blackLinear)/(1.0 - blackLinear)
888 cs.toReferenceTransforms = []
890 if transferFunction == 'REDlogFilm':
891 data = array.array('f', "\0" * lutResolution1d * 4)
892 for c in range(lutResolution1d):
893 data[c] = cineonToLinear(1023.0*c/(lutResolution1d-1))
895 lut = "CineonLog_to_linear.spi1d"
896 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
898 cs.toReferenceTransforms.append( {
901 'interpolation':'linear',
902 'direction':'forward'
905 if gamut == 'DRAGONcolor':
906 cs.toReferenceTransforms.append( {
908 'matrix':mat44FromMat33([0.532279, 0.376648, 0.091073,
909 0.046344, 0.974513, -0.020860,
910 -0.053976, -0.000320, 1.054267]),
911 'direction':'forward'
913 elif gamut == 'DRAGONcolor2':
914 cs.toReferenceTransforms.append( {
916 'matrix':mat44FromMat33([0.468452, 0.331484, 0.200064,
917 0.040787, 0.857658, 0.101553,
918 -0.047504, -0.000282, 1.047756]),
919 'direction':'forward'
921 elif gamut == 'REDcolor2':
922 cs.toReferenceTransforms.append( {
924 'matrix':mat44FromMat33([0.480997, 0.402289, 0.116714,
925 -0.004938, 1.000154, 0.004781,
926 -0.105257, 0.025320, 1.079907]),
927 'direction':'forward'
929 elif gamut == 'REDcolor3':
930 cs.toReferenceTransforms.append( {
932 'matrix':mat44FromMat33([0.512136, 0.360370, 0.127494,
933 0.070377, 0.903884, 0.025737,
934 -0.020824, 0.017671, 1.003123]),
935 'direction':'forward'
937 elif gamut == 'REDcolor4':
938 cs.toReferenceTransforms.append( {
940 'matrix':mat44FromMat33([0.474202, 0.333677, 0.192121,
941 0.065164, 0.836932, 0.097901,
942 -0.019281, 0.016362, 1.002889]),
943 'direction':'forward'
946 cs.fromReferenceTransforms = []
950 REDlogFilmDRAGON = createREDlogFilm("DRAGONcolor", "REDlogFilm", name="REDlogFilm")
951 configData['colorSpaces'].append(REDlogFilmDRAGON)
953 REDlogFilmDRAGON2 = createREDlogFilm("DRAGONcolor2", "REDlogFilm", name="REDlogFilm")
954 configData['colorSpaces'].append(REDlogFilmDRAGON2)
956 REDlogFilmREDcolor2 = createREDlogFilm("REDcolor2", "REDlogFilm", name="REDlogFilm")
957 configData['colorSpaces'].append(REDlogFilmREDcolor2)
959 REDlogFilmREDcolor3 = createREDlogFilm("REDcolor3", "REDlogFilm", name="REDlogFilm")
960 configData['colorSpaces'].append(REDlogFilmREDcolor3)
962 REDlogFilmREDcolor4 = createREDlogFilm("REDcolor4", "REDlogFilm", name="REDlogFilm")
963 configData['colorSpaces'].append(REDlogFilmREDcolor4)
966 REDlogFilmDRAGON = createREDlogFilm("", "REDlogFilm", name="REDlogFilm")
967 configData['colorSpaces'].append(REDlogFilmDRAGON)
970 REDlogFilmDRAGON = createREDlogFilm("DRAGONcolor", "", name="REDlogFilm")
971 configData['colorSpaces'].append(REDlogFilmDRAGON)
973 REDlogFilmDRAGON2 = createREDlogFilm("DRAGONcolor2", "", name="REDlogFilm")
974 configData['colorSpaces'].append(REDlogFilmDRAGON2)
976 REDlogFilmREDcolor2 = createREDlogFilm("REDcolor2", "", name="REDlogFilm")
977 configData['colorSpaces'].append(REDlogFilmREDcolor2)
979 REDlogFilmREDcolor3 = createREDlogFilm("REDcolor3", "", name="REDlogFilm")
980 configData['colorSpaces'].append(REDlogFilmREDcolor3)
982 REDlogFilmREDcolor4 = createREDlogFilm("REDcolor4", "", name="REDlogFilm")
983 configData['colorSpaces'].append(REDlogFilmREDcolor4)
988 def createCanonLog(gamut, transferFunction, name='Canon-Log'):
989 name = "%s - %s" % (transferFunction, gamut)
990 if transferFunction == "":
991 name = "Linear - %s" % gamut
993 name = "%s" % transferFunction
995 cs = ColorSpace(name)
996 cs.description = name
997 cs.equalityGroup = ''
1001 def legalToFull(codeValue):
1002 return (codeValue - 64.0)/(940.0 - 64.0)
1004 def canonLogToLinear(codeValue):
1005 # log = fullToLegal(c1 * log10(c2*linear + 1) + c3)
1006 # linear = (pow(10, (legalToFul(log) - c3)/c1) - 1)/c2
1011 linear = (pow(10.0, (legalToFull(codeValue) - c3)/c1) -1.0)/c2
1012 linear = 0.9 * linear
1013 #print( codeValue, linear )
1016 cs.toReferenceTransforms = []
1018 if transferFunction == "Canon-Log":
1019 data = array.array('f', "\0" * lutResolution1d * 4)
1020 for c in range(lutResolution1d):
1021 data[c] = canonLogToLinear(1023.0*c/(lutResolution1d-1))
1023 lut = "%s_to_linear.spi1d" % transferFunction
1024 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
1026 cs.toReferenceTransforms.append( {
1029 'interpolation':'linear',
1030 'direction':'forward'
1033 if gamut == 'Rec. 709 Daylight':
1034 cs.toReferenceTransforms.append( {
1036 'matrix':[0.561538969, 0.402060105, 0.036400926, 0.0,
1037 0.092739623, 0.924121198, -0.016860821, 0.0,
1038 0.084812961, 0.006373835, 0.908813204, 0.0,
1040 'direction':'forward'
1042 elif gamut == 'Rec. 709 Tungsten':
1043 cs.toReferenceTransforms.append( {
1045 'matrix':[0.566996399, 0.365079418, 0.067924183, 0.0,
1046 0.070901044, 0.880331008, 0.048767948, 0.0,
1047 0.073013542, -0.066540862, 0.99352732, 0.0,
1049 'direction':'forward'
1051 elif gamut == 'DCI-P3 Daylight':
1052 cs.toReferenceTransforms.append( {
1054 'matrix':[0.607160575, 0.299507286, 0.093332140, 0.0,
1055 0.004968120, 1.050982224, -0.055950343, 0.0,
1056 -0.007839939, 0.000809127, 1.007030813, 0.0,
1058 'direction':'forward'
1060 elif gamut == 'DCI-P3 Tungsten':
1061 cs.toReferenceTransforms.append( {
1063 'matrix':[0.650279125, 0.253880169, 0.095840706, 0.0,
1064 -0.026137986, 1.017900530, 0.008237456, 0.0,
1065 0.007757558, -0.063081669, 1.055324110, 0.0,
1067 'direction':'forward'
1069 elif gamut == 'Cinema Gamut Daylight':
1070 cs.toReferenceTransforms.append( {
1072 'matrix':[0.763064455, 0.149021161, 0.087914384, 0.0,
1073 0.003657457, 1.10696038, -0.110617837, 0.0,
1074 -0.009407794,-0.218383305, 1.227791099, 0.0,
1076 'direction':'forward'
1078 elif gamut == 'Cinema Gamut Tungsten':
1079 cs.toReferenceTransforms.append( {
1081 'matrix':[0.817416293, 0.090755698, 0.091828009, 0.0,
1082 -0.035361374, 1.065690585, -0.030329211, 0.0,
1083 0.010390366, -0.299271107, 1.288880741, 0.0,
1085 'direction':'forward'
1088 cs.fromReferenceTransforms = []
1092 CanonLog1 = createCanonLog("Rec. 709 Daylight", "Canon-Log", name="Canon-Log")
1093 configData['colorSpaces'].append(CanonLog1)
1095 CanonLog2 = createCanonLog("Rec. 709 Tungsten", "Canon-Log", name="Canon-Log")
1096 configData['colorSpaces'].append(CanonLog2)
1098 CanonLog3 = createCanonLog("DCI-P3 Daylight", "Canon-Log", name="Canon-Log")
1099 configData['colorSpaces'].append(CanonLog3)
1101 CanonLog4 = createCanonLog("DCI-P3 Tungsten", "Canon-Log", name="Canon-Log")
1102 configData['colorSpaces'].append(CanonLog4)
1104 CanonLog5 = createCanonLog("Cinema Gamut Daylight", "Canon-Log", name="Canon-Log")
1105 configData['colorSpaces'].append(CanonLog5)
1107 CanonLog6 = createCanonLog("Cinema Gamut Tungsten", "Canon-Log", name="Canon-Log")
1108 configData['colorSpaces'].append(CanonLog6)
1110 # Linearization only
1111 CanonLog7 = createCanonLog('', "Canon-Log", name="Canon-Log")
1112 configData['colorSpaces'].append(CanonLog7)
1115 CanonLog8 = createCanonLog("Rec. 709 Daylight", "", name="Canon-Log")
1116 configData['colorSpaces'].append(CanonLog8)
1118 CanonLog9 = createCanonLog("Rec. 709 Tungsten", "", name="Canon-Log")
1119 configData['colorSpaces'].append(CanonLog9)
1121 CanonLog10 = createCanonLog("DCI-P3 Daylight", "", name="Canon-Log")
1122 configData['colorSpaces'].append(CanonLog10)
1124 CanonLog11 = createCanonLog("DCI-P3 Tungsten", "", name="Canon-Log")
1125 configData['colorSpaces'].append(CanonLog11)
1127 CanonLog12 = createCanonLog("Cinema Gamut Daylight", "", name="Canon-Log")
1128 configData['colorSpaces'].append(CanonLog12)
1130 CanonLog13 = createCanonLog("Cinema Gamut Tungsten", "", name="Canon-Log")
1131 configData['colorSpaces'].append(CanonLog13)
1136 def createSlog(gamut, transferFunction, name='S-Log3'):
1137 name = "%s - %s" % (transferFunction, gamut)
1138 if transferFunction == "":
1139 name = "Linear - %s" % gamut
1141 name = "%s" % transferFunction
1143 cs = ColorSpace(name)
1144 cs.description = name
1145 cs.equalityGroup = ''
1149 def sLog1ToLinear(SLog):
1155 lin = ( pow(10., ( ( ( SLog - b) / ( w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) * 0.9
1157 lin = ( ( ( SLog - b) / ( w - b) - 0.030001222851889303) / 5.) * 0.9
1160 def sLog2ToLinear(SLog):
1166 lin = ( 219. * ( pow(10., ( ( ( SLog - b) / ( w - b) - 0.616596 - 0.03) / 0.432699)) - 0.037584) / 155.) * 0.9
1168 lin = ( ( ( SLog - b) / ( w - b) - 0.030001222851889303) / 3.53881278538813) * 0.9
1171 def sLog3ToLinear(codeValue):
1172 if codeValue >= (171.2102946929):
1173 linear = pow(10.0, ((codeValue - 420.0) / 261.5)) * (0.18 + 0.01) - 0.01
1175 linear = (codeValue - 95.0)*0.01125000/(171.2102946929 - 95.0)
1176 #print( codeValue, linear )
1179 cs.toReferenceTransforms = []
1181 if transferFunction == "S-Log1":
1182 data = array.array('f', "\0" * lutResolution1d * 4)
1183 for c in range(lutResolution1d):
1184 data[c] = sLog1ToLinear(1023.0*c/(lutResolution1d-1))
1186 lut = "%s_to_linear.spi1d" % transferFunction
1187 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
1189 #print( "Writing %s" % lut)
1191 cs.toReferenceTransforms.append( {
1194 'interpolation':'linear',
1195 'direction':'forward'
1197 elif transferFunction == "S-Log2":
1198 data = array.array('f', "\0" * lutResolution1d * 4)
1199 for c in range(lutResolution1d):
1200 data[c] = sLog2ToLinear(1023.0*c/(lutResolution1d-1))
1202 lut = "%s_to_linear.spi1d" % transferFunction
1203 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
1205 #print( "Writing %s" % lut)
1207 cs.toReferenceTransforms.append( {
1210 'interpolation':'linear',
1211 'direction':'forward'
1213 elif transferFunction == "S-Log3":
1214 data = array.array('f', "\0" * lutResolution1d * 4)
1215 for c in range(lutResolution1d):
1216 data[c] = sLog3ToLinear(1023.0*c/(lutResolution1d-1))
1218 lut = "%s_to_linear.spi1d" % transferFunction
1219 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
1221 #print( "Writing %s" % lut)
1223 cs.toReferenceTransforms.append( {
1226 'interpolation':'linear',
1227 'direction':'forward'
1230 if gamut == 'S-Gamut':
1231 cs.toReferenceTransforms.append( {
1233 'matrix':mat44FromMat33([0.754338638, 0.133697046, 0.111968437,
1234 0.021198141, 1.005410934, -0.026610548,
1235 -0.009756991, 0.004508563, 1.005253201]),
1236 'direction':'forward'
1238 elif gamut == 'S-Gamut Daylight':
1239 cs.toReferenceTransforms.append( {
1241 'matrix':mat44FromMat33([0.8764457030, 0.0145411681, 0.1090131290,
1242 0.0774075345, 0.9529571767, -0.0303647111,
1243 0.0573564351, -0.1151066335, 1.0577501984]),
1244 'direction':'forward'
1246 elif gamut == 'S-Gamut Tungsten':
1247 cs.toReferenceTransforms.append( {
1249 'matrix':mat44FromMat33([1.0110238740, -0.1362526051, 0.1252287310,
1250 0.1011994504, 0.9562196265, -0.0574190769,
1251 0.0600766530, -0.1010185315, 1.0409418785]),
1252 'direction':'forward'
1254 elif gamut == 'S-Gamut3.Cine':
1255 cs.toReferenceTransforms.append( {
1257 'matrix':mat44FromMat33([0.6387886672, 0.2723514337, 0.0888598992,
1258 -0.0039159061, 1.0880732308, -0.0841573249,
1259 -0.0299072021, -0.0264325799, 1.0563397820]),
1260 'direction':'forward'
1262 elif gamut == 'S-Gamut3':
1263 cs.toReferenceTransforms.append( {
1265 'matrix':mat44FromMat33([0.7529825954, 0.1433702162, 0.1036471884,
1266 0.0217076974, 1.0153188355, -0.0370265329,
1267 -0.0094160528, 0.0033704179, 1.0060456349]),
1268 'direction':'forward'
1271 cs.fromReferenceTransforms = []
1275 SLog1SGamut = createSlog("S-Gamut", "S-Log1", name="S-Log")
1276 configData['colorSpaces'].append(SLog1SGamut)
1279 SLog2SGamut = createSlog("S-Gamut", "S-Log2", name="S-Log2")
1280 configData['colorSpaces'].append(SLog2SGamut)
1282 SLog2SGamutDaylight = createSlog("S-Gamut Daylight", "S-Log2", name="S-Log2")
1283 configData['colorSpaces'].append(SLog2SGamutDaylight)
1285 SLog2SGamutTungsten = createSlog("S-Gamut Tungsten", "S-Log2", name="S-Log2")
1286 configData['colorSpaces'].append(SLog2SGamutTungsten)
1289 SLog3SGamut3Cine = createSlog("S-Gamut3.Cine", "S-Log3", name="S-Log3")
1290 configData['colorSpaces'].append(SLog3SGamut3Cine)
1292 SLog3SGamut3 = createSlog("S-Gamut3", "S-Log3", name="S-Log3")
1293 configData['colorSpaces'].append(SLog3SGamut3)
1295 # Linearization only
1296 SLog1 = createSlog("", "S-Log1", name="S-Log")
1297 configData['colorSpaces'].append(SLog1)
1299 SLog2 = createSlog("", "S-Log2", name="S-Log2")
1300 configData['colorSpaces'].append(SLog2)
1302 SLog3 = createSlog("", "S-Log3", name="S-Log3")
1303 configData['colorSpaces'].append(SLog3)
1306 SGamut = createSlog("S-Gamut", "", name="S-Log")
1307 configData['colorSpaces'].append(SGamut)
1309 SGamutDaylight = createSlog("S-Gamut Daylight", "", name="S-Log2")
1310 configData['colorSpaces'].append(SGamutDaylight)
1312 SGamutTungsten = createSlog("S-Gamut Tungsten", "", name="S-Log2")
1313 configData['colorSpaces'].append(SGamutTungsten)
1315 SGamut3Cine = createSlog("S-Gamut3.Cine", "", name="S-Log3")
1316 configData['colorSpaces'].append(SGamut3Cine)
1318 SGamut3 = createSlog("S-Gamut3", "", name="S-Log3")
1319 configData['colorSpaces'].append(SGamut3)
1324 def createLogC(gamut, transferFunction, exposureIndex, name='LogC'):
1325 name = "%s (EI%s) - %s" % (transferFunction, exposureIndex, gamut)
1326 if transferFunction == "":
1327 name = "Linear - %s" % gamut
1329 name = "%s (EI%s)" % (transferFunction, exposureIndex)
1331 cs = ColorSpace(name)
1332 cs.description = name
1333 cs.equalityGroup = ''
1338 IDT_maker_version = "0.08"
1341 blackSignal = 0.003907
1342 midGraySignal = 0.01
1343 encodingGain = 0.256598
1344 encodingOffset = 0.391007
1347 return (math.log(EI/nominalEI)/math.log(2) * (0.89 - 1) / 3 + 1) * encodingGain
1349 def LogCInverseParametersForEI(EI) :
1351 slope = 1.0 / (cut * math.log(10))
1352 offset = math.log10(cut) - slope * cut
1353 gain = EI / nominalEI
1354 gray = midGraySignal / gain
1355 # The higher the EI, the lower the gamma
1356 encGain = gainForEI(EI)
1357 encOffset = encodingOffset
1358 for i in range(0,3) :
1359 nz = ((95.0 / 1023.0 - encOffset) / encGain - offset) / slope
1360 encOffset = encodingOffset - math.log10(1 + nz) * encGain
1361 # Calculate some intermediate values
1363 b = nz - blackSignal / gray
1364 e = slope * a * encGain
1365 f = encGain * (slope * b + offset) + encOffset
1366 # Manipulations so we can return relative exposure
1375 'cut' : (cut - b) / a,
1381 def logCtoLinear(codeValue, exposureIndex):
1382 p = LogCInverseParametersForEI(exposureIndex)
1383 breakpoint = p['e'] * p['cut'] + p['f']
1384 if (codeValue > breakpoint):
1385 linear = (pow(10,(codeValue/1023.0 - p['d']) / p['c']) - p['b']) / p['a']
1387 linear = (codeValue/1023.0 - p['f']) / p['e']
1389 #print( codeValue, linear )
1393 cs.toReferenceTransforms = []
1395 if transferFunction == "V3 LogC":
1396 data = array.array('f', "\0" * lutResolution1d * 4)
1397 for c in range(lutResolution1d):
1398 data[c] = logCtoLinear(1023.0*c/(lutResolution1d-1), int(exposureIndex))
1400 lut = "%s_to_linear.spi1d" % ("%s_%s" % (transferFunction, exposureIndex))
1401 WriteSPI1D(lutDir + "/" + lut, 0.0, 1.0, data, lutResolution1d, 1)
1403 #print( "Writing %s" % lut)
1404 cs.toReferenceTransforms.append( {
1407 'interpolation':'linear',
1408 'direction':'forward'
1411 if gamut == 'Wide Gamut':
1412 cs.toReferenceTransforms.append( {
1414 'matrix':mat44FromMat33([0.680206, 0.236137, 0.083658,
1415 0.085415, 1.017471, -0.102886,
1416 0.002057, -0.062563, 1.060506]),
1417 'direction':'forward'
1420 cs.fromReferenceTransforms = []
1423 transferFunction = "V3 LogC"
1424 gamut = "Wide Gamut"
1425 #EIs = [160.0, 200.0, 250.0, 320.0, 400.0, 500.0, 640.0, 800.0, 1000.0, 1280.0, 1600.0, 2000.0, 2560.0, 3200.0]
1426 EIs = [160, 200, 250, 320, 400, 500, 640, 800, 1000, 1280, 1600, 2000, 2560, 3200]
1431 LogCEIfull = createLogC(gamut, transferFunction, EI, name="LogC")
1432 configData['colorSpaces'].append(LogCEIfull)
1434 # Linearization only
1436 LogCEIlinearization = createLogC("", transferFunction, EI, name="LogC")
1437 configData['colorSpaces'].append(LogCEIlinearization)
1440 LogCEIprimaries = createLogC(gamut, "", defaultEI, name="LogC")
1441 configData['colorSpaces'].append(LogCEIprimaries)
1444 # Generic log transform
1446 def createGenericLog(name='log',
1453 lutResolution1d=lutResolution1d):
1454 cs = ColorSpace(name)
1455 cs.description = "The %s color space" % name
1456 cs.equalityGroup = name
1457 cs.family = 'Utility'
1461 #'%s/logShaper/logShaper16i_to_aces_param.ctl' % acesCTLReleaseDir
1462 '%s/utilities/ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl' % acesCTLReleaseDir
1464 lut = "%s_to_aces.spi1d" % name
1466 generate1dLUTFromCTL( lutDir + "/" + lut,
1473 'middleGrey' : middleGrey,
1474 'minExposure' : minExposure,
1475 'maxExposure' : maxExposure
1482 cs.toReferenceTransforms = []
1483 cs.toReferenceTransforms.append( {
1486 'interpolation':'linear',
1487 'direction':'forward'
1490 cs.fromReferenceTransforms = []
1496 def createACESLMT(lmtName,
1499 lutResolution1d=1024,
1502 cs = ColorSpace("%s" % lmtName)
1503 cs.description = "The ACES Look Transform: %s" % lmtName
1504 cs.equalityGroup = ''
1509 pprint.pprint( lmtValues )
1512 # Generate the shaper transform
1514 (shaperName, shaperToACESCTL, shaperFromACESCTL, shaperInputScale, shaperParams) = shaperInfo
1516 shaperLut = "%s_to_aces.spi1d" % shaperName
1517 if( not os.path.exists( lutDir + "/" + shaperLut ) ):
1519 shaperToACESCTL % acesCTLReleaseDir
1521 generate1dLUTFromCTL( lutDir + "/" + shaperLut,
1525 1.0/shaperInputScale,
1531 shaperOCIOTransform = {
1534 'interpolation':'linear',
1535 'direction':'inverse'
1539 # Generate the forward transform
1541 cs.fromReferenceTransforms = []
1543 if 'transformCTL' in lmtValues:
1545 shaperToACESCTL % acesCTLReleaseDir,
1546 '%s/%s' % (acesCTLReleaseDir, lmtValues['transformCTL'])
1548 lut = "%s.%s.spi3d" % (shaperName, lmtName)
1550 generate3dLUTFromCTL( lutDir + "/" + lut,
1554 1.0/shaperInputScale,
1560 cs.fromReferenceTransforms.append( shaperOCIOTransform )
1561 cs.fromReferenceTransforms.append( {
1564 'interpolation':'tetrahedral',
1565 'direction':'forward'
1569 # Generate the inverse transform
1571 cs.toReferenceTransforms = []
1573 if 'transformCTLInverse' in lmtValues:
1575 '%s/%s' % (acesCTLReleaseDir, odtValues['transformCTLInverse']),
1576 shaperFromACESCTL % acesCTLReleaseDir
1578 lut = "Inverse.%s.%s.spi3d" % (odtName, shaperName)
1580 generate3dLUTFromCTL( lutDir + "/" + lut,
1590 cs.toReferenceTransforms.append( {
1593 'interpolation':'tetrahedral',
1594 'direction':'forward'
1597 shaperInverse = shaperOCIOTransform.copy()
1598 shaperInverse['direction'] = 'forward'
1599 cs.toReferenceTransforms.append( shaperInverse )
1607 lmtLutResolution1d = max(4096, lutResolution1d)
1608 lmtLutResolution3d = max(65, lutResolution3d)
1611 lmtShaperName = 'LMT Shaper'
1613 'middleGrey' : 0.18,
1614 'minExposure' : -10.0,
1617 lmtShaper = createGenericLog(name=lmtShaperName,
1618 middleGrey=lmtParams['middleGrey'],
1619 minExposure=lmtParams['minExposure'],
1620 maxExposure=lmtParams['maxExposure'],
1621 lutResolution1d=lmtLutResolution1d)
1622 configData['colorSpaces'].append(lmtShaper)
1624 shaperInputScale_genericLog2 = 1.0
1626 # Log 2 shaper name and CTL transforms bundled up
1629 '%s/utilities/ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl',
1630 '%s/utilities/ACESlib.OCIO_shaper_lin_to_log2_param.a1.0.0.ctl',
1631 #'%s/logShaper/logShaper16i_to_aces_param.ctl',
1632 #'%s/logShaper/aces_to_logShaper16i_param.ctl',
1633 shaperInputScale_genericLog2,
1637 sortedLMTs = sorted(lmtInfo.iteritems(), key=lambda x: x[1])
1639 for lmt in sortedLMTs:
1640 (lmtName, lmtValues) = lmt
1642 lmtValues['transformUserName'],
1648 configData['colorSpaces'].append(cs)
1651 # ACES RRT with the supplied ODT
1653 def createACESRRTplusODT(odtName,
1656 lutResolution1d=1024,
1659 cs = ColorSpace("%s" % odtName)
1660 cs.description = "%s - %s Output Transform" % (odtValues['transformUserNamePrefix'], odtName)
1661 cs.equalityGroup = ''
1662 cs.family = 'Output'
1666 pprint.pprint( odtValues )
1669 # Generate the shaper transform
1671 #if 'shaperCTL' in odtValues:
1672 (shaperName, shaperToACESCTL, shaperFromACESCTL, shaperInputScale, shaperParams) = shaperInfo
1674 if 'legalRange' in odtValues:
1675 shaperParams['legalRange'] = odtValues['legalRange']
1677 shaperParams['legalRange'] = 0
1679 shaperLut = "%s_to_aces.spi1d" % shaperName
1680 if( not os.path.exists( lutDir + "/" + shaperLut ) ):
1682 shaperToACESCTL % acesCTLReleaseDir
1684 generate1dLUTFromCTL( lutDir + "/" + shaperLut,
1688 1.0/shaperInputScale,
1694 shaperOCIOTransform = {
1697 'interpolation':'linear',
1698 'direction':'inverse'
1702 # Generate the forward transform
1704 cs.fromReferenceTransforms = []
1706 if 'transformLUT' in odtValues:
1707 # Copy into the lut dir
1708 transformLUTFileName = os.path.basename(odtValues['transformLUT'])
1709 lut = lutDir + "/" + transformLUTFileName
1710 shutil.copy(odtValues['transformLUT'], lut)
1712 cs.fromReferenceTransforms.append( shaperOCIOTransform )
1713 cs.fromReferenceTransforms.append( {
1715 'path': transformLUTFileName,
1716 'interpolation':'tetrahedral',
1717 'direction':'forward'
1719 elif 'transformCTL' in odtValues:
1723 shaperToACESCTL % acesCTLReleaseDir,
1724 '%s/rrt/RRT.a1.0.0.ctl' % acesCTLReleaseDir,
1725 '%s/odt/%s' % (acesCTLReleaseDir, odtValues['transformCTL'])
1727 lut = "%s.RRT.a1.0.0.%s.spi3d" % (shaperName, odtName)
1729 generate3dLUTFromCTL( lutDir + "/" + lut,
1734 1.0/shaperInputScale,
1740 cs.fromReferenceTransforms.append( shaperOCIOTransform )
1741 cs.fromReferenceTransforms.append( {
1744 'interpolation':'tetrahedral',
1745 'direction':'forward'
1749 # Generate the inverse transform
1751 cs.toReferenceTransforms = []
1753 if 'transformLUTInverse' in odtValues:
1754 # Copy into the lut dir
1755 transformLUTInverseFileName = os.path.basename(odtValues['transformLUTInverse'])
1756 lut = lutDir + "/" + transformLUTInverseFileName
1757 shutil.copy(odtValues['transformLUTInverse'], lut)
1759 cs.toReferenceTransforms.append( {
1761 'path': transformLUTInverseFileName,
1762 'interpolation':'tetrahedral',
1763 'direction':'forward'
1766 shaperInverse = shaperOCIOTransform.copy()
1767 shaperInverse['direction'] = 'forward'
1768 cs.toReferenceTransforms.append( shaperInverse )
1769 elif 'transformCTLInverse' in odtValues:
1771 '%s/odt/%s' % (acesCTLReleaseDir, odtValues['transformCTLInverse']),
1772 '%s/rrt/InvRRT.a1.0.0.ctl' % acesCTLReleaseDir,
1773 shaperFromACESCTL % acesCTLReleaseDir
1775 lut = "InvRRT.a1.0.0.%s.%s.spi3d" % (odtName, shaperName)
1777 generate3dLUTFromCTL( lutDir + "/" + lut,
1788 cs.toReferenceTransforms.append( {
1791 'interpolation':'tetrahedral',
1792 'direction':'forward'
1795 shaperInverse = shaperOCIOTransform.copy()
1796 shaperInverse['direction'] = 'forward'
1797 cs.toReferenceTransforms.append( shaperInverse )
1802 # RRT/ODT shaper options
1807 log2ShaperName = shaperName
1809 'middleGrey' : 0.18,
1810 'minExposure' : -6.0,
1813 log2Shaper = createGenericLog(name=log2ShaperName,
1814 middleGrey=log2Params['middleGrey'],
1815 minExposure=log2Params['minExposure'],
1816 maxExposure=log2Params['maxExposure'])
1817 configData['colorSpaces'].append(log2Shaper)
1819 shaperInputScale_genericLog2 = 1.0
1821 # Log 2 shaper name and CTL transforms bundled up
1824 '%s/utilities/ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl',
1825 '%s/utilities/ACESlib.OCIO_shaper_lin_to_log2_param.a1.0.0.ctl',
1826 #'%s/logShaper/logShaper16i_to_aces_param.ctl',
1827 #'%s/logShaper/aces_to_logShaper16i_param.ctl',
1828 shaperInputScale_genericLog2,
1832 shaperData[log2ShaperName] = log2ShaperData
1835 # Shaper that also includes the AP1 primaries
1836 # - Needed for some LUT baking steps
1838 log2ShaperAP1 = createGenericLog(name=log2ShaperName,
1839 middleGrey=log2Params['middleGrey'],
1840 minExposure=log2Params['minExposure'],
1841 maxExposure=log2Params['maxExposure'])
1842 log2ShaperAP1.name = "%s - AP1" % log2ShaperAP1.name
1843 # AP1 primaries to AP0 primaries
1844 log2ShaperAP1.toReferenceTransforms.append( {
1846 'matrix':mat44FromMat33(acesAP1toAP0),
1847 'direction':'forward'
1849 configData['colorSpaces'].append(log2ShaperAP1)
1852 # Choose your shaper
1855 # Shaper name. Should really be automated or made a user choice
1857 # Options: aceslogShaper, aceslogScaledShaper, log2Shaper
1858 #shaperName = 'log2Shaper'
1860 #if shaperName in shaperData:
1861 # rrtShaperName = shaperName
1862 # rrtShaper = shaperData[shaperName]
1865 rrtShaperName = log2ShaperName
1866 rrtShaper = log2ShaperData
1869 # RRT + ODT Combinations
1871 #for odtName, odtValues in odtInfo.iteritems():
1872 sortedOdts = sorted(odtInfo.iteritems(), key=lambda x: x[1])
1874 for odt in sortedOdts:
1875 (odtName, odtValues) = odt
1877 # Have to handle ODTs that can generate either legal or full output
1878 if odtName in ['Academy.Rec2020_100nits_dim.a1.0.0',
1879 'Academy.Rec709_100nits_dim.a1.0.0',
1880 'Academy.Rec709_D60sim_100nits_dim.a1.0.0']:
1881 odtNameLegal = '%s - Legal' % odtValues['transformUserName']
1883 odtNameLegal = odtValues['transformUserName']
1885 odtLegal = odtValues.copy()
1886 odtLegal['legalRange'] = 1
1888 cs = createACESRRTplusODT(
1895 configData['colorSpaces'].append(cs)
1897 # Create a display entry using this color space
1898 configData['displays'][odtNameLegal] = {
1901 'Output Transform':cs }
1903 if odtName in ['Academy.Rec2020_100nits_dim.a1.0.0',
1904 'Academy.Rec709_100nits_dim.a1.0.0',
1905 'Academy.Rec709_D60sim_100nits_dim.a1.0.0']:
1907 print( "Generating full range ODT for %s" % odtName)
1909 odtNameFull = "%s - Full" % odtValues['transformUserName']
1910 odtFull = odtValues.copy()
1911 odtFull['legalRange'] = 0
1913 csFull = createACESRRTplusODT(
1920 configData['colorSpaces'].append(csFull)
1922 # Create a display entry using this color space
1923 configData['displays'][odtNameFull] = {
1926 'Output Transform':csFull }
1929 # Generic Matrix transform
1931 def createGenericMatrix(name='matrix',
1932 fromReferenceValues=[],
1933 toReferenceValues=[]):
1934 cs = ColorSpace(name)
1935 cs.description = "The %s color space" % name
1936 cs.equalityGroup = name
1937 cs.family = 'Utility'
1940 cs.toReferenceTransforms = []
1941 if toReferenceValues != []:
1942 for matrix in toReferenceValues:
1943 cs.toReferenceTransforms.append( {
1945 'matrix':mat44FromMat33(matrix),
1946 'direction':'forward'
1949 cs.fromReferenceTransforms = []
1950 if fromReferenceValues != []:
1951 for matrix in fromReferenceValues:
1952 cs.fromReferenceTransforms.append( {
1954 'matrix':mat44FromMat33(matrix),
1955 'direction':'forward'
1960 cs = createGenericMatrix('XYZ', fromReferenceValues=[acesAP0toXYZ])
1961 configData['colorSpaces'].append(cs)
1963 cs = createGenericMatrix('Linear - AP1', toReferenceValues=[acesAP1toAP0])
1964 configData['colorSpaces'].append(cs)
1966 # ACES to Linear, P3D60 primaries
1967 xyzToP3D60 = [ 2.4027414142, -0.8974841639, -0.3880533700,
1968 -0.8325796487, 1.7692317536, 0.0237127115,
1969 0.0388233815, -0.0824996856, 1.0363685997]
1971 cs = createGenericMatrix('Linear - P3-D60', fromReferenceValues=[acesAP0toXYZ, xyzToP3D60])
1972 configData['colorSpaces'].append(cs)
1974 # ACES to Linear, P3D60 primaries
1975 xyzToP3DCI = [ 2.7253940305, -1.0180030062, -0.4401631952,
1976 -0.7951680258, 1.6897320548, 0.0226471906,
1977 0.0412418914, -0.0876390192, 1.1009293786]
1979 cs = createGenericMatrix('Linear - P3-DCI', fromReferenceValues=[acesAP0toXYZ, xyzToP3DCI])
1980 configData['colorSpaces'].append(cs)
1982 # ACES to Linear, Rec 709 primaries
1983 xyzToRec709 = [ 3.2409699419, -1.5373831776, -0.4986107603,
1984 -0.9692436363, 1.8759675015, 0.0415550574,
1985 0.0556300797, -0.2039769589, 1.0569715142]
1987 cs = createGenericMatrix('Linear - Rec.709', fromReferenceValues=[acesAP0toXYZ, xyzToRec709])
1988 configData['colorSpaces'].append(cs)
1990 # ACES to Linear, Rec 2020 primaries
1991 xyzToRec2020 = [ 1.7166511880, -0.3556707838, -0.2533662814,
1992 -0.6666843518, 1.6164812366, 0.0157685458,
1993 0.0176398574, -0.0427706133, 0.9421031212]
1995 cs = createGenericMatrix('Linear - Rec.2020', fromReferenceValues=[acesAP0toXYZ, xyzToRec2020])
1996 configData['colorSpaces'].append(cs)
1998 print( "generateLUTs - end" )
2001 def generateBakedLUTs(odtInfo, shaperName, bakedDir, configPath, lutResolution1d, lutResolution3d, lutResolutionShaper=1024):
2003 # Add the legal and full variations into this list
2004 odtInfoC = dict(odtInfo)
2005 for odtCTLName, odtValues in odtInfo.iteritems():
2006 if odtCTLName in ['Academy.Rec2020_100nits_dim.a1.0.0',
2007 'Academy.Rec709_100nits_dim.a1.0.0',
2008 'Academy.Rec709_D60sim_100nits_dim.a1.0.0']:
2009 odtName = odtValues["transformUserName"]
2011 odtValuesLegal = dict(odtValues)
2012 odtValuesLegal["transformUserName"] = "%s - Legal" % odtName
2013 odtInfoC["%s - Legal" % odtCTLName] = odtValuesLegal
2015 odtValuesFull = dict(odtValues)
2016 odtValuesFull["transformUserName"] = "%s - Full" % odtName
2017 odtInfoC["%s - Full" % odtCTLName] = odtValuesFull
2019 del( odtInfoC[odtCTLName] )
2021 for odtCTLName, odtValues in odtInfoC.iteritems():
2022 odtPrefix = odtValues["transformUserNamePrefix"]
2023 odtName = odtValues["transformUserName"]
2026 for inputspace in ["ACEScc", "ACESproxy"]:
2027 args = ["--iconfig", configPath, "-v", "--inputspace", inputspace ]
2028 args += ["--outputspace", "%s" % odtName ]
2029 args += ["--description", "%s - %s for %s data" % (odtPrefix, odtName, inputspace) ]
2030 args += ["--shaperspace", shaperName, "--shapersize", str(lutResolutionShaper) ]
2031 args += ["--cubesize", str(lutResolution3d) ]
2032 args += ["--format", "icc", "%s/photoshop/%s for %s.icc" % (bakedDir, odtName, inputspace) ]
2034 bakeLUT = process.Process(description="bake a LUT", cmd="ociobakelut", args=args)
2038 for inputspace in ["ACEScc", "ACESproxy"]:
2039 args = ["--iconfig", configPath, "-v", "--inputspace", inputspace ]
2040 args += ["--outputspace", "%s" % odtName ]
2041 args += ["--description", "%s - %s for %s data" % (odtPrefix, odtName, inputspace) ]
2042 args += ["--shaperspace", shaperName, "--shapersize", str(lutResolutionShaper) ]
2043 args += ["--cubesize", str(lutResolution3d) ]
2045 fargs = ["--format", "flame", "%s/flame/%s for %s Flame.3dl" % (bakedDir, odtName, inputspace) ]
2046 bakeLUT = process.Process(description="bake a LUT", cmd="ociobakelut", args=(args + fargs))
2049 largs = ["--format", "lustre", "%s/lustre/%s for %s Lustre.3dl" % (bakedDir, odtName, inputspace) ]
2050 bakeLUT = process.Process(description="bake a LUT", cmd="ociobakelut", args=(args + largs))
2054 for inputspace in ["ACEScg", "ACES2065-1"]:
2055 args = ["--iconfig", configPath, "-v", "--inputspace", inputspace ]
2056 args += ["--outputspace", "%s" % odtName ]
2057 args += ["--description", "%s - %s for %s data" % (odtPrefix, odtName, inputspace) ]
2058 if inputspace == 'ACEScg':
2059 linShaperName = "%s - AP1" % shaperName
2061 linShaperName = shaperName
2062 args += ["--shaperspace", linShaperName, "--shapersize", str(lutResolutionShaper) ]
2064 args += ["--cubesize", str(lutResolution3d) ]
2066 margs = ["--format", "cinespace", "%s/maya/%s for %s Maya.csp" % (bakedDir, odtName, inputspace) ]
2067 bakeLUT = process.Process(description="bake a LUT", cmd="ociobakelut", args=(args + margs))
2070 hargs = ["--format", "houdini", "%s/houdini/%s for %s Houdini.lut" % (bakedDir, odtName, inputspace) ]
2071 bakeLUT = process.Process(description="bake a LUT", cmd="ociobakelut", args=(args + hargs))
2075 def createConfigDir(configDir, bakeSecondaryLUTs):
2076 dirs = [configDir, "%s/luts" % configDir]
2077 if bakeSecondaryLUTs:
2078 dirs.extend(["%s/baked" % configDir,
2079 "%s/baked/flame" % configDir, "%s/baked/photoshop" % configDir,
2080 "%s/baked/houdini" % configDir, "%s/baked/lustre" % configDir,
2081 "%s/baked/maya" % configDir])
2084 if not os.path.exists(d):
2087 def getTransformInfo(ctlTransform):
2088 fp = open(ctlTransform, 'rb')
2091 lines = fp.readlines()
2093 # Grab transform ID and User Name
2094 transformID = lines[1][3:].split('<')[1].split('>')[1].lstrip().rstrip()
2095 #print( transformID )
2096 transformUserName = '-'.join(lines[2][3:].split('<')[1].split('>')[1].split('-')[1:]).lstrip().rstrip()
2097 transformUserNamePrefix = lines[2][3:].split('<')[1].split('>')[1].split('-')[0].lstrip().rstrip()
2098 #print( transformUserName )
2101 return (transformID, transformUserName, transformUserNamePrefix)
2103 # For versions after WGR9
2104 def getODTInfo(acesCTLReleaseDir):
2105 # Credit to Alex Fry for the original approach here
2106 odtDir = os.path.join(acesCTLReleaseDir, "odt")
2108 for dirName, subdirList, fileList in os.walk(odtDir):
2109 for fname in fileList:
2110 allodt.append((os.path.join(dirName,fname)))
2112 odtCTLs = [x for x in allodt if ("InvODT" not in x) and (os.path.split(x)[-1][0] != '.')]
2118 for odtCTL in odtCTLs:
2119 odtTokens = os.path.split(odtCTL)
2122 # Handle nested directories
2123 odtPathTokens = os.path.split(odtTokens[-2])
2124 odtDir = odtPathTokens[-1]
2125 while odtPathTokens[-2][-3:] != 'odt':
2126 odtPathTokens = os.path.split(odtPathTokens[-2])
2127 odtDir = os.path.join(odtPathTokens[-1], odtDir)
2130 #print( "odtDir : %s" % odtDir )
2131 transformCTL = odtTokens[-1]
2132 #print( transformCTL )
2133 odtName = string.join(transformCTL.split('.')[1:-1], '.')
2136 # Find id, user name and user name prefix
2137 (transformID, transformUserName, transformUserNamePrefix) = getTransformInfo(
2138 "%s/odt/%s/%s" % (acesCTLReleaseDir, odtDir, transformCTL) )
2141 transformCTLInverse = "InvODT.%s.ctl" % odtName
2142 if not os.path.exists(os.path.join(odtTokens[-2], transformCTLInverse)):
2143 transformCTLInverse = None
2144 #print( transformCTLInverse )
2146 # Add to list of ODTs
2148 odts[odtName]['transformCTL'] = os.path.join(odtDir, transformCTL)
2149 if transformCTLInverse != None:
2150 odts[odtName]['transformCTLInverse'] = os.path.join(odtDir, transformCTLInverse)
2152 odts[odtName]['transformID'] = transformID
2153 odts[odtName]['transformUserNamePrefix'] = transformUserNamePrefix
2154 odts[odtName]['transformUserName'] = transformUserName
2156 print( "ODT : %s" % odtName )
2157 print( "\tTransform ID : %s" % transformID )
2158 print( "\tTransform User Name Prefix : %s" % transformUserNamePrefix )
2159 print( "\tTransform User Name : %s" % transformUserName )
2160 print( "\tForward ctl : %s" % odts[odtName]['transformCTL'])
2161 if 'transformCTLInverse' in odts[odtName]:
2162 print( "\tInverse ctl : %s" % odts[odtName]['transformCTLInverse'])
2164 print( "\tInverse ctl : %s" % "None" )
2170 # For versions after WGR9
2171 def getLMTInfo(acesCTLReleaseDir):
2172 # Credit to Alex Fry for the original approach here
2173 lmtDir = os.path.join(acesCTLReleaseDir, "lmt")
2175 for dirName, subdirList, fileList in os.walk(lmtDir):
2176 for fname in fileList:
2177 alllmt.append((os.path.join(dirName,fname)))
2179 lmtCTLs = [x for x in alllmt if ("InvLMT" not in x) and ("README" not in x) and (os.path.split(x)[-1][0] != '.')]
2185 for lmtCTL in lmtCTLs:
2186 lmtTokens = os.path.split(lmtCTL)
2189 # Handle nested directories
2190 lmtPathTokens = os.path.split(lmtTokens[-2])
2191 lmtDir = lmtPathTokens[-1]
2192 while lmtPathTokens[-2][-3:] != 'ctl':
2193 lmtPathTokens = os.path.split(lmtPathTokens[-2])
2194 lmtDir = os.path.join(lmtPathTokens[-1], lmtDir)
2197 #print( "lmtDir : %s" % lmtDir )
2198 transformCTL = lmtTokens[-1]
2199 #print( transformCTL )
2200 lmtName = string.join(transformCTL.split('.')[1:-1], '.')
2203 # Find id, user name and user name prefix
2204 (transformID, transformUserName, transformUserNamePrefix) = getTransformInfo(
2205 "%s/%s/%s" % (acesCTLReleaseDir, lmtDir, transformCTL) )
2208 transformCTLInverse = "InvLMT.%s.ctl" % lmtName
2209 if not os.path.exists(os.path.join(lmtTokens[-2], transformCTLInverse)):
2210 transformCTLInverse = None
2211 #print( transformCTLInverse )
2213 # Add to list of LMTs
2215 lmts[lmtName]['transformCTL'] = os.path.join(lmtDir, transformCTL)
2216 if transformCTLInverse != None:
2217 lmts[odtName]['transformCTLInverse'] = os.path.join(lmtDir, transformCTLInverse)
2219 lmts[lmtName]['transformID'] = transformID
2220 lmts[lmtName]['transformUserNamePrefix'] = transformUserNamePrefix
2221 lmts[lmtName]['transformUserName'] = transformUserName
2223 print( "LMT : %s" % lmtName )
2224 print( "\tTransform ID : %s" % transformID )
2225 print( "\tTransform User Name Prefix : %s" % transformUserNamePrefix )
2226 print( "\tTransform User Name : %s" % transformUserName )
2227 print( "\t Forward ctl : %s" % lmts[lmtName]['transformCTL'])
2228 if 'transformCTLInverse' in lmts[lmtName]:
2229 print( "\t Inverse ctl : %s" % lmts[lmtName]['transformCTLInverse'])
2231 print( "\t Inverse ctl : %s" % "None" )
2238 # Create the ACES config
2240 def createACESConfig(acesCTLReleaseDir,
2242 lutResolution1d=4096,
2244 bakeSecondaryLUTs=True,
2247 # Get ODT names and CTL paths
2248 odtInfo = getODTInfo(acesCTLReleaseDir)
2250 # Get ODT names and CTL paths
2251 lmtInfo = getLMTInfo(acesCTLReleaseDir)
2254 createConfigDir(configDir, bakeSecondaryLUTs)
2256 # Generate config data and LUTs for different transforms
2257 lutDir = "%s/luts" % configDir
2258 shaperName = 'Output Shaper'
2259 configData = generateLUTs(odtInfo, lmtInfo, shaperName, acesCTLReleaseDir, lutDir, lutResolution1d, lutResolution3d, cleanup)
2261 # Create the config using the generated LUTs
2262 print( "Creating generic config")
2263 config = createConfig(configData)
2266 # Write the config to disk
2267 writeConfig(config, "%s/config.ocio" % configDir )
2269 # Create a config that will work well with Nuke using the previously generated LUTs
2270 print( "Creating Nuke-specific config")
2271 nuke_config = createConfig(configData, nuke=True)
2274 # Write the config to disk
2275 writeConfig(nuke_config, "%s/nuke_config.ocio" % configDir )
2277 # Bake secondary LUTs using the config
2278 if bakeSecondaryLUTs:
2279 generateBakedLUTs(odtInfo, shaperName, "%s/baked" % configDir, "%s/config.ocio" % configDir, lutResolution1d, lutResolution3d, lutResolution1d)
2287 p = optparse.OptionParser(description='An OCIO config generation script',
2288 prog='createACESConfig',
2289 version='createACESConfig 0.1',
2290 usage='%prog [options]')
2291 p.add_option('--acesCTLDir', '-a', default=None)
2292 p.add_option('--configDir', '-c', default=None)
2293 p.add_option('--lutResolution1d', default=4096)
2294 p.add_option('--lutResolution3d', default=64)
2295 p.add_option('--dontBakeSecondaryLUTs', action="store_true")
2296 p.add_option('--keepTempImages', action="store_true")
2298 options, arguments = p.parse_args()
2303 acesCTLDir = options.acesCTLDir
2304 configDir = options.configDir
2305 lutResolution1d = int(options.lutResolution1d)
2306 lutResolution3d = int(options.lutResolution3d)
2307 bakeSecondaryLUTs = not(options.dontBakeSecondaryLUTs)
2308 cleanupTempImages = not(options.keepTempImages)
2311 argsStart = sys.argv.index('--') + 1
2312 args = sys.argv[argsStart:]
2314 argsStart = len(sys.argv)+1
2317 print( "command line : \n%s\n" % " ".join(sys.argv) )
2319 if configDir == None:
2320 print( "process: No ACES CTL directory specified" )
2324 # Generate the configuration
2326 createACESConfig(acesCTLDir, configDir, lutResolution1d, lutResolution3d, bakeSecondaryLUTs, cleanupTempImages)
2329 if __name__ == '__main__':