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