Remove unused locals.
[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     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, '
315                   'because lower cased names match' % (
316                 colorspace.name, alias_name))
317             continue
318
319         print('Adding alias colorspace space %s, alias to %s' % (
320             alias_name, colorspace.name))
321
322         compact_family_name = family
323
324         description = colorspace.description
325         if colorspace.aces_transform_id:
326             description += (
327                 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
328
329         ocio_colorspace_alias = ocio.ColorSpace(
330             name=alias_name,
331             bitDepth=colorspace.bit_depth,
332             description=description,
333             equalityGroup=colorspace.equality_group,
334             family=compact_family_name,
335             isData=colorspace.is_data,
336             allocation=colorspace.allocation_type,
337             allocationVars=colorspace.allocation_vars)
338
339         if colorspace.to_reference_transforms:
340             print('\tGenerating To-Reference transforms')
341             ocio_transform = generate_OCIO_transform(
342                 [{'type': 'colorspace',
343                   'src': colorspace.name,
344                   'dst': reference_colorspace.name,
345                   'direction': 'forward'}])
346             ocio_colorspace_alias.setTransform(
347                 ocio_transform,
348                 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
349
350         if colorspace.from_reference_transforms:
351             print('\tGenerating From-Reference transforms')
352             ocio_transform = generate_OCIO_transform(
353                 [{'type': 'colorspace',
354                   'src': reference_colorspace.name,
355                   'dst': colorspace.name,
356                   'direction': 'forward'}])
357             ocio_colorspace_alias.setTransform(
358                 ocio_transform,
359                 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
360
361         config.addColorSpace(ocio_colorspace_alias)
362
363
364 def add_look(config,
365              look,
366              custom_lut_dir,
367              reference_name,
368              config_data):
369     """
370     Object description.
371
372     Parameters
373     ----------
374     parameter : type
375         Parameter description.
376
377     Returns
378     -------
379     type
380          Return value description.
381     """
382
383     look_name, look_colorspace, look_lut, look_cccid = unpack_default(look, 4)
384
385     print('Adding look %s - %s' % (look_name, ', '.join(look)))
386
387     #
388     # Copy look lut
389     #
390     if custom_lut_dir:
391         if '$' not in look_lut:
392             print('Getting ready to copy look lut : %s' % look_lut)
393             shutil.copy2(look_lut, custom_lut_dir)
394             look_lut = os.path.split(look_lut)[1]
395         else:
396             print('Skipping LUT copy because path contains a context variable')
397
398     #
399     # Create OCIO Look
400     #
401     # Look 1
402     print('Adding look to config')
403     lk1 = ocio.Look()
404     lk1.setName(look_name)
405     lk1.setProcessSpace(look_colorspace)
406
407     keys = {'type': 'lutFile',
408             'path': look_lut,
409             'direction': 'forward'}
410     if look_cccid:
411         keys['cccid'] = look_cccid
412
413     ocio_transform = generate_OCIO_transform([keys])
414     lk1.setTransform(ocio_transform)
415
416     # add to config
417     config.addLook(lk1)
418
419     print('Creating aliased colorspace')
420
421     #
422     # Create OCIO colorspace that references that look
423     # - Needed for some implementations that don't process looks well
424     # - Also needed for some implementations that don't expose looks well
425     #
426     look_aliases = ['look_%s' % compact(look_name)]
427     colorspace = ColorSpace(look_name,
428                             aliases=look_aliases,
429                             description='The %s Look colorspace' % look_name,
430                             family='Look')
431
432     colorspace.from_reference_transforms = [{'type': 'look',
433                                              'look': look_name,
434                                              'src': reference_name,
435                                              'dst': reference_name,
436                                              'direction': 'forward'}]
437
438     print('Adding colorspace %s, alias to look %s to config data' % (
439         look_name, look_name))
440
441     # Add this colorspace into the main list of colorspaces
442     config_data['colorSpaces'].append(colorspace)
443
444     print()
445
446
447 def integrate_looks_into_views(looks,
448                                reference_name,
449                                config_data,
450                                multiple_displays=False):
451     """
452     Object description.
453
454     Parameters
455     ----------
456     parameter : type
457         Parameter description.
458
459     Returns
460     -------
461     type
462          Return value description.
463     """
464     look_names = [look[0] for look in looks]
465
466     # Option 1 - Add a 'look' to each Display
467     # - Assumes there is a Display for each ACES Output Transform
468     if multiple_displays:
469         for look_name in look_names:
470             config_data['looks'].append(look_name)
471
472     # Option 2
473     # - Copy each Output Transform colorspace
474     # - For each copy, add a LookTransform at the head of the from_reference
475     #     transform list
476     # - Add these new copied colorspaces for the Displays / Views 
477     else:
478         for display, view_list in config_data['displays'].iteritems():
479             output_colorspace_c = None
480             look_names_string = ''
481             for view_name, output_colorspace in view_list.iteritems():
482                 if view_name == 'Output Transform':
483
484                     print('Adding new View that incorporates looks')
485
486                     # Make a copy of the output colorspace
487                     output_colorspace_c = copy.deepcopy(output_colorspace)
488
489                     # for look_name in look_names:
490                     for i in range(len(look_names)):
491                         look_name = look_names[i]
492
493                         # Add the LookTransform to the head of the
494                         # from_reference transform list.
495                         if output_colorspace_c.from_reference_transforms:
496                             output_colorspace_c.from_reference_transforms.insert(
497                                 i, {'type': 'look',
498                                     'look': look_name,
499                                     'src': reference_name,
500                                     'dst': reference_name,
501                                     'direction': 'forward'})
502
503                         # Add the LookTransform to the end of
504                         # the to_reference transform list.
505                         if output_colorspace_c.to_reference_transforms:
506                             inverse_look_name = look_names[
507                                 len(look_names) - 1 - i]
508
509                             output_colorspace_c.to_reference_transforms.append(
510                                 {'type': 'look',
511                                  'look': inverse_look_name,
512                                  'src': reference_name,
513                                  'dst': reference_name,
514                                  'direction': 'inverse'})
515
516                         if look_name not in config_data['looks']:
517                             config_data['looks'].append(look_name)
518
519                     look_names_string = ', '.join(look_names)
520                     output_colorspace_c.name = '%s with %s' % (
521                     output_colorspace.name, look_names_string)
522                     output_colorspace_c.aliases = [
523                         'out_%s' % compact(output_colorspace_c.name)]
524
525                     print('Colorspace that incorporates looks '
526                           'created : %s' % output_colorspace_c.name)
527
528                     config_data['colorSpaces'].append(output_colorspace_c)
529
530             if output_colorspace_c:
531                 print('Adding colorspace that incorporates looks '
532                       'into view list')
533
534                 # Change the name of the View
535                 view_list['Output Transform with %s' % look_names_string] = (
536                     output_colorspace_c)
537                 config_data['displays'][display] = view_list
538
539                 # print('Display : %s, View List : %s' % (
540                 # display, ', '.join(view_list)) )
541
542
543 def create_config(config_data,
544                   aliases=False,
545                   prefix=False,
546                   multiple_displays=False,
547                   look_info=None,
548                   custom_lut_dir=None):
549     """
550     Object description.
551
552     Parameters
553     ----------
554     parameter : type
555         Parameter description.
556
557     Returns
558     -------
559     type
560          Return value description.
561     """
562
563     if look_info is None:
564         look_info = []
565
566     prefixed_names = {}
567     alias_colorspaces = []
568
569     # Creating the *OCIO* configuration.
570     config = ocio.Config()
571
572     # Setting configuration description.
573     config.setDescription('An ACES config generated from python')
574
575     # Setting configuration search path.
576     search_path = ['luts']
577     if custom_lut_dir:
578         search_path.append('custom')
579     config.setSearchPath(':'.join(search_path))
580
581     # Defining the reference colorspace.
582     reference_data = config_data['referenceColorSpace']
583
584     # Adding the color space Family into the name
585     # Helps with applications that present colorspaces as one long list
586     if prefix:
587         prefixed_name = colorspace_prefixed_name(reference_data)
588         prefixed_names[reference_data.name] = prefixed_name
589         reference_data.name = prefixed_name
590
591     print('Adding the reference color space : %s' % reference_data.name)
592
593     reference = ocio.ColorSpace(
594         name=reference_data.name,
595         bitDepth=reference_data.bit_depth,
596         description=reference_data.description,
597         equalityGroup=reference_data.equality_group,
598         family=reference_data.family,
599         isData=reference_data.is_data,
600         allocation=reference_data.allocation_type,
601         allocationVars=reference_data.allocation_vars)
602
603     config.addColorSpace(reference)
604
605     # Add alias
606     if aliases:
607         if reference_data.aliases:
608             # add_colorspace_alias(config, reference_data,
609             #                     reference_data, reference_data.aliases)
610             # defer adding alias colorspaces until end.
611             # Helps with some applications.
612             alias_colorspaces.append(
613                 [reference_data, reference_data, reference_data.aliases])
614
615     print()
616
617     # print('color spaces : %s' % [
618     # x.name for x in sorted(config_data['colorSpaces'])])
619
620     #
621     # Add Looks and Look colorspaces
622     #
623     if look_info:
624         print('Adding looks')
625
626         config_data['looks'] = []
627
628         # Add looks and colorspaces
629         for look in look_info:
630             add_look(config,
631                      look,
632                      custom_lut_dir,
633                      reference_data.name,
634                      config_data)
635
636         # Integrate looks with displays, views
637         integrate_looks_into_views(look_info,
638                                    reference_data.name,
639                                    config_data,
640                                    multiple_displays)
641
642         print()
643
644     print('Adding the regular color spaces')
645
646     # Creating the remaining colorspaces.
647     for colorspace in sorted(config_data['colorSpaces']):
648         # Adding the color space Family into the name
649         # Helps with applications that present colorspaces as one long list
650         if prefix:
651             prefixed_name = colorspace_prefixed_name(colorspace)
652             prefixed_names[colorspace.name] = prefixed_name
653             colorspace.name = prefixed_name
654
655         print('Creating new color space : %s' % colorspace.name)
656
657         description = colorspace.description
658         if colorspace.aces_transform_id:
659             description += (
660                 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
661
662         ocio_colorspace = ocio.ColorSpace(
663             name=colorspace.name,
664             bitDepth=colorspace.bit_depth,
665             description=description,
666             equalityGroup=colorspace.equality_group,
667             family=colorspace.family,
668             isData=colorspace.is_data,
669             allocation=colorspace.allocation_type,
670             allocationVars=colorspace.allocation_vars)
671
672         if colorspace.to_reference_transforms:
673             print('\tGenerating To-Reference transforms')
674             ocio_transform = generate_OCIO_transform(
675                 colorspace.to_reference_transforms)
676             ocio_colorspace.setTransform(
677                 ocio_transform,
678                 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
679
680         if colorspace.from_reference_transforms:
681             print('\tGenerating From-Reference transforms')
682             ocio_transform = generate_OCIO_transform(
683                 colorspace.from_reference_transforms)
684             ocio_colorspace.setTransform(
685                 ocio_transform,
686                 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
687
688         config.addColorSpace(ocio_colorspace)
689
690         #
691         # Add alias to normal colorspace, using compact name
692         #
693         if aliases:
694             if colorspace.aliases:
695                 # add_colorspace_alias(config, reference_data,
696                 #                     colorspace, colorspace.aliases)
697                 # defer adding alias colorspaces until end.
698                 # Helps with some applications.
699                 alias_colorspaces.append(
700                     [reference_data, colorspace, colorspace.aliases])
701
702         print()
703
704     print()
705
706     #
707     # We add roles early so we can create alias colorspaces with the names
708     # of the roles before the rest of the colorspace aliases are added
709     # to the config.
710     print('Setting the roles')
711
712     if prefix:
713         set_config_default_roles(
714             config,
715             color_picking=prefixed_names[
716                 config_data['roles']['color_picking']],
717             color_timing=prefixed_names[config_data['roles']['color_timing']],
718             compositing_log=prefixed_names[
719                 config_data['roles']['compositing_log']],
720             data=prefixed_names[config_data['roles']['data']],
721             default=prefixed_names[config_data['roles']['default']],
722             matte_paint=prefixed_names[config_data['roles']['matte_paint']],
723             reference=prefixed_names[config_data['roles']['reference']],
724             scene_linear=prefixed_names[config_data['roles']['scene_linear']],
725             texture_paint=prefixed_names[
726                 config_data['roles']['texture_paint']])
727
728         # Not allowed for the moment. role names can not overlap
729         # with colorspace names.
730         """
731         # Add the aliased colorspaces for each role
732         for role_name, role_colorspace_name in config_data['roles'].iteritems():
733             role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
734
735             print( 'Finding colorspace : %s' % role_colorspace_prefixed_name )
736             # Find the colorspace pointed to by the role
737             role_colorspaces = [colorspace
738                 for colorspace in config_data['colorSpaces']
739                 if colorspace.name == role_colorspace_prefixed_name]
740             role_colorspace = None
741             if len(role_colorspaces) > 0:
742                 role_colorspace = role_colorspaces[0]
743             else:
744                 if reference_data.name == role_colorspace_prefixed_name:
745                     role_colorspace = reference_data
746
747             if role_colorspace:
748                 print( 'Adding an alias colorspace named %s, pointing to %s' % (
749                     role_name, role_colorspace.name))
750
751                 add_colorspace_aliases(
752                 config, reference_data, role_colorspace, [role_name], 'Roles')
753         """
754
755     else:
756         set_config_default_roles(
757             config,
758             color_picking=config_data['roles']['color_picking'],
759             color_timing=config_data['roles']['color_timing'],
760             compositing_log=config_data['roles']['compositing_log'],
761             data=config_data['roles']['data'],
762             default=config_data['roles']['default'],
763             matte_paint=config_data['roles']['matte_paint'],
764             reference=config_data['roles']['reference'],
765             scene_linear=config_data['roles']['scene_linear'],
766             texture_paint=config_data['roles']['texture_paint'])
767
768         # Not allowed for the moment. role names can not overlap
769         # with colorspace names.
770         """
771         # Add the aliased colorspaces for each role
772         for role_name, role_colorspace_name in config_data['roles'].iteritems():
773             # Find the colorspace pointed to by the role
774             role_colorspaces = [colorspace
775             for colorspace in config_data['colorSpaces']
776             if colorspace.name == role_colorspace_name]
777             role_colorspace = None
778             if len(role_colorspaces) > 0:
779                 role_colorspace = role_colorspaces[0]
780             else:
781                 if reference_data.name == role_colorspace_name:
782                     role_colorspace = reference_data
783
784             if role_colorspace:
785                 print( 'Adding an alias colorspace named %s, pointing to %s' % (
786                     role_name, role_colorspace.name))
787
788                 add_colorspace_aliases(
789                 config, reference_data, role_colorspace, [role_name], 'Roles')
790         """
791
792     print()
793
794     # We add these at the end as some applications use the order of the
795     # colorspaces definitions in the config to order the colorspaces
796     # in their selection lists.
797     # Other go alphabetically. This should keep the alias colorspaces out
798     # of the way for the apps that use the order of definition in the config.
799     print('Adding the alias colorspaces')
800     for reference, colorspace, aliases in alias_colorspaces:
801         add_colorspace_aliases(config, reference, colorspace, aliases)
802
803     print()
804
805     print('Adding the diplays and views')
806
807     # Set the color_picking role to be
808     # the first Display's Output Transform View.
809     default_display_name = config_data['defaultDisplay']
810     default_display_views = config_data['displays'][default_display_name]
811     default_display_colorspace = default_display_views['Output Transform']
812
813     set_config_default_roles(
814         config,
815         color_picking=default_display_colorspace.name)
816
817     # Defining the *views* and *displays*.
818     displays = []
819     views = []
820
821     # Defining a *generic* *display* and *view* setup.
822     if multiple_displays:
823         # Built list of looks to add to Displays
824         looks = config_data['looks'] if ('looks' in config_data) else []
825         looks = ', '.join(looks)
826         print('Creating multiple displays, with looks : %s' % looks)
827
828         # Note: We don't reorder the Displays to put the 'defaultDisplay' first
829         # because OCIO will order them alphabetically
830         # when the config is written to disk.
831
832         # Create Displays, Views
833         for display, view_list in config_data['displays'].iteritems():
834             for view_name, colorspace in view_list.iteritems():
835                 config.addDisplay(display, view_name, colorspace.name, looks)
836                 if 'Output Transform' in view_name and looks != '':
837                     # Add normal View, without looks
838                     config.addDisplay(display, view_name, colorspace.name)
839
840                     # Add View with looks
841                     view_name_with_looks = '%s with %s' % (view_name, looks)
842                     config.addDisplay(display, view_name_with_looks,
843                                       colorspace.name, looks)
844                 else:
845                     config.addDisplay(display, view_name, colorspace.name)
846                 if not (view_name in views):
847                     views.append(view_name)
848             displays.append(display)
849
850     # Defining the set of *views* and *displays* useful in a *GUI* context.
851     else:
852         single_display_name = 'ACES'
853         # single_display_name = config_data['roles']['scene_linear']
854         displays.append(single_display_name)
855
856         # Make sure the default display is first
857         display_names = sorted(config_data['displays'])
858         display_names.insert(0, display_names.pop(
859             display_names.index(default_display_name)))
860
861         # Built list of looks to add to Displays
862         looks = config_data['looks'] if ('looks' in config_data) else []
863         look_names = ', '.join(looks)
864
865         displays_views_colorspaces = []
866
867         # Create Displays, Views
868         for display in display_names:
869             view_list = config_data['displays'][display]
870             for view_name, colorspace in view_list.iteritems():
871                 if 'Output Transform' in view_name:
872                     # print( 'Adding view for %s' % colorspace.name )
873
874                     # We use the Display names as the View names in this case
875                     # as there is a single Display that contains all views.
876                     # This works for more applications than not,
877                     # as of the time of this implementation.
878
879                     # Maya 2016 doesn't like parentheses in View names
880                     display_cleaned = replace(display, {')': '', '(': ''})
881
882                     # If View includes looks
883                     if 'with' in view_name:
884                         # Integrate looks into view name
885                         display_cleaned = '%s with %s' % (
886                         display_cleaned, look_names)
887
888                         views_with_looks_at_end = False
889                         # Storing combo of display, view and colorspace name
890                         # in a list so we can add them to the end of the list.
891                         if views_with_looks_at_end:
892                             displays_views_colorspaces.append(
893                                 [single_display_name, display_cleaned,
894                                  colorspace.name])
895
896                         # Or add as normal
897                         else:
898                             config.addDisplay(single_display_name,
899                                               display_cleaned, colorspace.name)
900
901                             # Add to views list
902                             if not (display_cleaned in views):
903                                 views.append(display_cleaned)
904
905                     # A normal View
906                     else:
907                         config.addDisplay(single_display_name, display_cleaned,
908                                           colorspace.name)
909
910                         # Add to views list
911                         if not (display_cleaned in views):
912                             views.append(display_cleaned)
913
914         # Add to config any display, view combinations that were saved
915         # for later. This list will be empty unless views_with_looks_at_end is
916         # set to True above.
917         for display_view_colorspace in displays_views_colorspaces:
918             single_display_name, display_cleaned, colorspace_name = (
919                 display_view_colorspace)
920
921             # Add to config
922             config.addDisplay(single_display_name, display_cleaned,
923                               colorspace_name)
924
925             # Add to views list
926             if not (display_cleaned in views):
927                 views.append(display_cleaned)
928
929
930         # Works with Nuke Studio and Mari, but not Nuke
931         # single_display_name = 'Utility'
932         # displays.append(single_display_name)
933
934         raw_display_space_name = config_data['roles']['data']
935         log_display_space_name = config_data['roles']['compositing_log']
936
937         # Find the newly-prefixed colorspace names
938         if prefix:
939             # print( prefixed_names )
940             raw_display_space_name = prefixed_names[raw_display_space_name]
941             log_display_space_name = prefixed_names[log_display_space_name]
942
943         config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
944         views.append('Raw')
945         config.addDisplay(single_display_name, 'Log', log_display_space_name)
946         views.append('Log')
947
948     # Setting the active *displays* and *views*.
949     config.setActiveDisplays(','.join(sorted(displays)))
950     config.setActiveViews(','.join(views))
951
952     print()
953
954     # Make sure we didn't create a bad config
955     config.sanityCheck()
956
957     # Reset the colorspace names back to their non-prefixed versions
958     if prefix:
959         # Build the reverse lookup
960         prefixed_names_inverse = {}
961         for original, prefixed in prefixed_names.iteritems():
962             prefixed_names_inverse[prefixed] = original
963
964         # Reset the reference colorspace name
965         reference_data.name = prefixed_names_inverse[reference_data.name]
966
967         # Reset the rest of the colorspace names
968         try:
969             for colorspace in config_data['colorSpaces']:
970                 colorspace.name = prefixed_names_inverse[colorspace.name]
971         except:
972             print('Prefixed names')
973             for original, prefixed in prefixed_names.iteritems():
974                 print('%s, %s' % (original, prefixed))
975
976             print('\n')
977
978             print('Inverse Lookup of Prefixed names')
979             for prefixed, original in prefixed_names_inverse.iteritems():
980                 print('%s, %s' % (prefixed, original))
981             raise
982
983     return config
984
985
986 def generate_LUTs(odt_info,
987                   lmt_info,
988                   shaper_name,
989                   aces_ctl_directory,
990                   lut_directory,
991                   lut_resolution_1d=4096,
992                   lut_resolution_3d=64,
993                   cleanup=True):
994     """
995     Object description.
996
997     Parameters
998     ----------
999     parameter : type
1000         Parameter description.
1001
1002     Returns
1003     -------
1004     dict
1005          Colorspaces and transforms converting between those colorspaces and
1006          the reference colorspace, *ACES*.
1007     """
1008
1009     print('generateLUTs - begin')
1010     config_data = {}
1011
1012     # Initialize a few variables
1013     config_data['displays'] = {}
1014     config_data['colorSpaces'] = []
1015
1016     # -------------------------------------------------------------------------
1017     # *ACES Color Spaces*
1018     # -------------------------------------------------------------------------
1019
1020     # *ACES* colorspaces
1021     (aces_reference,
1022      aces_colorspaces,
1023      aces_displays,
1024      aces_log_display_space,
1025      aces_roles,
1026      aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1027                                                      lut_directory,
1028                                                      lut_resolution_1d,
1029                                                      lut_resolution_3d,
1030                                                      lmt_info,
1031                                                      odt_info,
1032                                                      shaper_name,
1033                                                      cleanup)
1034
1035     config_data['referenceColorSpace'] = aces_reference
1036     config_data['roles'] = aces_roles
1037
1038     for cs in aces_colorspaces:
1039         config_data['colorSpaces'].append(cs)
1040
1041     for name, data in aces_displays.iteritems():
1042         config_data['displays'][name] = data
1043
1044     config_data['defaultDisplay'] = aces_default_display
1045     config_data['linearDisplaySpace'] = aces_reference
1046     config_data['logDisplaySpace'] = aces_log_display_space
1047
1048     # -------------------------------------------------------------------------
1049     # *Camera Input Transforms*
1050     # -------------------------------------------------------------------------
1051
1052     # *ARRI Log-C* to *ACES*.
1053     arri_colorspaces = arri.create_colorspaces(lut_directory,
1054                                                lut_resolution_1d)
1055     for cs in arri_colorspaces:
1056         config_data['colorSpaces'].append(cs)
1057
1058     # *Canon-Log* to *ACES*.
1059     canon_colorspaces = canon.create_colorspaces(lut_directory,
1060                                                  lut_resolution_1d)
1061     for cs in canon_colorspaces:
1062         config_data['colorSpaces'].append(cs)
1063
1064     # *GoPro Protune* to *ACES*.
1065     gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1066                                                  lut_resolution_1d)
1067     for cs in gopro_colorspaces:
1068         config_data['colorSpaces'].append(cs)
1069
1070     # *Panasonic V-Log* to *ACES*.
1071     panasonic_colorspaces = panasonic.create_colorspaces(lut_directory,
1072                                                          lut_resolution_1d)
1073     for cs in panasonic_colorspaces:
1074         config_data['colorSpaces'].append(cs)
1075
1076     # *RED* colorspaces to *ACES*.
1077     red_colorspaces = red.create_colorspaces(lut_directory,
1078                                              lut_resolution_1d)
1079     for cs in red_colorspaces:
1080         config_data['colorSpaces'].append(cs)
1081
1082     # *S-Log* to *ACES*.
1083     sony_colorspaces = sony.create_colorspaces(lut_directory,
1084                                                lut_resolution_1d)
1085     for cs in sony_colorspaces:
1086         config_data['colorSpaces'].append(cs)
1087
1088     # -------------------------------------------------------------------------
1089     # General Color Spaces
1090     # -------------------------------------------------------------------------
1091     general_colorspaces = general.create_colorspaces(lut_directory,
1092                                                      lut_resolution_1d)
1093     for cs in general_colorspaces:
1094         config_data['colorSpaces'].append(cs)
1095
1096     # The *Raw* color space
1097     raw = general.create_raw()
1098     config_data['colorSpaces'].append(raw)
1099
1100     # Override certain roles, for now
1101     config_data['roles']['data'] = raw.name
1102     config_data['roles']['reference'] = raw.name
1103     config_data['roles']['texture_paint'] = raw.name
1104
1105     print('generateLUTs - end')
1106     return config_data
1107
1108
1109 def generate_baked_LUTs(odt_info,
1110                         shaper_name,
1111                         baked_directory,
1112                         config_path,
1113                         lut_resolution_3d,
1114                         lut_resolution_shaper=1024,
1115                         prefix=False):
1116     """
1117     Object description.
1118
1119     Parameters
1120     ----------
1121     parameter : type
1122         Parameter description.
1123
1124     Returns
1125     -------
1126     type
1127          Return value description.
1128     """
1129
1130     odt_info_C = dict(odt_info)
1131
1132     # Uncomment if you would like to support the older behavior where ODTs
1133     # that have support for full and legal range output generate
1134     # a LUT for each.
1135     """
1136     # Create two entries for ODTs that have full and legal range support
1137     for odt_ctl_name, odt_values in odt_info.iteritems():
1138         if odt_values['transformHasFullLegalSwitch']:
1139             odt_name = odt_values['transformUserName']
1140
1141             odt_values_legal = dict(odt_values)
1142             odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1143             odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1144
1145             odt_values_full = dict(odt_values)
1146             odt_values_full['transformUserName'] = '%s - Full' % odt_name
1147             odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1148
1149             del (odt_info_C[odt_ctl_name])
1150     """
1151
1152     # Generate appropriate LUTs for each ODT
1153     for odt_ctl_name, odt_values in odt_info_C.iteritems():
1154         odt_prefix = odt_values['transformUserNamePrefix']
1155         odt_name = odt_values['transformUserName']
1156
1157         # *Photoshop*
1158         for input_space in ['ACEScc', 'ACESproxy']:
1159             args = ['--iconfig', config_path,
1160                     '-v']
1161             if prefix:
1162                 args += ['--inputspace', 'ACES - %s' % input_space]
1163                 args += ['--outputspace', 'Output - %s' % odt_name]
1164             else:
1165                 args += ['--inputspace', input_space]
1166                 args += ['--outputspace', odt_name]
1167
1168             args += ['--description',
1169                      '%s - %s for %s data' % (odt_prefix,
1170                                               odt_name,
1171                                               input_space)]
1172             if prefix:
1173                 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1174                          '--shapersize', str(lut_resolution_shaper)]
1175             else:
1176                 args += ['--shaperspace', shaper_name,
1177                          '--shapersize', str(lut_resolution_shaper)]
1178             args += ['--cubesize', str(lut_resolution_3d)]
1179             args += ['--format',
1180                      'icc',
1181                      os.path.join(baked_directory,
1182                                   'photoshop',
1183                                   '%s for %s.icc' % (odt_name, input_space))]
1184
1185             bake_lut = Process(description='bake a LUT',
1186                                cmd='ociobakelut',
1187                                args=args)
1188             bake_lut.execute()
1189
1190         # *Flame*, *Lustre*
1191         for input_space in ['ACEScc', 'ACESproxy']:
1192             args = ['--iconfig', config_path,
1193                     '-v']
1194             if prefix:
1195                 args += ['--inputspace', 'ACES - %s' % input_space]
1196                 args += ['--outputspace', 'Output - %s' % odt_name]
1197             else:
1198                 args += ['--inputspace', input_space]
1199                 args += ['--outputspace', odt_name]
1200             args += ['--description',
1201                      '%s - %s for %s data' % (
1202                          odt_prefix, odt_name, input_space)]
1203             if prefix:
1204                 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1205                          '--shapersize', str(lut_resolution_shaper)]
1206             else:
1207                 args += ['--shaperspace', shaper_name,
1208                          '--shapersize', str(lut_resolution_shaper)]
1209             args += ['--cubesize', str(lut_resolution_3d)]
1210
1211             fargs = ['--format',
1212                      'flame',
1213                      os.path.join(
1214                          baked_directory,
1215                          'flame',
1216                          '%s for %s Flame.3dl' % (odt_name, input_space))]
1217             bake_lut = Process(description='bake a LUT',
1218                                cmd='ociobakelut',
1219                                args=(args + fargs))
1220             bake_lut.execute()
1221
1222             largs = ['--format',
1223                      'lustre',
1224                      os.path.join(
1225                          baked_directory,
1226                          'lustre',
1227                          '%s for %s Lustre.3dl' % (odt_name, input_space))]
1228             bake_lut = Process(description='bake a LUT',
1229                                cmd='ociobakelut',
1230                                args=(args + largs))
1231             bake_lut.execute()
1232
1233         # *Maya*, *Houdini*
1234         for input_space in ['ACEScg', 'ACES2065-1']:
1235             args = ['--iconfig', config_path,
1236                     '-v']
1237             if prefix:
1238                 args += ['--inputspace', 'ACES - %s' % input_space]
1239                 args += ['--outputspace', 'Output - %s' % odt_name]
1240             else:
1241                 args += ['--inputspace', input_space]
1242                 args += ['--outputspace', odt_name]
1243             args += ['--description',
1244                      '%s - %s for %s data' % (
1245                          odt_prefix, odt_name, input_space)]
1246             if input_space == 'ACEScg':
1247                 lin_shaper_name = '%s - AP1' % shaper_name
1248             else:
1249                 lin_shaper_name = shaper_name
1250             if prefix:
1251                 lin_shaper_name = 'Utility - %s' % lin_shaper_name
1252             args += ['--shaperspace', lin_shaper_name,
1253                      '--shapersize', str(lut_resolution_shaper)]
1254
1255             args += ['--cubesize', str(lut_resolution_3d)]
1256
1257             margs = ['--format',
1258                      'cinespace',
1259                      os.path.join(
1260                          baked_directory,
1261                          'maya',
1262                          '%s for %s Maya.csp' % (odt_name, input_space))]
1263             bake_lut = Process(description='bake a LUT',
1264                                cmd='ociobakelut',
1265                                args=(args + margs))
1266             bake_lut.execute()
1267
1268             hargs = ['--format',
1269                      'houdini',
1270                      os.path.join(
1271                          baked_directory,
1272                          'houdini',
1273                          '%s for %s Houdini.lut' % (odt_name, input_space))]
1274             bake_lut = Process(description='bake a LUT',
1275                                cmd='ociobakelut',
1276                                args=(args + hargs))
1277             bake_lut.execute()
1278
1279
1280 def create_config_dir(config_directory,
1281                       bake_secondary_luts=False,
1282                       custom_lut_dir=None):
1283     """
1284     Object description.
1285
1286     Parameters
1287     ----------
1288     parameter : type
1289         Parameter description.
1290
1291     Returns
1292     -------
1293     type
1294          Return value description.
1295     """
1296
1297     lut_directory = os.path.join(config_directory, 'luts')
1298     dirs = [config_directory, lut_directory]
1299
1300     if bake_secondary_luts:
1301         dirs.extend([os.path.join(config_directory, 'baked'),
1302                      os.path.join(config_directory, 'baked', 'flame'),
1303                      os.path.join(config_directory, 'baked', 'photoshop'),
1304                      os.path.join(config_directory, 'baked', 'houdini'),
1305                      os.path.join(config_directory, 'baked', 'lustre'),
1306                      os.path.join(config_directory, 'baked', 'maya')])
1307
1308     if custom_lut_dir:
1309         dirs.append(os.path.join(config_directory, 'custom'))
1310
1311     for d in dirs:
1312         not os.path.exists(d) and os.mkdir(d)
1313
1314     return lut_directory
1315
1316
1317 def create_ACES_config(aces_ctl_directory,
1318                        config_directory,
1319                        lut_resolution_1d=4096,
1320                        lut_resolution_3d=64,
1321                        bake_secondary_luts=True,
1322                        multiple_displays=False,
1323                        look_info=None,
1324                        copy_custom_luts=True,
1325                        cleanup=True,
1326                        prefix_colorspaces_with_family_names=True):
1327     """
1328     Creates the ACES configuration.
1329
1330     Parameters
1331     ----------
1332     parameter : type
1333         Parameter description.
1334
1335     Returns
1336     -------
1337     type
1338          Return value description.
1339     """
1340
1341     if look_info is None:
1342         look_info = []
1343
1344     # Directory for custom LUTs
1345     custom_lut_dir = None
1346     if copy_custom_luts:
1347         custom_lut_dir = os.path.join(config_directory, 'custom')
1348
1349     lut_directory = create_config_dir(config_directory,
1350                                       bake_secondary_luts,
1351                                       custom_lut_dir)
1352
1353     odt_info = aces.get_ODTs_info(aces_ctl_directory)
1354     lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1355
1356     shaper_name = 'Output Shaper'
1357     config_data = generate_LUTs(odt_info,
1358                                 lmt_info,
1359                                 shaper_name,
1360                                 aces_ctl_directory,
1361                                 lut_directory,
1362                                 lut_resolution_1d,
1363                                 lut_resolution_3d,
1364                                 cleanup)
1365
1366     print('Creating config - with prefixes, with aliases')
1367     config = create_config(config_data,
1368                            prefix=prefix_colorspaces_with_family_names,
1369                            aliases=True,
1370                            multiple_displays=multiple_displays,
1371                            look_info=look_info,
1372                            custom_lut_dir=custom_lut_dir)
1373     print('\n\n\n')
1374
1375     write_config(config,
1376                  os.path.join(config_directory, 'config.ocio'))
1377
1378     if bake_secondary_luts:
1379         generate_baked_LUTs(odt_info,
1380                             shaper_name,
1381                             os.path.join(config_directory, 'baked'),
1382                             os.path.join(config_directory, 'config.ocio'),
1383                             lut_resolution_3d,
1384                             lut_resolution_1d,
1385                             prefix=prefix_colorspaces_with_family_names)
1386
1387     return True
1388
1389
1390 def main():
1391     """
1392     Object description.
1393
1394     Parameters
1395     ----------
1396     parameter : type
1397         Parameter description.
1398
1399     Returns
1400     -------
1401     type
1402          Return value description.
1403     """
1404
1405     import optparse
1406
1407     usage = '%prog [options]\n'
1408     usage += '\n'
1409     usage += 'An OCIO config generation script for ACES 1.0\n'
1410     usage += '\n'
1411     usage += 'Command line examples'
1412     usage += '\n'
1413     usage += ('Create a GUI-friendly ACES 1.0 config with no secondary, '
1414               'baked LUTs : \n')
1415     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1416               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1417               '--dontBakeSecondaryLUTs')
1418     usage += '\n'
1419     usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1420     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1421               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1422               '--createMultipleDisplays')
1423     usage += '\n'
1424     usage += '\n'
1425     usage += 'Adding custom looks'
1426     usage += '\n'
1427     usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style CDL '
1428               '(will be applied in the ACEScc colorspace): \n')
1429     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1430               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1431               '\n\t\t--addACESLookCDL ACESCDLName '
1432               '/path/to/SampleCDL.ccc cc03345')
1433     usage += '\n'
1434     usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1435     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1436               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1437               '\n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" '
1438               '/path/to/SampleCDL.ccc cc03345')
1439     usage += '\n'
1440     usage += ('\tIn this example, the CDL will be applied in the '
1441               'ACEScc colorspace, but the user could choose other spaces '
1442               'by changing the argument after the name of the look. \n')
1443     usage += '\n'
1444     usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style LUT '
1445               '(will be applied in the ACEScc colorspace): \n')
1446     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1447               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1448               '\n\t\t--addACESLookLUT ACESLUTName '
1449               '/path/to/SampleCDL.ccc cc03345')
1450     usage += '\n'
1451     usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1452     usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1453               '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1454               '\n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" '
1455               '/path/to/SampleCDL.ccc cc03345')
1456     usage += '\n'
1457     usage += ('\tIn this example, the LUT will be applied in the '
1458               'ACEScc colorspace, but the user could choose other spaces '
1459               'by changing the argument after the name of the look. \n')
1460     usage += '\n'
1461
1462     look_info = []
1463
1464     def look_info_callback(option, opt_str, value, parser):
1465         print('look_info_callback')
1466         print(option, opt_str, value, parser)
1467         if opt_str == '--addCustomLookCDL':
1468             look_info.append(value)
1469         elif opt_str == '--addCustomLookLUT':
1470             look_info.append(value)
1471         elif opt_str == '--addACESLookCDL':
1472             look_info.append([value[0], 'ACES - ACEScc', value[1], value[2]])
1473         elif opt_str == '--addACESLookLUT':
1474             look_info.append([value[0], 'ACES - ACEScc', value[1]])
1475
1476     p = optparse.OptionParser(description='',
1477                               prog='create_aces_config',
1478                               version='create_aces_config 1.0',
1479                               usage=usage)
1480     p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1481         ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1482     p.add_option('--configDir', '-c', default=os.environ.get(
1483         ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1484     p.add_option('--lutResolution1d', default=4096)
1485     p.add_option('--lutResolution3d', default=64)
1486     p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1487     p.add_option('--keepTempImages', action='store_true', default=False)
1488
1489     p.add_option('--createMultipleDisplays', action='store_true',
1490                  default=False)
1491
1492     p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1493                  action='callback', callback=look_info_callback)
1494     p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1495                  action='callback', callback=look_info_callback)
1496     p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1497                  action='callback', callback=look_info_callback)
1498     p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1499                  action='callback', callback=look_info_callback)
1500     p.add_option('--copyCustomLUTs', action='store_true', default=False)
1501
1502     options, arguments = p.parse_args()
1503
1504     aces_ctl_directory = options.acesCTLDir
1505     config_directory = options.configDir
1506     lut_resolution_1d = int(options.lutResolution1d)
1507     lut_resolution_3d = int(options.lutResolution3d)
1508     bake_secondary_luts = not options.dontBakeSecondaryLUTs
1509     cleanup_temp_images = not options.keepTempImages
1510     multiple_displays = options.createMultipleDisplays
1511     copy_custom_luts = options.copyCustomLUTs
1512
1513     print(look_info)
1514
1515     print('command line : \n%s\n' % ' '.join(sys.argv))
1516
1517     assert aces_ctl_directory is not None, (
1518         'process: No "{0}" environment variable defined or no "ACES CTL" '
1519         'directory specified'.format(
1520             ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1521
1522     assert config_directory is not None, (
1523         'process: No "{0}" environment variable defined or no configuration '
1524         'directory specified'.format(
1525             ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1526
1527     return create_ACES_config(aces_ctl_directory,
1528                               config_directory,
1529                               lut_resolution_1d,
1530                               lut_resolution_3d,
1531                               bake_secondary_luts,
1532                               multiple_displays,
1533                               look_info,
1534                               copy_custom_luts,
1535                               cleanup_temp_images)
1536
1537
1538 if __name__ == '__main__':
1539     main()