2 # -*- coding: utf-8 -*-
5 Defines objects creating the *ACES* configuration.
8 from __future__ import division
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
26 from aces_ocio.utilities import (
28 colorspace_prefixed_name,
33 __author__ = 'ACES Developers'
34 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
36 __maintainer__ = 'ACES Developers'
37 __email__ = 'aces@oscars.org'
38 __status__ = 'Production'
40 __all__ = ['ACES_OCIO_CTL_DIRECTORY_ENVIRON',
41 'ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON',
42 'set_config_default_roles',
44 'generate_OCIO_transform',
45 'add_colorspace_alias',
48 'generate_baked_LUTs',
53 ACES_OCIO_CTL_DIRECTORY_ENVIRON = 'ACES_OCIO_CTL_DIRECTORY'
54 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON = 'ACES_OCIO_CONFIGURATION_DIRECTORY'
57 def set_config_default_roles(config,
68 compositing_linear=''):
70 Sets given *OCIO* configuration default roles.
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.
84 default : str or unicode
86 matte_paint : str or unicode
87 Matte painting role title.
88 reference : str or unicode
90 scene_linear : str or unicode
91 Scene linear role title.
92 texture_paint : str or unicode
93 Texture painting role title.
102 config.setRole(ocio.Constants.ROLE_COLOR_PICKING, color_picking)
104 config.setRole(ocio.Constants.ROLE_COLOR_TIMING, color_timing)
106 config.setRole(ocio.Constants.ROLE_COMPOSITING_LOG, compositing_log)
108 config.setRole(ocio.Constants.ROLE_DATA, data)
110 config.setRole(ocio.Constants.ROLE_DEFAULT, default)
112 config.setRole(ocio.Constants.ROLE_MATTE_PAINT, matte_paint)
114 config.setRole(ocio.Constants.ROLE_REFERENCE, reference)
116 config.setRole(ocio.Constants.ROLE_TEXTURE_PAINT, texture_paint)
118 # *rendering* and *compositing_linear* roles default to the *scene_linear*
119 # value if not set explicitly.
121 config.setRole('rendering', rendering)
122 if compositing_linear:
123 config.setRole('compositing_linear', compositing_linear)
125 config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
127 config.setRole('rendering', scene_linear)
128 if not compositing_linear:
129 config.setRole('compositing_linear', scene_linear)
134 def write_config(config, config_path, sanity_check=True):
136 Writes the configuration to given path.
141 Parameter description.
146 Return value description.
154 print 'Configuration was not written due to a failed Sanity Check'
157 with open(config_path, mode='w') as fp:
158 fp.write(config.serialize())
161 def generate_OCIO_transform(transforms):
168 Parameter description.
173 Return value description.
176 direction_options = {
177 'forward': ocio.Constants.TRANSFORM_DIR_FORWARD,
178 'inverse': ocio.Constants.TRANSFORM_DIR_INVERSE}
182 for transform in transforms:
184 # *lutFile* transform
185 if transform['type'] == 'lutFile':
186 ocio_transform = ocio.FileTransform()
188 if 'path' in transform:
189 ocio_transform.setSrc(transform['path'])
191 if 'cccid' in transform:
192 ocio_transform.setCCCId(transform['cccid'])
194 if 'interpolation' in transform:
195 ocio_transform.setInterpolation(transform['interpolation'])
197 ocio_transform.setInterpolation(ocio.Constants.INTERP_BEST)
199 if 'direction' in transform:
200 ocio_transform.setDirection(
201 direction_options[transform['direction']])
203 ocio_transforms.append(ocio_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'])
212 if 'offset' in transform:
213 ocio_transform.setOffset(transform['offset'])
215 if 'direction' in transform:
216 ocio_transform.setDirection(
217 direction_options[transform['direction']])
219 ocio_transforms.append(ocio_transform)
221 # *exponent* transform
222 elif transform['type'] == 'exponent':
223 ocio_transform = ocio.ExponentTransform()
225 if 'value' in transform:
226 ocio_transform.setValue(transform['value'])
228 ocio_transforms.append(ocio_transform)
231 elif transform['type'] == 'log':
232 ocio_transform = ocio.LogTransform()
234 if 'base' in transform:
235 ocio_transform.setBase(transform['base'])
237 if 'direction' in transform:
238 ocio_transform.setDirection(
239 direction_options[transform['direction']])
241 ocio_transforms.append(ocio_transform)
243 # *colorspace* transform
244 elif transform['type'] == 'colorspace':
245 ocio_transform = ocio.ColorSpaceTransform()
247 if 'src' in transform:
248 ocio_transform.setSrc(transform['src'])
250 if 'dst' in transform:
251 ocio_transform.setDst(transform['dst'])
253 if 'direction' in transform:
254 ocio_transform.setDirection(
255 direction_options[transform['direction']])
257 ocio_transforms.append(ocio_transform)
260 elif transform['type'] == 'look':
261 ocio_transform = ocio.LookTransform()
262 if 'look' in transform:
263 ocio_transform.setLooks(transform['look'])
265 if 'src' in transform:
266 ocio_transform.setSrc(transform['src'])
268 if 'dst' in transform:
269 ocio_transform.setDst(transform['dst'])
271 if 'direction' in transform:
272 ocio_transform.setDirection(
273 direction_options[transform['direction']])
275 ocio_transforms.append(ocio_transform)
279 print('Ignoring unknown transform type : %s' % transform['type'])
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
287 transform = ocio_transforms[0]
292 def add_colorspace_aliases(config,
293 reference_colorspace,
295 colorspace_alias_names,
303 Parameter description.
308 Return value description.
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))
318 print('Adding alias colorspace space %s, alias to %s' % (
319 alias_name, colorspace.name))
321 compact_family_name = family
323 description = colorspace.description
324 if colorspace.aces_transform_id:
326 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
328 ocio_colorspace_alias = ocio.ColorSpace(
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)
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(
347 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
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(
358 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
360 config.addColorSpace(ocio_colorspace_alias)
374 Parameter description.
379 Return value description.
382 look_name, look_colorspace, look_lut, look_cccid = unpack_default(look, 4)
384 print('Adding look %s - %s' % (look_name, ', '.join(look)))
386 # Copy *look LUT* if `custom_lut_dir` is provided.
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]
393 print('Skipping LUT copy because path contains a context variable')
395 print('Adding look to config')
396 ocio_look = ocio.Look()
397 ocio_look.setName(look_name)
398 ocio_look.setProcessSpace(look_colorspace)
400 keys = {'type': 'lutFile',
402 'direction': 'forward'}
404 keys['cccid'] = look_cccid
406 ocio_transform = generate_OCIO_transform([keys])
407 ocio_look.setTransform(ocio_transform)
409 config.addLook(ocio_look)
411 print('Creating aliased colorspace')
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,
422 colorspace.from_reference_transforms = [{'type': 'look',
424 'src': reference_name,
425 'dst': reference_name,
426 'direction': 'forward'}]
428 print('Adding colorspace %s, alias to look %s to config data' % (
429 look_name, look_name))
431 config_data['colorSpaces'].append(colorspace)
436 def integrate_looks_into_views(looks,
439 multiple_displays=False):
446 Parameter description.
451 Return value description.
453 look_names = [look[0] for look in looks]
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)
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*.
468 for display, view_list in config_data['displays'].iteritems():
470 look_names_string = ''
471 for view_name, output_colorspace in view_list.iteritems():
472 if view_name == 'Output Transform':
474 print('Adding new View that incorporates looks')
476 colorspace_c = copy.deepcopy(output_colorspace)
478 for i, look_name in enumerate(look_names):
479 look_name = look_names[i]
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(
488 'src': reference_name,
489 'dst': reference_name,
490 'direction': 'forward'})
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]
498 colorspace_c.to_reference_transforms.append(
500 'look': inverse_look_name,
501 'src': reference_name,
502 'dst': reference_name,
503 'direction': 'inverse'})
505 if look_name not in config_data['looks']:
506 config_data['looks'].append(look_name)
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)]
514 print('Colorspace that incorporates looks '
515 'created : %s' % colorspace_c.name)
517 config_data['colorSpaces'].append(colorspace_c)
520 print('Adding colorspace that incorporates looks '
523 # Updating the *View* name.
524 view_list['Output Transform with %s' % look_names_string] = (
526 config_data['displays'][display] = view_list
529 def create_config(config_data,
532 multiple_displays=False,
534 custom_lut_dir=None):
541 Parameter description.
546 Return value description.
549 if look_info is None:
553 alias_colorspaces = []
555 config = ocio.Config()
557 config.setDescription('An ACES config generated from python')
559 search_path = ['luts']
561 search_path.append('custom')
562 config.setSearchPath(':'.join(search_path))
564 reference_data = config_data['referenceColorSpace']
566 # Adding the colorspace *Family* into the name which helps with
567 # applications that presenting colorspaces as one a flat list.
569 prefixed_name = colorspace_prefixed_name(reference_data)
570 prefixed_names[reference_data.name] = prefixed_name
571 reference_data.name = prefixed_name
573 print('Adding the reference color space : %s' % reference_data.name)
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)
585 config.addColorSpace(reference)
588 if reference_data.aliases:
589 # TODO: Explain context for following comment.
590 # Deferring adding alias colorspaces until end, which helps with
592 alias_colorspaces.append(
593 [reference_data, reference_data, reference_data.aliases])
598 print('Adding looks')
600 config_data['looks'] = []
602 for look in look_info:
609 integrate_looks_into_views(look_info,
616 print('Adding regular colorspaces')
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.
622 prefixed_name = colorspace_prefixed_name(colorspace)
623 prefixed_names[colorspace.name] = prefixed_name
624 colorspace.name = prefixed_name
626 print('Creating new color space : %s' % colorspace.name)
628 description = colorspace.description
629 if colorspace.aces_transform_id:
631 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
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)
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(
649 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
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(
657 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
659 config.addColorSpace(ocio_colorspace)
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])
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')
679 set_config_default_roles(
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']])
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.
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]
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]
711 if reference_data.name == role_colorspace_prefixed_name:
712 role_colorspace = reference_data
715 print( 'Adding an alias colorspace named %s, pointing to %s' % (
716 role_name, role_colorspace.name))
718 add_colorspace_aliases(
719 config, reference_data, role_colorspace, [role_name], 'Roles')
723 set_config_default_roles(
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'])
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.
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]
749 if reference_data.name == role_colorspace_name:
750 role_colorspace = reference_data
753 print('Adding an alias colorspace named %s, pointing to %s' % (
754 role_name, role_colorspace.name))
756 add_colorspace_aliases(
757 config, reference_data, role_colorspace, [role_name], 'Roles')
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)
774 print('Adding the diplays and views')
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']
782 set_config_default_roles(
784 color_picking=default_display_colorspace.name)
786 # Defining *Displays* and *Views*.
787 displays, views = [], []
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)
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)
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)
810 config.addDisplay(display, view_name, colorspace.name)
811 if not (view_name in views):
812 views.append(view_name)
813 displays.append(display)
815 # *Displays* and *Views* useful in a *GUI* context.
817 single_display_name = 'ACES'
818 displays.append(single_display_name)
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)))
825 looks = config_data['looks'] if ('looks' in config_data) else []
826 look_names = ', '.join(looks)
828 displays_views_colorspaces = []
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:
835 # We use the *Display* names as the *View* names in this
836 # case as there is a single *Display* containing all the
838 # This works for more applications than not,as of the time
839 # of this implementation.
841 # Autodesk Maya 2016 doesn't support parentheses in
843 sanitised_display = replace(display, {')': '', '(': ''})
845 # *View* with *Looks*.
846 if 'with' in view_name:
847 sanitised_display = '%s with %s' % (
848 sanitised_display, look_names)
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,
858 config.addDisplay(single_display_name,
862 if not (sanitised_display in views):
863 views.append(sanitised_display)
865 # *View* without *Looks*.
867 config.addDisplay(single_display_name,
871 if not (sanitised_display in views):
872 views.append(sanitised_display)
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
878 for display_view_colorspace in displays_views_colorspaces:
879 single_display_name, sanitised_display, colorspace_name = (
880 display_view_colorspace)
882 config.addDisplay(single_display_name,
886 if not (sanitised_display in views):
887 views.append(sanitised_display)
889 raw_display_space_name = config_data['roles']['data']
890 log_display_space_name = config_data['roles']['compositing_log']
893 raw_display_space_name = prefixed_names[raw_display_space_name]
894 log_display_space_name = prefixed_names[log_display_space_name]
896 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
898 config.addDisplay(single_display_name, 'Log', log_display_space_name)
901 config.setActiveDisplays(','.join(sorted(displays)))
902 config.setActiveViews(','.join(views))
906 # Ensuring the configuration is valid.
909 # Resetting colorspace names to their non-prefixed versions.
911 prefixed_names_inverse = {}
912 for original, prefixed in prefixed_names.iteritems():
913 prefixed_names_inverse[prefixed] = original
915 reference_data.name = prefixed_names_inverse[reference_data.name]
918 for colorspace in config_data['colorSpaces']:
919 colorspace.name = prefixed_names_inverse[colorspace.name]
921 print('Prefixed names')
922 for original, prefixed in prefixed_names.iteritems():
923 print('%s, %s' % (original, prefixed))
927 print('Inverse Lookup of Prefixed names')
928 for prefixed, original in prefixed_names_inverse.iteritems():
929 print('%s, %s' % (prefixed, original))
935 def generate_LUTs(odt_info,
940 lut_resolution_1d=4096,
941 lut_resolution_3d=64,
949 Parameter description.
954 Colorspaces and transforms converting between those colorspaces and
955 the reference colorspace, *ACES*.
958 print('generateLUTs - begin')
961 config_data['displays'] = {}
962 config_data['colorSpaces'] = []
964 # -------------------------------------------------------------------------
965 # *ACES Color Spaces*
966 # -------------------------------------------------------------------------
972 aces_log_display_space,
974 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
983 config_data['referenceColorSpace'] = aces_reference
984 config_data['roles'] = aces_roles
986 for cs in aces_colorspaces:
987 config_data['colorSpaces'].append(cs)
989 for name, data in aces_displays.iteritems():
990 config_data['displays'][name] = data
992 config_data['defaultDisplay'] = aces_default_display
993 config_data['linearDisplaySpace'] = aces_reference
994 config_data['logDisplaySpace'] = aces_log_display_space
996 # -------------------------------------------------------------------------
997 # *Camera Input Transforms*
998 # -------------------------------------------------------------------------
1000 # *ARRI Log-C* to *ACES*
1001 arri_colorspaces = arri.create_colorspaces(lut_directory,
1003 for cs in arri_colorspaces:
1004 config_data['colorSpaces'].append(cs)
1006 # *Canon-Log* to *ACES*
1007 canon_colorspaces = canon.create_colorspaces(lut_directory,
1009 for cs in canon_colorspaces:
1010 config_data['colorSpaces'].append(cs)
1012 # *GoPro Protune* to *ACES*
1013 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1015 for cs in gopro_colorspaces:
1016 config_data['colorSpaces'].append(cs)
1018 # *Panasonic V-Log* to *ACES*
1019 panasonic_colorspaces = panasonic.create_colorspaces(lut_directory,
1021 for cs in panasonic_colorspaces:
1022 config_data['colorSpaces'].append(cs)
1024 # *RED* colorspaces to *ACES*
1025 red_colorspaces = red.create_colorspaces(lut_directory,
1027 for cs in red_colorspaces:
1028 config_data['colorSpaces'].append(cs)
1031 sony_colorspaces = sony.create_colorspaces(lut_directory,
1033 for cs in sony_colorspaces:
1034 config_data['colorSpaces'].append(cs)
1036 # -------------------------------------------------------------------------
1037 # General Colorspaces
1038 # -------------------------------------------------------------------------
1039 general_colorspaces = general.create_colorspaces(lut_directory,
1041 for cs in general_colorspaces:
1042 config_data['colorSpaces'].append(cs)
1044 # The *Raw* colorspace
1045 raw = general.create_raw()
1046 config_data['colorSpaces'].append(raw)
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
1053 print('generateLUTs - end')
1058 def generate_baked_LUTs(odt_info,
1063 lut_resolution_shaper=1024,
1071 Parameter description.
1076 Return value description.
1079 odt_info_C = dict(odt_info)
1081 # Older behavior for *ODTs* that have support for full and legal ranges,
1082 # generating a LUT for both ranges.
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']
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
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
1097 del (odt_info_C[odt_ctl_name])
1100 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1101 odt_prefix = odt_values['transformUserNamePrefix']
1102 odt_name = odt_values['transformUserName']
1105 for input_space in ['ACEScc', 'ACESproxy']:
1106 args = ['--iconfig', config_path,
1109 args += ['--inputspace', 'ACES - %s' % input_space]
1110 args += ['--outputspace', 'Output - %s' % odt_name]
1112 args += ['--inputspace', input_space]
1113 args += ['--outputspace', odt_name]
1115 args += ['--description',
1116 '%s - %s for %s data' % (odt_prefix,
1120 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1121 '--shapersize', str(lut_resolution_shaper)]
1123 args += ['--shaperspace', shaper_name,
1124 '--shapersize', str(lut_resolution_shaper)]
1125 args += ['--cubesize', str(lut_resolution_3d)]
1126 args += ['--format',
1128 os.path.join(baked_directory,
1130 '%s for %s.icc' % (odt_name, input_space))]
1132 bake_lut = Process(description='bake a LUT',
1138 for input_space in ['ACEScc', 'ACESproxy']:
1139 args = ['--iconfig', config_path,
1142 args += ['--inputspace', 'ACES - %s' % input_space]
1143 args += ['--outputspace', 'Output - %s' % odt_name]
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)]
1151 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1152 '--shapersize', str(lut_resolution_shaper)]
1154 args += ['--shaperspace', shaper_name,
1155 '--shapersize', str(lut_resolution_shaper)]
1156 args += ['--cubesize', str(lut_resolution_3d)]
1158 fargs = ['--format',
1163 '%s for %s Flame.3dl' % (odt_name, input_space))]
1164 bake_lut = Process(description='bake a LUT',
1166 args=(args + fargs))
1169 largs = ['--format',
1174 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1175 bake_lut = Process(description='bake a LUT',
1177 args=(args + largs))
1181 for input_space in ['ACEScg', 'ACES2065-1']:
1182 args = ['--iconfig', config_path,
1185 args += ['--inputspace', 'ACES - %s' % input_space]
1186 args += ['--outputspace', 'Output - %s' % odt_name]
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
1196 lin_shaper_name = shaper_name
1198 lin_shaper_name = 'Utility - %s' % lin_shaper_name
1199 args += ['--shaperspace', lin_shaper_name,
1200 '--shapersize', str(lut_resolution_shaper)]
1202 args += ['--cubesize', str(lut_resolution_3d)]
1204 margs = ['--format',
1209 '%s for %s Maya.csp' % (odt_name, input_space))]
1210 bake_lut = Process(description='bake a LUT',
1212 args=(args + margs))
1215 hargs = ['--format',
1220 '%s for %s Houdini.lut' % (odt_name, input_space))]
1221 bake_lut = Process(description='bake a LUT',
1223 args=(args + hargs))
1227 def create_config_dir(config_directory,
1228 bake_secondary_luts=False,
1229 custom_lut_dir=None):
1236 Parameter description.
1241 Return value description.
1244 lut_directory = os.path.join(config_directory, 'luts')
1245 dirs = [config_directory, lut_directory]
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')])
1256 dirs.append(os.path.join(config_directory, 'custom'))
1259 not os.path.exists(d) and os.mkdir(d)
1261 return lut_directory
1264 def create_ACES_config(aces_ctl_directory,
1266 lut_resolution_1d=4096,
1267 lut_resolution_3d=64,
1268 bake_secondary_luts=True,
1269 multiple_displays=False,
1271 copy_custom_luts=True,
1273 prefix_colorspaces_with_family_names=True):
1275 Creates the ACES configuration.
1280 Parameter description.
1285 Return value description.
1288 if look_info is None:
1291 custom_lut_dir = None
1292 if copy_custom_luts:
1293 custom_lut_dir = os.path.join(config_directory, 'custom')
1295 lut_directory = create_config_dir(config_directory,
1296 bake_secondary_luts,
1299 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1300 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1302 shaper_name = 'Output Shaper'
1303 config_data = generate_LUTs(odt_info,
1312 print('Creating config - with prefixes, with aliases')
1313 config = create_config(config_data,
1314 prefix=prefix_colorspaces_with_family_names,
1316 multiple_displays=multiple_displays,
1317 look_info=look_info,
1318 custom_lut_dir=custom_lut_dir)
1321 write_config(config,
1322 os.path.join(config_directory, 'config.ocio'))
1324 if bake_secondary_luts:
1325 generate_baked_LUTs(odt_info,
1327 os.path.join(config_directory, 'baked'),
1328 os.path.join(config_directory, 'config.ocio'),
1331 prefix=prefix_colorspaces_with_family_names)
1343 Parameter description.
1348 Return value description.
1353 usage = '%prog [options]\n'
1355 usage += 'An OCIO config generation script for ACES 1.0\n'
1357 usage += 'Command line examples'
1359 usage += ('Create a GUI-friendly ACES 1.0 config with no secondary, '
1361 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1362 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1363 '--dontBakeSecondaryLUTs')
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')
1371 usage += 'Adding custom looks'
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')
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')
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')
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')
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')
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')
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]])
1422 p = optparse.OptionParser(description='',
1423 prog='create_aces_config',
1424 version='create_aces_config 1.0',
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)
1435 p.add_option('--createMultipleDisplays', action='store_true',
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)
1448 options, arguments = p.parse_args()
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
1461 print('command line : \n%s\n' % ' '.join(sys.argv))
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))
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))
1473 return create_ACES_config(aces_ctl_directory,
1477 bake_secondary_luts,
1481 cleanup_temp_images)
1484 if __name__ == '__main__':