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