Only the full range output will be used for Output Transforms that support either...
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / aces_config.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Defines objects creating the *ACES* configuration.
6 """
7
8 from __future__ import division
9
10 import copy
11 import os
12 import shutil
13 import sys
14
15 import PyOpenColorIO as ocio
16 from aces_ocio.colorspaces import aces
17 from aces_ocio.colorspaces import arri
18 from aces_ocio.colorspaces import canon
19 from aces_ocio.colorspaces import general
20 from aces_ocio.colorspaces import gopro
21 from aces_ocio.colorspaces import panasonic
22 from aces_ocio.colorspaces import red
23 from aces_ocio.colorspaces import sony
24 from aces_ocio.process import Process
25
26 from aces_ocio.utilities import replace, ColorSpace, compact
27
28 __author__ = 'ACES Developers'
29 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
30 __license__ = ''
31 __maintainer__ = 'ACES Developers'
32 __email__ = 'aces@oscars.org'
33 __status__ = 'Production'
34
35 __all__ = ['ACES_OCIO_CTL_DIRECTORY_ENVIRON',
36            'ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON',
37            'set_config_default_roles',
38            'write_config',
39            'generate_OCIO_transform',
40            'add_colorspace_alias',
41            'create_config',
42            'generate_LUTs',
43            'generate_baked_LUTs',
44            'create_config_dir',
45            'create_ACES_config',
46            'main']
47
48 ACES_OCIO_CTL_DIRECTORY_ENVIRON = 'ACES_OCIO_CTL_DIRECTORY'
49 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON = 'ACES_OCIO_CONFIGURATION_DIRECTORY'
50
51
52 def set_config_default_roles(config,
53                              color_picking='',
54                              color_timing='',
55                              compositing_log='',
56                              data='',
57                              default='',
58                              matte_paint='',
59                              reference='',
60                              scene_linear='',
61                              texture_paint='',
62                              rendering='',
63                              compositing_linear=''):
64     """
65     Sets given *OCIO* configuration default roles.
66
67     Parameters
68     ----------
69     config : config
70         *OCIO* configuration.
71     color_picking : str or unicode
72         Color picking role title.
73     color_timing : str or unicode
74         Color timing role title.
75     compositing_log : str or unicode
76         Compositing log role title.
77     data : str or unicode
78         Data role title.
79     default : str or unicode
80         Default role title.
81     matte_paint : str or unicode
82         Matte painting role title.
83     reference : str or unicode
84         Reference role title.
85     scene_linear : str or unicode
86         Scene linear role title.
87     texture_paint : str or unicode
88         Texture painting role title.
89
90     Returns
91     -------
92     bool
93          Definition success.
94     """
95
96     if color_picking:
97         config.setRole(ocio.Constants.ROLE_COLOR_PICKING, color_picking)
98     if color_timing:
99         config.setRole(ocio.Constants.ROLE_COLOR_TIMING, color_timing)
100     if compositing_log:
101         config.setRole(ocio.Constants.ROLE_COMPOSITING_LOG, compositing_log)
102     if data:
103         config.setRole(ocio.Constants.ROLE_DATA, data)
104     if default:
105         config.setRole(ocio.Constants.ROLE_DEFAULT, default)
106     if matte_paint:
107         config.setRole(ocio.Constants.ROLE_MATTE_PAINT, matte_paint)
108     if reference:
109         config.setRole(ocio.Constants.ROLE_REFERENCE, reference)
110     if texture_paint:
111         config.setRole(ocio.Constants.ROLE_TEXTURE_PAINT, texture_paint)
112
113     # 'rendering' and 'compositing_linear' roles default to the 'scene_linear'
114     # value if not set explicitly
115     if rendering:
116         config.setRole("rendering", rendering)
117     if compositing_linear:
118         config.setRole("compositing_linear", compositing_linear)
119     if scene_linear:
120         config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
121         if not rendering:
122             config.setRole("rendering", scene_linear)
123         if not compositing_linear:
124             config.setRole("compositing_linear", scene_linear)
125
126     return True
127
128
129 def write_config(config, config_path, sanity_check=True):
130     """
131     Writes the configuration to given path.
132
133     Parameters
134     ----------
135     parameter : type
136         Parameter description.
137
138     Returns
139     -------
140     type
141          Return value description.
142     """
143
144     if sanity_check:
145         try:
146             config.sanityCheck()
147         except Exception, e:
148             print e
149             print 'Configuration was not written due to a failed Sanity Check'
150             return
151
152     with open(config_path, mode='w') as fp:
153         fp.write(config.serialize())
154
155
156 def generate_OCIO_transform(transforms):
157     """
158     Object description.
159
160     Parameters
161     ----------
162     parameter : type
163         Parameter description.
164
165     Returns
166     -------
167     type
168          Return value description.
169     """
170
171     interpolation_options = {
172         'linear': ocio.Constants.INTERP_LINEAR,
173         'nearest': ocio.Constants.INTERP_NEAREST,
174         'tetrahedral': ocio.Constants.INTERP_TETRAHEDRAL}
175
176     direction_options = {
177         'forward': ocio.Constants.TRANSFORM_DIR_FORWARD,
178         'inverse': ocio.Constants.TRANSFORM_DIR_INVERSE}
179
180     ocio_transforms = []
181
182     for transform in transforms:
183
184         # lutFile transform
185         if transform['type'] == 'lutFile':
186             # Create transforms
187             ocio_transform = ocio.FileTransform()
188
189             if 'path' in transform:
190                 ocio_transform.setSrc(transform['path'])
191
192             if 'cccid' in transform:
193                 ocio_transform.setCCCId(transform['cccid'])
194
195             if 'interpolation' in transform:
196                 ocio_transform.setInterpolation(transform['interpolation'])
197             else:
198                 ocio_transform.setInterpolation(ocio.Constants.INTERP_BEST)
199
200             if 'direction' in transform:
201                 ocio_transform.setDirection(
202                     direction_options[transform['direction']])
203
204             ocio_transforms.append(ocio_transform)
205
206         # matrix transform
207         elif transform['type'] == 'matrix':
208             ocio_transform = ocio.MatrixTransform()
209             # MatrixTransform member variables can't be initialized directly.
210             # Each must be set individually.
211             ocio_transform.setMatrix(transform['matrix'])
212
213             if 'offset' in transform:
214                 ocio_transform.setOffset(transform['offset'])
215
216             if 'direction' in transform:
217                 ocio_transform.setDirection(
218                     direction_options[transform['direction']])
219
220             ocio_transforms.append(ocio_transform)
221
222         # exponent transform
223         elif transform['type'] == 'exponent':
224             ocio_transform = ocio.ExponentTransform()
225
226             if 'value' in transform:
227                 ocio_transform.setValue(transform['value'])
228
229             ocio_transforms.append(ocio_transform)
230
231         # log transform
232         elif transform['type'] == 'log':
233             ocio_transform = ocio.LogTransform()
234
235             if 'base' in transform:
236                 ocio_transform.setBase(transform['base'])
237
238             if 'direction' in transform:
239                 ocio_transform.setDirection(
240                     direction_options[transform['direction']])
241
242             ocio_transforms.append(ocio_transform)
243
244         # color space transform
245         elif transform['type'] == 'colorspace':
246             ocio_transform = ocio.ColorSpaceTransform()
247
248             if 'src' in transform:
249                 ocio_transform.setSrc(transform['src'])
250
251             if 'dst' in transform:
252                 ocio_transform.setDst(transform['dst'])
253
254             if 'direction' in transform:
255                 ocio_transform.setDirection(
256                     direction_options[transform['direction']])
257
258             ocio_transforms.append(ocio_transform)
259
260         # look transform
261         elif transform['type'] == 'look':
262             ocio_transform = ocio.LookTransform()
263             if 'look' in transform:
264                 ocio_transform.setLooks(transform['look'])
265
266             if 'src' in transform:
267                 ocio_transform.setSrc(transform['src'])
268
269             if 'dst' in transform:
270                 ocio_transform.setDst(transform['dst'])
271
272             if 'direction' in transform:
273                 ocio_transform.setDirection(
274                     direction_options[transform['direction']])
275
276             ocio_transforms.append(ocio_transform)
277
278         # unknown type
279         else:
280             print("Ignoring unknown transform type : %s" % transform['type'])
281
282     if len(ocio_transforms) > 1:
283         group_transform = ocio.GroupTransform()
284         for transform in ocio_transforms:
285             group_transform.push_back(transform)
286         transform = group_transform
287     else:
288         transform = ocio_transforms[0]
289
290     return transform
291
292
293 def add_colorspace_aliases(config,
294                            reference_colorspace,
295                            colorspace,
296                            colorspace_alias_names,
297                            family='Aliases'):
298     """
299     Object description.
300
301     Parameters
302     ----------
303     parameter : type
304         Parameter description.
305
306     Returns
307     -------
308     type
309          Return value description.
310     """
311
312     for alias_name in colorspace_alias_names:
313         if alias_name.lower() == colorspace.name.lower():
314             print('Skipping alias creation for %s, alias %s, because lower cased names match' % (
315                 colorspace.name, alias_name) )
316             continue
317
318         print('Adding alias colorspace space %s, alias to %s' % (
319             alias_name, colorspace.name))
320
321         compact_family_name = family
322
323         description = colorspace.description
324         if colorspace.aces_transform_id:
325             description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
326
327         ocio_colorspace_alias = ocio.ColorSpace(
328             name=alias_name,
329             bitDepth=colorspace.bit_depth,
330             description=description,
331             equalityGroup=colorspace.equality_group,
332             family=compact_family_name,
333             isData=colorspace.is_data,
334             allocation=colorspace.allocation_type,
335             allocationVars=colorspace.allocation_vars)
336
337         if colorspace.to_reference_transforms:
338             print('\tGenerating To-Reference transforms')
339             ocio_transform = generate_OCIO_transform(
340                 [{'type': 'colorspace',
341                   'src': colorspace.name,
342                   'dst': reference_colorspace.name,
343                   'direction': 'forward'}])
344             ocio_colorspace_alias.setTransform(
345                 ocio_transform,
346                 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
347
348         if colorspace.from_reference_transforms:
349             print('\tGenerating From-Reference transforms')
350             ocio_transform = generate_OCIO_transform(
351                 [{'type': 'colorspace',
352                   'src': reference_colorspace.name,
353                   'dst': colorspace.name,
354                   'direction': 'forward'}])
355             ocio_colorspace_alias.setTransform(
356                 ocio_transform,
357                 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
358
359         config.addColorSpace(ocio_colorspace_alias)
360
361 def colorspace_prefixed_name(colorspace):
362     prefix = colorspace.family.replace("/", " - ")
363     return "%s - %s" % (prefix, colorspace.name)
364
365 def add_look(config,
366              look,
367              prefix,
368              custom_lut_dir,
369              reference_name,
370              config_data,
371              multiple_displays=False):
372     """
373     Object description.
374
375     Parameters
376     ----------
377     parameter : type
378         Parameter description.
379
380     Returns
381     -------
382     type
383          Return value description.
384     """
385
386     look_name = look[0]
387     look_colorspace = look[1]
388     look_lut = look[2]
389     look_cccid = None
390     if len(look) == 4:
391         look_cccid = look[3]
392
393     print('Adding look %s - %s' % (look_name, ", ".join(look)) )
394
395     #
396     # Copy look lut
397     #
398     if custom_lut_dir:
399         if not '$' in look_lut:
400             print( "Getting ready to copy look lut : %s" % look_lut )
401             shutil.copy2(look_lut, custom_lut_dir)
402             look_lut = os.path.split(look_lut)[1]
403         else:
404             print( "Skipping LUT copy because path contains a context variable" )
405
406     #
407     # Create OCIO Look
408     #
409     # Look 1
410     print('Adding look to config' )
411     lk1 = ocio.Look()
412     lk1.setName( look_name )
413     lk1.setProcessSpace( look_colorspace )
414
415     keys = {'type': 'lutFile',
416             'path': look_lut,
417             'direction': 'forward'}
418     if look_cccid:
419         keys['cccid'] = look_cccid
420
421     ocio_transform = generate_OCIO_transform([keys])
422     lk1.setTransform( ocio_transform )
423
424     # add to config
425     config.addLook( lk1 )
426
427     print( "Creating aliased colorspace")
428
429     #
430     # Create OCIO colorspace that references that look
431     # - Needed for some implementations that don't process looks well
432     # - Also needed for some implementations that don't expose looks well
433     #
434     look_aliases = ["look_%s" % compact(look_name)]
435     colorspace = ColorSpace(look_name,
436         aliases=look_aliases,
437         description="The %s Look colorspace" % look_name,
438         family='Look')
439
440     colorspace.from_reference_transforms = [{'type': 'look',
441         'look': look_name,
442         'src': reference_name,
443         'dst': reference_name,
444         'direction': 'forward'}]
445
446     print('Adding colorspace %s, alias to look %s to config data' % (
447         look_name, look_name))
448
449     # Add this colorspace into the main list of colorspaces
450     config_data['colorSpaces'].append(colorspace)
451
452     print("")
453
454 def integrate_looks_into_views(config,
455                                looks,
456                                reference_name,
457                                config_data,
458                                multiple_displays=False):
459     """
460     Object description.
461
462     Parameters
463     ----------
464     parameter : type
465         Parameter description.
466
467     Returns
468     -------
469     type
470          Return value description.
471     """
472     look_names = [look[0] for look in looks] 
473
474     # Option 1 - Add a 'look' to each Display
475     # - Assumes there is a Display for each ACES Output Transform
476     if multiple_displays:
477         for look_name in look_names:
478             config_data['looks'].append(look_name)
479
480     # Option 2
481     # - Copy each Output Transform colorspace
482     # - For each copy, add a LookTransform at the head of the from_reference
483     #     transform list
484     # - Add these new copied colorspaces for the Displays / Views 
485     else:
486         for display, view_list in config_data['displays'].iteritems():
487             output_colorspace_copy = None
488             look_names_string = ""
489             for view_name, output_colorspace in view_list.iteritems():
490                 if view_name == "Output Transform":
491
492                     print( "Adding new View that incorporates looks" )
493
494                     # Make a copy of the output colorspace
495                     output_colorspace_copy = copy.deepcopy(output_colorspace)
496
497                     #for look_name in look_names:
498                     for i in range(len(look_names)):
499                         look_name = look_names[i]
500
501                         # Add the LookTransform to the head of the from_reference transform list
502                         if output_colorspace_copy.from_reference_transforms:
503                             output_colorspace_copy.from_reference_transforms.insert(i, {'type': 'look',
504                                 'look': look_name,
505                                 'src': reference_name,
506                                 'dst': reference_name,
507                                 'direction': 'forward'})
508
509                         # Add the LookTransform to the end of the to_reference transform list
510                         if output_colorspace_copy.to_reference_transforms:
511                             inverse_look_name = look_names[len(look_names) -1 -i]
512
513                             output_colorspace_copy.to_reference_transforms.append({'type': 'look',
514                                 'look': inverse_look_name,
515                                 'src': reference_name,
516                                 'dst': reference_name,
517                                 'direction': 'inverse'})
518
519                         if not look_name in config_data['looks']:
520                             config_data['looks'].append(look_name)
521
522                     look_names_string = ", ".join(look_names)
523                     output_colorspace_copy.name = "%s with %s" % (output_colorspace.name, look_names_string)
524                     output_colorspace_copy.aliases = ["out_%s" % compact(output_colorspace_copy.name)]
525
526                     print( "Colorspace that incorporates looks created : %s" % output_colorspace_copy.name )
527
528                     config_data['colorSpaces'].append(output_colorspace_copy)
529
530             if output_colorspace_copy:
531                 print( "Adding colorspace that incorporates looks into view list" )
532
533                 # Change the name of the View
534                 view_list["Output Transform with %s" % look_names_string] = output_colorspace_copy
535                 config_data['displays'][display] = view_list
536
537                 #print( "Display : %s, View List : %s" % (display, ", ".join(view_list)) )
538
539 def create_config(config_data, 
540     aliases=False, 
541     prefix=False,
542     multiple_displays=False,
543     look_info=[],
544     custom_lut_dir=None):
545     """
546     Object description.
547
548     Parameters
549     ----------
550     parameter : type
551         Parameter description.
552
553     Returns
554     -------
555     type
556          Return value description.
557     """
558
559     prefixed_names = {}
560     alias_colorspaces = []
561
562     # Creating the *OCIO* configuration.
563     config = ocio.Config()
564
565     # Setting configuration description.
566     config.setDescription('An ACES config generated from python')
567
568     # Setting configuration search path.
569     searchPath = ['luts']
570     if custom_lut_dir:
571         searchPath.append('custom')
572     config.setSearchPath(':'.join(searchPath))
573
574     # Defining the reference colorspace.
575     reference_data = config_data['referenceColorSpace']
576
577     # Adding the color space Family into the name
578     # Helps with applications that present colorspaces as one long list
579     if prefix:
580         prefixed_name = colorspace_prefixed_name(reference_data)
581         prefixed_names[reference_data.name] = prefixed_name
582         reference_data.name = prefixed_name
583
584     print('Adding the reference color space : %s' % reference_data.name)
585
586     reference = ocio.ColorSpace(
587         name=reference_data.name,
588         bitDepth=reference_data.bit_depth,
589         description=reference_data.description,
590         equalityGroup=reference_data.equality_group,
591         family=reference_data.family,
592         isData=reference_data.is_data,
593         allocation=reference_data.allocation_type,
594         allocationVars=reference_data.allocation_vars)
595
596     config.addColorSpace(reference)
597
598     # Add alias
599     if aliases:
600         if reference_data.aliases != []:
601             #add_colorspace_alias(config, reference_data,
602             #                     reference_data, reference_data.aliases)
603             # defer adding alias colorspaces until end. Helps with some applications
604             alias_colorspaces.append([reference_data, reference_data, reference_data.aliases])
605
606
607     print("")
608
609     #print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
610
611     #
612     # Add Looks and Look colorspaces
613     #
614     if look_info != []:
615         print('Adding looks')
616
617         config_data['looks'] = []
618
619         # Add looks and colorspaces
620         for look in look_info:
621             add_look(config, 
622                 look, 
623                 prefix, 
624                 custom_lut_dir, 
625                 reference_data.name,
626                 config_data)
627
628         # Integrate looks with displays, views
629         integrate_looks_into_views(config, 
630             look_info,
631             reference_data.name,
632             config_data,
633             multiple_displays)
634
635         print("")
636
637     print('Adding the regular color spaces')
638
639     # Creating the remaining colorspaces.
640     for colorspace in sorted(config_data['colorSpaces']):
641         # Adding the color space Family into the name
642         # Helps with applications that present colorspaces as one long list
643         if prefix:
644             prefixed_name = colorspace_prefixed_name(colorspace)
645             prefixed_names[colorspace.name] = prefixed_name
646             colorspace.name = prefixed_name
647
648         print('Creating new color space : %s' % colorspace.name)
649
650         description = colorspace.description
651         if colorspace.aces_transform_id:
652             description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
653
654         ocio_colorspace = ocio.ColorSpace(
655             name=colorspace.name,
656             bitDepth=colorspace.bit_depth,
657             description=description,
658             equalityGroup=colorspace.equality_group,
659             family=colorspace.family,
660             isData=colorspace.is_data,
661             allocation=colorspace.allocation_type,
662             allocationVars=colorspace.allocation_vars)
663
664         if colorspace.to_reference_transforms:
665             print('\tGenerating To-Reference transforms')
666             ocio_transform = generate_OCIO_transform(
667                 colorspace.to_reference_transforms)
668             ocio_colorspace.setTransform(
669                 ocio_transform,
670                 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
671
672         if colorspace.from_reference_transforms:
673             print('\tGenerating From-Reference transforms')
674             ocio_transform = generate_OCIO_transform(
675                 colorspace.from_reference_transforms)
676             ocio_colorspace.setTransform(
677                 ocio_transform,
678                 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
679
680         config.addColorSpace(ocio_colorspace)
681
682         #
683         # Add alias to normal colorspace, using compact name
684         #
685         if aliases:
686             if colorspace.aliases != []:
687                 #add_colorspace_alias(config, reference_data,
688                 #                     colorspace, colorspace.aliases)
689                 # defer adding alias colorspaces until end. Helps with some applications
690                 alias_colorspaces.append([reference_data, colorspace, colorspace.aliases])
691
692         print('')
693
694     print("")
695
696     #
697     # We add roles early so we can create alias colorspaces with the names of the roles
698     # before the rest of the colorspace aliases are added to the config.
699     #
700     print('Setting the roles')
701
702     if prefix:
703         set_config_default_roles(
704             config,
705             color_picking=prefixed_names[config_data['roles']['color_picking']],
706             color_timing=prefixed_names[config_data['roles']['color_timing']],
707             compositing_log=prefixed_names[config_data['roles']['compositing_log']],
708             data=prefixed_names[config_data['roles']['data']],
709             default=prefixed_names[config_data['roles']['default']],
710             matte_paint=prefixed_names[config_data['roles']['matte_paint']],
711             reference=prefixed_names[config_data['roles']['reference']],
712             scene_linear=prefixed_names[config_data['roles']['scene_linear']],
713             texture_paint=prefixed_names[config_data['roles']['texture_paint']])
714  
715         # Not allowed for the moment. role names can not overlap with colorspace names.
716         '''
717         # Add the aliased colorspaces for each role
718         for role_name, role_colorspace_name in config_data['roles'].iteritems():
719             role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
720
721             print( "Finding colorspace : %s" % role_colorspace_prefixed_name )
722             # Find the colorspace pointed to by the role
723             role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_prefixed_name]
724             role_colorspace = None
725             if len(role_colorspaces) > 0:
726                 role_colorspace = role_colorspaces[0]
727             else:
728                 if reference_data.name == role_colorspace_prefixed_name:
729                     role_colorspace = reference_data
730
731             if role_colorspace:
732                 print( "Adding an alias colorspace named %s, pointing to %s" % (
733                     role_name, role_colorspace.name))
734
735                 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
736         '''
737
738     else:
739         set_config_default_roles(
740             config,
741             color_picking=config_data['roles']['color_picking'],
742             color_timing=config_data['roles']['color_timing'],
743             compositing_log=config_data['roles']['compositing_log'],
744             data=config_data['roles']['data'],
745             default=config_data['roles']['default'],
746             matte_paint=config_data['roles']['matte_paint'],
747             reference=config_data['roles']['reference'],
748             scene_linear=config_data['roles']['scene_linear'],
749             texture_paint=config_data['roles']['texture_paint'])
750
751         # Not allowed for the moment. role names can not overlap with colorspace names.
752         '''
753         # Add the aliased colorspaces for each role
754         for role_name, role_colorspace_name in config_data['roles'].iteritems():
755             # Find the colorspace pointed to by the role
756             role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_name]
757             role_colorspace = None
758             if len(role_colorspaces) > 0:
759                 role_colorspace = role_colorspaces[0]
760             else:
761                 if reference_data.name == role_colorspace_name:
762                     role_colorspace = reference_data
763
764             if role_colorspace:
765                 print( "Adding an alias colorspace named %s, pointing to %s" % (
766                     role_name, role_colorspace.name))
767
768                 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
769         '''
770
771     print("")
772
773     # We add these at the end as some applications use the order of the colorspaces
774     # definitions in the config to order the colorspaces in their selection lists.
775     # Other go alphabetically. This should keep the alias colorspaces out of the way
776     # for the apps that use the order of definition in the config.
777     print('Adding the alias colorspaces')
778     for reference, colorspace, aliases in alias_colorspaces:
779         add_colorspace_aliases(config, reference, colorspace, aliases)
780
781     print("")
782
783     print('Adding the diplays and views')
784
785     # Defining the *views* and *displays*.
786     displays = []
787     views = []
788
789
790     # Defining a *generic* *display* and *view* setup.
791     if multiple_displays:
792         # Built list of looks to add to Displays
793         looks = config_data['looks'] if ('looks' in config_data) else []
794         looks = ", ".join(looks)
795         print( "Creating multiple displays, with looks : %s" % looks)
796
797         # Create Displays, Views
798         for display, view_list in config_data['displays'].iteritems():
799             for view_name, colorspace in view_list.iteritems():
800                 config.addDisplay(display, view_name, colorspace.name, looks)
801                 if 'Output Transform' in view_name and looks != "":
802                     # Add normal View, without looks
803                     config.addDisplay(display, view_name, colorspace.name)
804
805                     # Add View with looks
806                     view_name_with_looks = "%s with %s" % (view_name, looks)
807                     config.addDisplay(display, view_name_with_looks, colorspace.name, looks)
808                 else:
809                     config.addDisplay(display, view_name, colorspace.name)
810                 if not (view_name in views):
811                     views.append(view_name)
812             displays.append(display)
813
814     # Defining the set of *views* and *displays* useful in a *GUI* context.
815     else:
816         single_display_name = 'ACES'
817         #single_display_name = config_data['roles']['scene_linear']
818         displays.append(single_display_name)
819
820         display_names = sorted(config_data['displays'])
821
822         # Make sure the default display is first
823         default_display = config_data['defaultDisplay']
824         display_names.insert(0, display_names.pop(display_names.index(default_display)))
825
826         # Built list of looks to add to Displays
827         looks = config_data['looks'] if ('looks' in config_data) else []
828         look_names = ", ".join(looks)
829
830         displays_views_colorspaces = []
831
832         # Create Displays, Views
833         for display in display_names:
834             view_list = config_data['displays'][display]
835             for view_name, colorspace in view_list.iteritems():
836                 if 'Output Transform' in view_name:
837                     #print( "Adding view for %s" % view_name )
838
839                     # Maya 2016 doesn't like parentheses in View names
840                     display_cleaned = replace(display, {')': '', '(': ''})
841
842                     # We use the Display names as the View names in this case
843                     # as there is a single Display that contains all views.
844                     # This works for more applications than not, as of the time of this implementation.
845
846                     # If View includes looks
847                     if 'with' in view_name:
848                         # Integrate looks into view name
849                         display_cleaned = "%s with %s" % (display_cleaned, look_names)
850
851                         viewsWithLooksAtEnd = False
852                         # Storing combo of display, view and colorspace name in a list so we can
853                         # add them to the end of the list
854                         if viewsWithLooksAtEnd:
855                             displays_views_colorspaces.append([single_display_name, display_cleaned, colorspace.name])
856
857                         # Or add as normal
858                         else:
859                             config.addDisplay(single_display_name, display_cleaned, colorspace.name)
860
861                             # Add to views list
862                             if not (display_cleaned in views):
863                                 views.append(display_cleaned)
864
865                     # A normal View
866                     else:
867                         config.addDisplay(single_display_name, display_cleaned, colorspace.name)
868
869                         # Add to views list
870                         if not (display_cleaned in views):
871                             views.append(display_cleaned)
872
873         # Add to config any display, view combinations that were saved for later
874         for display_view_colorspace in displays_views_colorspaces:
875             single_display_name, display_cleaned, colorspace_name = display_view_colorspace
876
877             # Add to config
878             config.addDisplay(single_display_name, display_cleaned, colorspace_name)
879
880             # Add to views list
881             if not (display_cleaned in views):
882                 views.append(display_cleaned)
883
884
885         # Works with Nuke Studio and Mari, but not Nuke
886         # single_display_name = 'Utility'
887         # displays.append(single_display_name)
888
889         raw_display_space_name = config_data['roles']['data']        
890         log_display_space_name = config_data['roles']['compositing_log']
891
892         # Find the newly-prefixed colorspace names
893         if prefix:
894             #print( prefixed_names )
895             raw_display_space_name = prefixed_names[raw_display_space_name]
896             log_display_space_name = prefixed_names[log_display_space_name]
897
898         config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
899         views.append('Raw')
900         config.addDisplay(single_display_name, 'Log', log_display_space_name)
901         views.append('Log')
902
903     # Setting the active *displays* and *views*.
904     config.setActiveDisplays(','.join(sorted(displays)))
905     config.setActiveViews(','.join(views))
906
907     print("")
908
909     # Make sure we didn't create a bad config
910     config.sanityCheck()
911
912     # Reset the colorspace names back to their non-prefixed versions
913     if prefix:
914         # Build the reverse lookup
915         prefixed_names_inverse = {}
916         for original, prefixed in prefixed_names.iteritems():
917             prefixed_names_inverse[prefixed] = original
918
919         # Reset the reference colorspace name
920         reference_data.name = prefixed_names_inverse[reference_data.name]
921
922         # Reset the rest of the colorspace names
923         try:
924             for colorspace in config_data['colorSpaces']:
925                 colorspace.name = prefixed_names_inverse[colorspace.name]
926         except:
927             print( "Prefixed names")
928             for original, prefixed in prefixed_names.iteritems():
929                 print( "%s, %s" % (original, prefixed) )
930
931             print( "\n")
932
933             print( "Inverse Lookup")
934             for prefixed, original in prefixed_names_inverse.iteritems():
935                 print( "%s, %s" % (prefixed, original) )
936             raise
937
938     return config
939
940
941 def generate_LUTs(odt_info,
942                   lmt_info,
943                   shaper_name,
944                   aces_ctl_directory,
945                   lut_directory,
946                   lut_resolution_1d=4096,
947                   lut_resolution_3d=64,
948                   cleanup=True):
949     """
950     Object description.
951
952     Parameters
953     ----------
954     parameter : type
955         Parameter description.
956
957     Returns
958     -------
959     dict
960          Colorspaces and transforms converting between those colorspaces and
961          the reference colorspace, *ACES*.
962     """
963
964     print('generateLUTs - begin')
965     config_data = {}
966
967     # Initialize a few variables
968     config_data['displays'] = {}
969     config_data['colorSpaces'] = []
970
971     # -------------------------------------------------------------------------
972     # *ACES Color Spaces*
973     # -------------------------------------------------------------------------
974
975     # *ACES* colorspaces
976     (aces_reference,
977      aces_colorspaces,
978      aces_displays,
979      aces_log_display_space,
980      aces_roles,
981      aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
982                                                      lut_directory,
983                                                      lut_resolution_1d,
984                                                      lut_resolution_3d,
985                                                      lmt_info,
986                                                      odt_info,
987                                                      shaper_name,
988                                                      cleanup)
989
990     config_data['referenceColorSpace'] = aces_reference
991     config_data['roles'] = aces_roles
992
993     for cs in aces_colorspaces:
994         config_data['colorSpaces'].append(cs)
995
996     for name, data in aces_displays.iteritems():
997         config_data['displays'][name] = data
998
999     config_data['defaultDisplay'] = aces_default_display
1000     config_data['linearDisplaySpace'] = aces_reference
1001     config_data['logDisplaySpace'] = aces_log_display_space
1002
1003     # -------------------------------------------------------------------------
1004     # *Camera Input Transforms*
1005     # -------------------------------------------------------------------------
1006
1007     # *ARRI Log-C* to *ACES*.
1008     arri_colorSpaces = arri.create_colorspaces(lut_directory,
1009                                                lut_resolution_1d)
1010     for cs in arri_colorSpaces:
1011         config_data['colorSpaces'].append(cs)
1012
1013     # *Canon-Log* to *ACES*.
1014     canon_colorspaces = canon.create_colorspaces(lut_directory,
1015                                                  lut_resolution_1d)
1016     for cs in canon_colorspaces:
1017         config_data['colorSpaces'].append(cs)
1018
1019     # *GoPro Protune* to *ACES*.
1020     gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1021                                                  lut_resolution_1d)
1022     for cs in gopro_colorspaces:
1023         config_data['colorSpaces'].append(cs)
1024
1025     # *Panasonic V-Log* to *ACES*.
1026     panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1027                                                          lut_resolution_1d)
1028     for cs in panasonic_colorSpaces:
1029         config_data['colorSpaces'].append(cs)
1030
1031     # *RED* colorspaces to *ACES*.
1032     red_colorspaces = red.create_colorspaces(lut_directory,
1033                                              lut_resolution_1d)
1034     for cs in red_colorspaces:
1035         config_data['colorSpaces'].append(cs)
1036
1037     # *S-Log* to *ACES*.
1038     sony_colorSpaces = sony.create_colorspaces(lut_directory,
1039                                                lut_resolution_1d)
1040     for cs in sony_colorSpaces:
1041         config_data['colorSpaces'].append(cs)
1042
1043     # -------------------------------------------------------------------------
1044     # General Color Spaces
1045     # -------------------------------------------------------------------------
1046     general_colorSpaces = general.create_colorspaces(lut_directory,
1047                                                      lut_resolution_1d,
1048                                                      lut_resolution_3d)
1049     for cs in general_colorSpaces:
1050         config_data['colorSpaces'].append(cs)
1051
1052     # The *Raw* color space
1053     raw = general.create_raw()
1054     config_data['colorSpaces'].append(raw)
1055
1056     # Override certain roles, for now
1057     config_data['roles']['data'] = raw.name
1058     config_data['roles']['reference'] = raw.name
1059     config_data['roles']['texture_paint'] = raw.name
1060
1061     print('generateLUTs - end')
1062     return config_data
1063
1064
1065 def generate_baked_LUTs(odt_info,
1066                         shaper_name,
1067                         baked_directory,
1068                         config_path,
1069                         lut_resolution_1d,
1070                         lut_resolution_3d,
1071                         lut_resolution_shaper=1024,
1072                         prefix=False):
1073     """
1074     Object description.
1075
1076     Parameters
1077     ----------
1078     parameter : type
1079         Parameter description.
1080
1081     Returns
1082     -------
1083     type
1084          Return value description.
1085     """
1086
1087     odt_info_C = dict(odt_info)
1088
1089     # Uncomment if you would like to support the older behavior where ODTs
1090     # that have support for full and legal range output generate a LUT for each.
1091     '''
1092     # Create two entries for ODTs that have full and legal range support
1093     for odt_ctl_name, odt_values in odt_info.iteritems():
1094         if odt_values['transformHasFullLegalSwitch']:
1095             odt_name = odt_values['transformUserName']
1096
1097             odt_values_legal = dict(odt_values)
1098             odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1099             odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1100
1101             odt_values_full = dict(odt_values)
1102             odt_values_full['transformUserName'] = '%s - Full' % odt_name
1103             odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1104
1105             del (odt_info_C[odt_ctl_name])
1106     '''
1107
1108     # Generate appropriate LUTs for each ODT
1109     for odt_ctl_name, odt_values in odt_info_C.iteritems():
1110         odt_prefix = odt_values['transformUserNamePrefix']
1111         odt_name = odt_values['transformUserName']
1112
1113         # *Photoshop*
1114         for input_space in ['ACEScc', 'ACESproxy']:
1115             args = ['--iconfig', config_path,
1116                     '-v']
1117             if prefix:
1118                 args += ['--inputspace', "ACES - %s" % input_space]
1119                 args += ['--outputspace', "Output - %s" % odt_name]
1120             else:
1121                 args += ['--inputspace', input_space]
1122                 args += ['--outputspace', odt_name]
1123
1124             args += ['--description',
1125                      '%s - %s for %s data' % (odt_prefix,
1126                                               odt_name,
1127                                               input_space)]
1128             if prefix:
1129                 args += ['--shaperspace', "Utility - %s" % shaper_name,
1130                          '--shapersize', str(lut_resolution_shaper)]
1131             else:
1132                 args += ['--shaperspace', shaper_name,
1133                          '--shapersize', str(lut_resolution_shaper)]
1134             args += ['--cubesize', str(lut_resolution_3d)]
1135             args += ['--format',
1136                      'icc',
1137                      os.path.join(baked_directory,
1138                                   'photoshop',
1139                                   '%s for %s.icc' % (odt_name, input_space))]
1140
1141             bake_lut = Process(description='bake a LUT',
1142                                cmd='ociobakelut',
1143                                args=args)
1144             bake_lut.execute()
1145
1146         # *Flame*, *Lustre*
1147         for input_space in ['ACEScc', 'ACESproxy']:
1148             args = ['--iconfig', config_path,
1149                     '-v']
1150             if prefix:
1151                 args += ['--inputspace', "ACES - %s" % input_space]
1152                 args += ['--outputspace', "Output - %s" % odt_name]
1153             else:
1154                 args += ['--inputspace', input_space]
1155                 args += ['--outputspace', odt_name]
1156             args += ['--description',
1157                      '%s - %s for %s data' % (
1158                          odt_prefix, odt_name, input_space)]
1159             if prefix:
1160                 args += ['--shaperspace', "Utility - %s" % shaper_name,
1161                          '--shapersize', str(lut_resolution_shaper)]
1162             else:
1163                 args += ['--shaperspace', shaper_name,
1164                          '--shapersize', str(lut_resolution_shaper)]
1165             args += ['--cubesize', str(lut_resolution_3d)]
1166
1167             fargs = ['--format',
1168                      'flame',
1169                      os.path.join(
1170                          baked_directory,
1171                          'flame',
1172                          '%s for %s Flame.3dl' % (odt_name, input_space))]
1173             bake_lut = Process(description='bake a LUT',
1174                                cmd='ociobakelut',
1175                                args=(args + fargs))
1176             bake_lut.execute()
1177
1178             largs = ['--format',
1179                      'lustre',
1180                      os.path.join(
1181                          baked_directory,
1182                          'lustre',
1183                          '%s for %s Lustre.3dl' % (odt_name, input_space))]
1184             bake_lut = Process(description='bake a LUT',
1185                                cmd='ociobakelut',
1186                                args=(args + largs))
1187             bake_lut.execute()
1188
1189         # *Maya*, *Houdini*
1190         for input_space in ['ACEScg', 'ACES2065-1']:
1191             args = ['--iconfig', config_path,
1192                     '-v']
1193             if prefix:
1194                 args += ['--inputspace', "ACES - %s" % input_space]
1195                 args += ['--outputspace', "Output - %s" % odt_name]
1196             else:
1197                 args += ['--inputspace', input_space]
1198                 args += ['--outputspace', odt_name]
1199             args += ['--description',
1200                      '%s - %s for %s data' % (
1201                          odt_prefix, odt_name, input_space)]
1202             if input_space == 'ACEScg':
1203                 lin_shaper_name = "%s - AP1" % shaper_name
1204             else:
1205                 lin_shaper_name = shaper_name
1206             if prefix:
1207                 lin_shaper_name = "Utility - %s" % lin_shaper_name
1208             args += ['--shaperspace', lin_shaper_name,
1209                      '--shapersize', str(lut_resolution_shaper)]
1210
1211             args += ['--cubesize', str(lut_resolution_3d)]
1212
1213             margs = ['--format',
1214                      'cinespace',
1215                      os.path.join(
1216                          baked_directory,
1217                          'maya',
1218                          '%s for %s Maya.csp' % (odt_name, input_space))]
1219             bake_lut = Process(description='bake a LUT',
1220                                cmd='ociobakelut',
1221                                args=(args + margs))
1222             bake_lut.execute()
1223
1224             hargs = ['--format',
1225                      'houdini',
1226                      os.path.join(
1227                          baked_directory,
1228                          'houdini',
1229                          '%s for %s Houdini.lut' % (odt_name, input_space))]
1230             bake_lut = Process(description='bake a LUT',
1231                                cmd='ociobakelut',
1232                                args=(args + hargs))
1233             bake_lut.execute()
1234
1235
1236 def create_config_dir(config_directory, 
1237                       bake_secondary_LUTs=False,
1238                       custom_lut_dir=None):
1239     """
1240     Object description.
1241
1242     Parameters
1243     ----------
1244     parameter : type
1245         Parameter description.
1246
1247     Returns
1248     -------
1249     type
1250          Return value description.
1251     """
1252
1253     lut_directory = os.path.join(config_directory, 'luts')
1254     dirs = [config_directory, lut_directory]
1255
1256     if bake_secondary_LUTs:
1257         dirs.extend([os.path.join(config_directory, 'baked'),
1258                      os.path.join(config_directory, 'baked', 'flame'),
1259                      os.path.join(config_directory, 'baked', 'photoshop'),
1260                      os.path.join(config_directory, 'baked', 'houdini'),
1261                      os.path.join(config_directory, 'baked', 'lustre'),
1262                      os.path.join(config_directory, 'baked', 'maya')])
1263
1264     if custom_lut_dir:
1265         dirs.append(os.path.join(config_directory, 'custom'))
1266
1267     for d in dirs:
1268         not os.path.exists(d) and os.mkdir(d)
1269
1270     return lut_directory
1271
1272
1273 def create_ACES_config(aces_ctl_directory,
1274                        config_directory,
1275                        lut_resolution_1d=4096,
1276                        lut_resolution_3d=64,
1277                        bake_secondary_LUTs=True,
1278                        multiple_displays=False,
1279                        look_info=[],
1280                        copy_custom_luts=True,
1281                        cleanup=True,
1282                        prefix_colorspaces_with_family_names=True):
1283     """
1284     Creates the ACES configuration.
1285
1286     Parameters
1287     ----------
1288     parameter : type
1289         Parameter description.
1290
1291     Returns
1292     -------
1293     type
1294          Return value description.
1295     """
1296
1297     # Directory for custom LUTs
1298     custom_lut_dir = None
1299     if copy_custom_luts:
1300         custom_lut_dir = os.path.join(config_directory, "custom")
1301
1302     lut_directory = create_config_dir(config_directory, 
1303                                       bake_secondary_LUTs,
1304                                       custom_lut_dir)
1305
1306     odt_info = aces.get_ODTs_info(aces_ctl_directory)
1307     lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1308
1309     shaper_name = 'Output Shaper'
1310     config_data = generate_LUTs(odt_info,
1311                                 lmt_info,
1312                                 shaper_name,
1313                                 aces_ctl_directory,
1314                                 lut_directory,
1315                                 lut_resolution_1d,
1316                                 lut_resolution_3d,
1317                                 cleanup)
1318
1319     print('Creating config - with prefixes, with aliases')
1320     config = create_config(config_data, 
1321         prefix=prefix_colorspaces_with_family_names, 
1322         aliases=True, 
1323         multiple_displays=multiple_displays,
1324         look_info=look_info,
1325         custom_lut_dir=custom_lut_dir)
1326     print('\n\n\n')
1327
1328     write_config(config,
1329                  os.path.join(config_directory, 'config.ocio'))
1330
1331     if bake_secondary_LUTs:
1332         generate_baked_LUTs(odt_info,
1333                             shaper_name,
1334                             os.path.join(config_directory, 'baked'),
1335                             os.path.join(config_directory, 'config.ocio'),
1336                             lut_resolution_1d,
1337                             lut_resolution_3d,
1338                             lut_resolution_1d,
1339                             prefix=prefix_colorspaces_with_family_names)
1340
1341     return True
1342
1343
1344 def main():
1345     """
1346     Object description.
1347
1348     Parameters
1349     ----------
1350     parameter : type
1351         Parameter description.
1352
1353     Returns
1354     -------
1355     type
1356          Return value description.
1357     """
1358
1359     import optparse
1360
1361     usage  = '%prog [options]\n'
1362     usage += '\n'
1363     usage += 'An OCIO config generation script for ACES 1.0\n'
1364     usage += '\n'
1365     usage += 'Command line examples'
1366     usage += '\n'
1367     usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1368     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1369     usage += '\n'
1370     usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1371     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1372     usage += '\n'
1373     usage += '\n'
1374     usage += 'Adding custom looks'
1375     usage += '\n'
1376     usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1377     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookCDL ACESCDLName /path/to/SampleCDL.ccc cc03345'
1378     usage += '\n'
1379     usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1380     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1381     usage += '\n'
1382     usage += '\tIn this example, the CDL will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1383     usage += '\n'
1384     usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1385     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookLUT ACESLUTName /path/to/SampleCDL.ccc cc03345'
1386     usage += '\n'
1387     usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1388     usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1389     usage += '\n'
1390     usage += '\tIn this example, the LUT will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1391     usage += '\n'
1392
1393     look_info = []
1394     def look_info_callback(option, opt_str, value, parser):
1395         print( "look_info_callback" )
1396         print( option, opt_str, value, parser )
1397         if opt_str == "--addCustomLookCDL":
1398             look_info.append(value)
1399         elif opt_str == "--addCustomLookLUT":
1400             look_info.append(value)
1401         elif opt_str == "--addACESLookCDL":
1402             look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1403         elif opt_str == "--addACESLookLUT":
1404             look_info.append([value[0], "ACES - ACEScc", value[1]])
1405
1406     p = optparse.OptionParser(description='',
1407                               prog='create_aces_config',
1408                               version='create_aces_config 1.0',
1409                               usage=usage)
1410     p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1411         ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1412     p.add_option('--configDir', '-c', default=os.environ.get(
1413         ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1414     p.add_option('--lutResolution1d', default=4096)
1415     p.add_option('--lutResolution3d', default=64)
1416     p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1417     p.add_option('--keepTempImages', action='store_true', default=False)
1418
1419     p.add_option('--createMultipleDisplays', action='store_true', default=False)
1420
1421     p.add_option('--addCustomLookLUT', '', type='string', nargs=3, 
1422         action="callback", callback=look_info_callback)
1423     p.add_option('--addCustomLookCDL', '', type='string', nargs=4, 
1424         action="callback", callback=look_info_callback)
1425     p.add_option('--addACESLookLUT', '', type='string', nargs=2, 
1426         action="callback", callback=look_info_callback)
1427     p.add_option('--addACESLookCDL', '', type='string', nargs=3, 
1428         action="callback", callback=look_info_callback)
1429     p.add_option('--copyCustomLUTs', action='store_true', default=False)
1430
1431     options, arguments = p.parse_args()
1432
1433     aces_ctl_directory = options.acesCTLDir
1434     config_directory = options.configDir
1435     lut_resolution_1d = int(options.lutResolution1d)
1436     lut_resolution_3d = int(options.lutResolution3d)
1437     bake_secondary_luts = not options.dontBakeSecondaryLUTs
1438     cleanup_temp_images = not options.keepTempImages
1439     multiple_displays = options.createMultipleDisplays
1440     copy_custom_luts = options.copyCustomLUTs
1441
1442     print( look_info )
1443
1444     # TODO: Investigate the following statements.
1445     try:
1446         args_start = sys.argv.index('--') + 1
1447         args = sys.argv[args_start:]
1448     except:
1449         args_start = len(sys.argv) + 1
1450         args = []
1451
1452     print('command line : \n%s\n' % ' '.join(sys.argv))
1453
1454     assert aces_ctl_directory is not None, (
1455         'process: No "{0}" environment variable defined or no "ACES CTL" '
1456         'directory specified'.format(
1457             ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1458
1459     assert config_directory is not None, (
1460         'process: No "{0}" environment variable defined or no configuration '
1461         'directory specified'.format(
1462             ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1463
1464     return create_ACES_config(aces_ctl_directory,
1465                               config_directory,
1466                               lut_resolution_1d,
1467                               lut_resolution_3d,
1468                               bake_secondary_luts,
1469                               multiple_displays,
1470                               look_info,
1471                               copy_custom_luts,
1472                               cleanup_temp_images)
1473
1474 if __name__ == '__main__':
1475     main()