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