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