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 interpolation_options = {
177 'linear': ocio.Constants.INTERP_LINEAR,
178 'nearest': ocio.Constants.INTERP_NEAREST,
179 'tetrahedral': ocio.Constants.INTERP_TETRAHEDRAL}
181 direction_options = {
182 'forward': ocio.Constants.TRANSFORM_DIR_FORWARD,
183 'inverse': ocio.Constants.TRANSFORM_DIR_INVERSE}
187 for transform in transforms:
190 if transform['type'] == 'lutFile':
192 ocio_transform = ocio.FileTransform()
194 if 'path' in transform:
195 ocio_transform.setSrc(transform['path'])
197 if 'cccid' in transform:
198 ocio_transform.setCCCId(transform['cccid'])
200 if 'interpolation' in transform:
201 ocio_transform.setInterpolation(transform['interpolation'])
203 ocio_transform.setInterpolation(ocio.Constants.INTERP_BEST)
205 if 'direction' in transform:
206 ocio_transform.setDirection(
207 direction_options[transform['direction']])
209 ocio_transforms.append(ocio_transform)
212 elif transform['type'] == 'matrix':
213 ocio_transform = ocio.MatrixTransform()
214 # MatrixTransform member variables can't be initialized directly.
215 # Each must be set individually.
216 ocio_transform.setMatrix(transform['matrix'])
218 if 'offset' in transform:
219 ocio_transform.setOffset(transform['offset'])
221 if 'direction' in transform:
222 ocio_transform.setDirection(
223 direction_options[transform['direction']])
225 ocio_transforms.append(ocio_transform)
228 elif transform['type'] == 'exponent':
229 ocio_transform = ocio.ExponentTransform()
231 if 'value' in transform:
232 ocio_transform.setValue(transform['value'])
234 ocio_transforms.append(ocio_transform)
237 elif transform['type'] == 'log':
238 ocio_transform = ocio.LogTransform()
240 if 'base' in transform:
241 ocio_transform.setBase(transform['base'])
243 if 'direction' in transform:
244 ocio_transform.setDirection(
245 direction_options[transform['direction']])
247 ocio_transforms.append(ocio_transform)
249 # color space transform
250 elif transform['type'] == 'colorspace':
251 ocio_transform = ocio.ColorSpaceTransform()
253 if 'src' in transform:
254 ocio_transform.setSrc(transform['src'])
256 if 'dst' in transform:
257 ocio_transform.setDst(transform['dst'])
259 if 'direction' in transform:
260 ocio_transform.setDirection(
261 direction_options[transform['direction']])
263 ocio_transforms.append(ocio_transform)
266 elif transform['type'] == 'look':
267 ocio_transform = ocio.LookTransform()
268 if 'look' in transform:
269 ocio_transform.setLooks(transform['look'])
271 if 'src' in transform:
272 ocio_transform.setSrc(transform['src'])
274 if 'dst' in transform:
275 ocio_transform.setDst(transform['dst'])
277 if 'direction' in transform:
278 ocio_transform.setDirection(
279 direction_options[transform['direction']])
281 ocio_transforms.append(ocio_transform)
285 print('Ignoring unknown transform type : %s' % transform['type'])
287 if len(ocio_transforms) > 1:
288 group_transform = ocio.GroupTransform()
289 for transform in ocio_transforms:
290 group_transform.push_back(transform)
291 transform = group_transform
293 transform = ocio_transforms[0]
298 def add_colorspace_aliases(config,
299 reference_colorspace,
301 colorspace_alias_names,
309 Parameter description.
314 Return value description.
317 for alias_name in colorspace_alias_names:
318 if alias_name.lower() == colorspace.name.lower():
319 print('Skipping alias creation for %s, alias %s, '
320 'because lower cased names match' % (
321 colorspace.name, alias_name))
324 print('Adding alias colorspace space %s, alias to %s' % (
325 alias_name, colorspace.name))
327 compact_family_name = family
329 description = colorspace.description
330 if colorspace.aces_transform_id:
332 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
334 ocio_colorspace_alias = ocio.ColorSpace(
336 bitDepth=colorspace.bit_depth,
337 description=description,
338 equalityGroup=colorspace.equality_group,
339 family=compact_family_name,
340 isData=colorspace.is_data,
341 allocation=colorspace.allocation_type,
342 allocationVars=colorspace.allocation_vars)
344 if colorspace.to_reference_transforms:
345 print('\tGenerating To-Reference transforms')
346 ocio_transform = generate_OCIO_transform(
347 [{'type': 'colorspace',
348 'src': colorspace.name,
349 'dst': reference_colorspace.name,
350 'direction': 'forward'}])
351 ocio_colorspace_alias.setTransform(
353 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
355 if colorspace.from_reference_transforms:
356 print('\tGenerating From-Reference transforms')
357 ocio_transform = generate_OCIO_transform(
358 [{'type': 'colorspace',
359 'src': reference_colorspace.name,
360 'dst': colorspace.name,
361 'direction': 'forward'}])
362 ocio_colorspace_alias.setTransform(
364 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
366 config.addColorSpace(ocio_colorspace_alias)
375 multiple_displays=False):
382 Parameter description.
387 Return value description.
390 look_name, look_colorspace, look_lut, look_cccid = unpack_default(look, 4)
392 print('Adding look %s - %s' % (look_name, ', '.join(look)))
398 if '$' not in look_lut:
399 print('Getting ready to copy look lut : %s' % look_lut)
400 shutil.copy2(look_lut, custom_lut_dir)
401 look_lut = os.path.split(look_lut)[1]
403 print('Skipping LUT copy because path contains a context variable')
409 print('Adding look to config')
411 lk1.setName(look_name)
412 lk1.setProcessSpace(look_colorspace)
414 keys = {'type': 'lutFile',
416 'direction': 'forward'}
418 keys['cccid'] = look_cccid
420 ocio_transform = generate_OCIO_transform([keys])
421 lk1.setTransform(ocio_transform)
426 print('Creating aliased colorspace')
429 # Create OCIO colorspace that references that look
430 # - Needed for some implementations that don't process looks well
431 # - Also needed for some implementations that don't expose looks well
433 look_aliases = ['look_%s' % compact(look_name)]
434 colorspace = ColorSpace(look_name,
435 aliases=look_aliases,
436 description='The %s Look colorspace' % look_name,
439 colorspace.from_reference_transforms = [{'type': 'look',
441 'src': reference_name,
442 'dst': reference_name,
443 'direction': 'forward'}]
445 print('Adding colorspace %s, alias to look %s to config data' % (
446 look_name, look_name))
448 # Add this colorspace into the main list of colorspaces
449 config_data['colorSpaces'].append(colorspace)
454 def integrate_looks_into_views(config,
458 multiple_displays=False):
465 Parameter description.
470 Return value description.
472 look_names = [look[0] for look in looks]
474 # Option 1 - Add a 'look' to each Display
475 # - Assumes there is a Display for each ACES Output Transform
476 if multiple_displays:
477 for look_name in look_names:
478 config_data['looks'].append(look_name)
481 # - Copy each Output Transform colorspace
482 # - For each copy, add a LookTransform at the head of the from_reference
484 # - Add these new copied colorspaces for the Displays / Views
486 for display, view_list in config_data['displays'].iteritems():
487 output_colorspace_c = None
488 look_names_string = ''
489 for view_name, output_colorspace in view_list.iteritems():
490 if view_name == 'Output Transform':
492 print('Adding new View that incorporates looks')
494 # Make a copy of the output colorspace
495 output_colorspace_c = copy.deepcopy(output_colorspace)
497 # for look_name in look_names:
498 for i in range(len(look_names)):
499 look_name = look_names[i]
501 # Add the LookTransform to the head of the
502 # from_reference transform list.
503 if output_colorspace_c.from_reference_transforms:
504 output_colorspace_c.from_reference_transforms.insert(
507 'src': reference_name,
508 'dst': reference_name,
509 'direction': 'forward'})
511 # Add the LookTransform to the end of
512 # the to_reference transform list.
513 if output_colorspace_c.to_reference_transforms:
514 inverse_look_name = look_names[
515 len(look_names) - 1 - i]
517 output_colorspace_c.to_reference_transforms.append(
519 'look': inverse_look_name,
520 'src': reference_name,
521 'dst': reference_name,
522 'direction': 'inverse'})
524 if look_name not in config_data['looks']:
525 config_data['looks'].append(look_name)
527 look_names_string = ', '.join(look_names)
528 output_colorspace_c.name = '%s with %s' % (
529 output_colorspace.name, look_names_string)
530 output_colorspace_c.aliases = [
531 'out_%s' % compact(output_colorspace_c.name)]
533 print('Colorspace that incorporates looks '
534 'created : %s' % output_colorspace_c.name)
536 config_data['colorSpaces'].append(output_colorspace_c)
538 if output_colorspace_c:
539 print('Adding colorspace that incorporates looks '
542 # Change the name of the View
543 view_list['Output Transform with %s' % look_names_string] = (
545 config_data['displays'][display] = view_list
547 # print('Display : %s, View List : %s' % (
548 # display, ', '.join(view_list)) )
551 def create_config(config_data,
554 multiple_displays=False,
556 custom_lut_dir=None):
563 Parameter description.
568 Return value description.
571 if look_info is None:
575 alias_colorspaces = []
577 # Creating the *OCIO* configuration.
578 config = ocio.Config()
580 # Setting configuration description.
581 config.setDescription('An ACES config generated from python')
583 # Setting configuration search path.
584 searchPath = ['luts']
586 searchPath.append('custom')
587 config.setSearchPath(':'.join(searchPath))
589 # Defining the reference colorspace.
590 reference_data = config_data['referenceColorSpace']
592 # Adding the color space Family into the name
593 # Helps with applications that present colorspaces as one long list
595 prefixed_name = colorspace_prefixed_name(reference_data)
596 prefixed_names[reference_data.name] = prefixed_name
597 reference_data.name = prefixed_name
599 print('Adding the reference color space : %s' % reference_data.name)
601 reference = ocio.ColorSpace(
602 name=reference_data.name,
603 bitDepth=reference_data.bit_depth,
604 description=reference_data.description,
605 equalityGroup=reference_data.equality_group,
606 family=reference_data.family,
607 isData=reference_data.is_data,
608 allocation=reference_data.allocation_type,
609 allocationVars=reference_data.allocation_vars)
611 config.addColorSpace(reference)
615 if reference_data.aliases:
616 # add_colorspace_alias(config, reference_data,
617 # reference_data, reference_data.aliases)
618 # defer adding alias colorspaces until end.
619 # Helps with some applications.
620 alias_colorspaces.append(
621 [reference_data, reference_data, reference_data.aliases])
625 # print('color spaces : %s' % [
626 # x.name for x in sorted(config_data['colorSpaces'])])
629 # Add Looks and Look colorspaces
632 print('Adding looks')
634 config_data['looks'] = []
636 # Add looks and colorspaces
637 for look in look_info:
645 # Integrate looks with displays, views
646 integrate_looks_into_views(config,
654 print('Adding the regular color spaces')
656 # Creating the remaining colorspaces.
657 for colorspace in sorted(config_data['colorSpaces']):
658 # Adding the color space Family into the name
659 # Helps with applications that present colorspaces as one long list
661 prefixed_name = colorspace_prefixed_name(colorspace)
662 prefixed_names[colorspace.name] = prefixed_name
663 colorspace.name = prefixed_name
665 print('Creating new color space : %s' % colorspace.name)
667 description = colorspace.description
668 if colorspace.aces_transform_id:
670 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
672 ocio_colorspace = ocio.ColorSpace(
673 name=colorspace.name,
674 bitDepth=colorspace.bit_depth,
675 description=description,
676 equalityGroup=colorspace.equality_group,
677 family=colorspace.family,
678 isData=colorspace.is_data,
679 allocation=colorspace.allocation_type,
680 allocationVars=colorspace.allocation_vars)
682 if colorspace.to_reference_transforms:
683 print('\tGenerating To-Reference transforms')
684 ocio_transform = generate_OCIO_transform(
685 colorspace.to_reference_transforms)
686 ocio_colorspace.setTransform(
688 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
690 if colorspace.from_reference_transforms:
691 print('\tGenerating From-Reference transforms')
692 ocio_transform = generate_OCIO_transform(
693 colorspace.from_reference_transforms)
694 ocio_colorspace.setTransform(
696 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
698 config.addColorSpace(ocio_colorspace)
701 # Add alias to normal colorspace, using compact name
704 if colorspace.aliases:
705 # add_colorspace_alias(config, reference_data,
706 # colorspace, colorspace.aliases)
707 # defer adding alias colorspaces until end.
708 # Helps with some applications.
709 alias_colorspaces.append(
710 [reference_data, colorspace, colorspace.aliases])
717 # We add roles early so we can create alias colorspaces with the names
718 # of the roles before the rest of the colorspace aliases are added
720 print('Setting the roles')
723 set_config_default_roles(
725 color_picking=prefixed_names[
726 config_data['roles']['color_picking']],
727 color_timing=prefixed_names[config_data['roles']['color_timing']],
728 compositing_log=prefixed_names[
729 config_data['roles']['compositing_log']],
730 data=prefixed_names[config_data['roles']['data']],
731 default=prefixed_names[config_data['roles']['default']],
732 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
733 reference=prefixed_names[config_data['roles']['reference']],
734 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
735 texture_paint=prefixed_names[
736 config_data['roles']['texture_paint']])
738 # Not allowed for the moment. role names can not overlap
739 # with colorspace names.
741 # Add the aliased colorspaces for each role
742 for role_name, role_colorspace_name in config_data['roles'].iteritems():
743 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
745 print( 'Finding colorspace : %s' % role_colorspace_prefixed_name )
746 # Find the colorspace pointed to by the role
747 role_colorspaces = [colorspace
748 for colorspace in config_data['colorSpaces']
749 if colorspace.name == role_colorspace_prefixed_name]
750 role_colorspace = None
751 if len(role_colorspaces) > 0:
752 role_colorspace = role_colorspaces[0]
754 if reference_data.name == role_colorspace_prefixed_name:
755 role_colorspace = reference_data
758 print( 'Adding an alias colorspace named %s, pointing to %s' % (
759 role_name, role_colorspace.name))
761 add_colorspace_aliases(
762 config, reference_data, role_colorspace, [role_name], 'Roles')
766 set_config_default_roles(
768 color_picking=config_data['roles']['color_picking'],
769 color_timing=config_data['roles']['color_timing'],
770 compositing_log=config_data['roles']['compositing_log'],
771 data=config_data['roles']['data'],
772 default=config_data['roles']['default'],
773 matte_paint=config_data['roles']['matte_paint'],
774 reference=config_data['roles']['reference'],
775 scene_linear=config_data['roles']['scene_linear'],
776 texture_paint=config_data['roles']['texture_paint'])
778 # Not allowed for the moment. role names can not overlap
779 # with colorspace names.
781 # Add the aliased colorspaces for each role
782 for role_name, role_colorspace_name in config_data['roles'].iteritems():
783 # Find the colorspace pointed to by the role
784 role_colorspaces = [colorspace
785 for colorspace in config_data['colorSpaces']
786 if colorspace.name == role_colorspace_name]
787 role_colorspace = None
788 if len(role_colorspaces) > 0:
789 role_colorspace = role_colorspaces[0]
791 if reference_data.name == role_colorspace_name:
792 role_colorspace = reference_data
795 print( 'Adding an alias colorspace named %s, pointing to %s' % (
796 role_name, role_colorspace.name))
798 add_colorspace_aliases(
799 config, reference_data, role_colorspace, [role_name], 'Roles')
804 # We add these at the end as some applications use the order of the
805 # colorspaces definitions in the config to order the colorspaces
806 # in their selection lists.
807 # Other go alphabetically. This should keep the alias colorspaces out
808 # of the way for the apps that use the order of definition in the config.
809 print('Adding the alias colorspaces')
810 for reference, colorspace, aliases in alias_colorspaces:
811 add_colorspace_aliases(config, reference, colorspace, aliases)
815 print('Adding the diplays and views')
817 # Set the color_picking role to be
818 # the first Display's Output Transform View.
819 default_display_name = config_data['defaultDisplay']
820 default_display_views = config_data['displays'][default_display_name]
821 default_display_colorspace = default_display_views['Output Transform']
823 set_config_default_roles(
825 color_picking=default_display_colorspace.name)
827 # Defining the *views* and *displays*.
831 # Defining a *generic* *display* and *view* setup.
832 if multiple_displays:
833 # Built list of looks to add to Displays
834 looks = config_data['looks'] if ('looks' in config_data) else []
835 looks = ', '.join(looks)
836 print('Creating multiple displays, with looks : %s' % looks)
838 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
839 # because OCIO will order them alphabetically
840 # when the config is written to disk.
842 # Create Displays, Views
843 for display, view_list in config_data['displays'].iteritems():
844 for view_name, colorspace in view_list.iteritems():
845 config.addDisplay(display, view_name, colorspace.name, looks)
846 if 'Output Transform' in view_name and looks != '':
847 # Add normal View, without looks
848 config.addDisplay(display, view_name, colorspace.name)
850 # Add View with looks
851 view_name_with_looks = '%s with %s' % (view_name, looks)
852 config.addDisplay(display, view_name_with_looks,
853 colorspace.name, looks)
855 config.addDisplay(display, view_name, colorspace.name)
856 if not (view_name in views):
857 views.append(view_name)
858 displays.append(display)
860 # Defining the set of *views* and *displays* useful in a *GUI* context.
862 single_display_name = 'ACES'
863 # single_display_name = config_data['roles']['scene_linear']
864 displays.append(single_display_name)
866 # Make sure the default display is first
867 display_names = sorted(config_data['displays'])
868 display_names.insert(0, display_names.pop(
869 display_names.index(default_display_name)))
871 # Built list of looks to add to Displays
872 looks = config_data['looks'] if ('looks' in config_data) else []
873 look_names = ', '.join(looks)
875 displays_views_colorspaces = []
877 # Create Displays, Views
878 for display in display_names:
879 view_list = config_data['displays'][display]
880 for view_name, colorspace in view_list.iteritems():
881 if 'Output Transform' in view_name:
882 # print( 'Adding view for %s' % colorspace.name )
884 # We use the Display names as the View names in this case
885 # as there is a single Display that contains all views.
886 # This works for more applications than not,
887 # as of the time of this implementation.
889 # Maya 2016 doesn't like parentheses in View names
890 display_cleaned = replace(display, {')': '', '(': ''})
892 # If View includes looks
893 if 'with' in view_name:
894 # Integrate looks into view name
895 display_cleaned = '%s with %s' % (
896 display_cleaned, look_names)
898 viewsWithLooksAtEnd = False
899 # Storing combo of display, view and colorspace name
900 # in a list so we can add them to the end of the list.
901 if viewsWithLooksAtEnd:
902 displays_views_colorspaces.append(
903 [single_display_name, display_cleaned,
908 config.addDisplay(single_display_name,
909 display_cleaned, colorspace.name)
912 if not (display_cleaned in views):
913 views.append(display_cleaned)
917 config.addDisplay(single_display_name, display_cleaned,
921 if not (display_cleaned in views):
922 views.append(display_cleaned)
924 # Add to config any display, view combinations that were saved
925 # for later. This list will be empty unless viewsWithLooksAtEnd is
927 for display_view_colorspace in displays_views_colorspaces:
928 single_display_name, display_cleaned, colorspace_name = (
929 display_view_colorspace)
932 config.addDisplay(single_display_name, display_cleaned,
936 if not (display_cleaned in views):
937 views.append(display_cleaned)
940 # Works with Nuke Studio and Mari, but not Nuke
941 # single_display_name = 'Utility'
942 # displays.append(single_display_name)
944 raw_display_space_name = config_data['roles']['data']
945 log_display_space_name = config_data['roles']['compositing_log']
947 # Find the newly-prefixed colorspace names
949 # print( prefixed_names )
950 raw_display_space_name = prefixed_names[raw_display_space_name]
951 log_display_space_name = prefixed_names[log_display_space_name]
953 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
955 config.addDisplay(single_display_name, 'Log', log_display_space_name)
958 # Setting the active *displays* and *views*.
959 config.setActiveDisplays(','.join(sorted(displays)))
960 config.setActiveViews(','.join(views))
964 # Make sure we didn't create a bad config
967 # Reset the colorspace names back to their non-prefixed versions
969 # Build the reverse lookup
970 prefixed_names_inverse = {}
971 for original, prefixed in prefixed_names.iteritems():
972 prefixed_names_inverse[prefixed] = original
974 # Reset the reference colorspace name
975 reference_data.name = prefixed_names_inverse[reference_data.name]
977 # Reset the rest of the colorspace names
979 for colorspace in config_data['colorSpaces']:
980 colorspace.name = prefixed_names_inverse[colorspace.name]
982 print('Prefixed names')
983 for original, prefixed in prefixed_names.iteritems():
984 print('%s, %s' % (original, prefixed))
988 print('Inverse Lookup of Prefixed names')
989 for prefixed, original in prefixed_names_inverse.iteritems():
990 print('%s, %s' % (prefixed, original))
996 def generate_LUTs(odt_info,
1001 lut_resolution_1d=4096,
1002 lut_resolution_3d=64,
1010 Parameter description.
1015 Colorspaces and transforms converting between those colorspaces and
1016 the reference colorspace, *ACES*.
1019 print('generateLUTs - begin')
1022 # Initialize a few variables
1023 config_data['displays'] = {}
1024 config_data['colorSpaces'] = []
1026 # -------------------------------------------------------------------------
1027 # *ACES Color Spaces*
1028 # -------------------------------------------------------------------------
1030 # *ACES* colorspaces
1034 aces_log_display_space,
1036 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1045 config_data['referenceColorSpace'] = aces_reference
1046 config_data['roles'] = aces_roles
1048 for cs in aces_colorspaces:
1049 config_data['colorSpaces'].append(cs)
1051 for name, data in aces_displays.iteritems():
1052 config_data['displays'][name] = data
1054 config_data['defaultDisplay'] = aces_default_display
1055 config_data['linearDisplaySpace'] = aces_reference
1056 config_data['logDisplaySpace'] = aces_log_display_space
1058 # -------------------------------------------------------------------------
1059 # *Camera Input Transforms*
1060 # -------------------------------------------------------------------------
1062 # *ARRI Log-C* to *ACES*.
1063 arri_colorSpaces = arri.create_colorspaces(lut_directory,
1065 for cs in arri_colorSpaces:
1066 config_data['colorSpaces'].append(cs)
1068 # *Canon-Log* to *ACES*.
1069 canon_colorspaces = canon.create_colorspaces(lut_directory,
1071 for cs in canon_colorspaces:
1072 config_data['colorSpaces'].append(cs)
1074 # *GoPro Protune* to *ACES*.
1075 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1077 for cs in gopro_colorspaces:
1078 config_data['colorSpaces'].append(cs)
1080 # *Panasonic V-Log* to *ACES*.
1081 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1083 for cs in panasonic_colorSpaces:
1084 config_data['colorSpaces'].append(cs)
1086 # *RED* colorspaces to *ACES*.
1087 red_colorspaces = red.create_colorspaces(lut_directory,
1089 for cs in red_colorspaces:
1090 config_data['colorSpaces'].append(cs)
1092 # *S-Log* to *ACES*.
1093 sony_colorSpaces = sony.create_colorspaces(lut_directory,
1095 for cs in sony_colorSpaces:
1096 config_data['colorSpaces'].append(cs)
1098 # -------------------------------------------------------------------------
1099 # General Color Spaces
1100 # -------------------------------------------------------------------------
1101 general_colorSpaces = general.create_colorspaces(lut_directory,
1104 for cs in general_colorSpaces:
1105 config_data['colorSpaces'].append(cs)
1107 # The *Raw* color space
1108 raw = general.create_raw()
1109 config_data['colorSpaces'].append(raw)
1111 # Override certain roles, for now
1112 config_data['roles']['data'] = raw.name
1113 config_data['roles']['reference'] = raw.name
1114 config_data['roles']['texture_paint'] = raw.name
1116 print('generateLUTs - end')
1120 def generate_baked_LUTs(odt_info,
1126 lut_resolution_shaper=1024,
1134 Parameter description.
1139 Return value description.
1142 odt_info_C = dict(odt_info)
1144 # Uncomment if you would like to support the older behavior where ODTs
1145 # that have support for full and legal range output generate
1148 # Create two entries for ODTs that have full and legal range support
1149 for odt_ctl_name, odt_values in odt_info.iteritems():
1150 if odt_values['transformHasFullLegalSwitch']:
1151 odt_name = odt_values['transformUserName']
1153 odt_values_legal = dict(odt_values)
1154 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1155 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1157 odt_values_full = dict(odt_values)
1158 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1159 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1161 del (odt_info_C[odt_ctl_name])
1164 # Generate appropriate LUTs for each ODT
1165 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1166 odt_prefix = odt_values['transformUserNamePrefix']
1167 odt_name = odt_values['transformUserName']
1170 for input_space in ['ACEScc', 'ACESproxy']:
1171 args = ['--iconfig', config_path,
1174 args += ['--inputspace', 'ACES - %s' % input_space]
1175 args += ['--outputspace', 'Output - %s' % odt_name]
1177 args += ['--inputspace', input_space]
1178 args += ['--outputspace', odt_name]
1180 args += ['--description',
1181 '%s - %s for %s data' % (odt_prefix,
1185 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1186 '--shapersize', str(lut_resolution_shaper)]
1188 args += ['--shaperspace', shaper_name,
1189 '--shapersize', str(lut_resolution_shaper)]
1190 args += ['--cubesize', str(lut_resolution_3d)]
1191 args += ['--format',
1193 os.path.join(baked_directory,
1195 '%s for %s.icc' % (odt_name, input_space))]
1197 bake_lut = Process(description='bake a LUT',
1203 for input_space in ['ACEScc', 'ACESproxy']:
1204 args = ['--iconfig', config_path,
1207 args += ['--inputspace', 'ACES - %s' % input_space]
1208 args += ['--outputspace', 'Output - %s' % odt_name]
1210 args += ['--inputspace', input_space]
1211 args += ['--outputspace', odt_name]
1212 args += ['--description',
1213 '%s - %s for %s data' % (
1214 odt_prefix, odt_name, input_space)]
1216 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1217 '--shapersize', str(lut_resolution_shaper)]
1219 args += ['--shaperspace', shaper_name,
1220 '--shapersize', str(lut_resolution_shaper)]
1221 args += ['--cubesize', str(lut_resolution_3d)]
1223 fargs = ['--format',
1228 '%s for %s Flame.3dl' % (odt_name, input_space))]
1229 bake_lut = Process(description='bake a LUT',
1231 args=(args + fargs))
1234 largs = ['--format',
1239 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1240 bake_lut = Process(description='bake a LUT',
1242 args=(args + largs))
1246 for input_space in ['ACEScg', 'ACES2065-1']:
1247 args = ['--iconfig', config_path,
1250 args += ['--inputspace', 'ACES - %s' % input_space]
1251 args += ['--outputspace', 'Output - %s' % odt_name]
1253 args += ['--inputspace', input_space]
1254 args += ['--outputspace', odt_name]
1255 args += ['--description',
1256 '%s - %s for %s data' % (
1257 odt_prefix, odt_name, input_space)]
1258 if input_space == 'ACEScg':
1259 lin_shaper_name = '%s - AP1' % shaper_name
1261 lin_shaper_name = shaper_name
1263 lin_shaper_name = 'Utility - %s' % lin_shaper_name
1264 args += ['--shaperspace', lin_shaper_name,
1265 '--shapersize', str(lut_resolution_shaper)]
1267 args += ['--cubesize', str(lut_resolution_3d)]
1269 margs = ['--format',
1274 '%s for %s Maya.csp' % (odt_name, input_space))]
1275 bake_lut = Process(description='bake a LUT',
1277 args=(args + margs))
1280 hargs = ['--format',
1285 '%s for %s Houdini.lut' % (odt_name, input_space))]
1286 bake_lut = Process(description='bake a LUT',
1288 args=(args + hargs))
1292 def create_config_dir(config_directory,
1293 bake_secondary_LUTs=False,
1294 custom_lut_dir=None):
1301 Parameter description.
1306 Return value description.
1309 lut_directory = os.path.join(config_directory, 'luts')
1310 dirs = [config_directory, lut_directory]
1312 if bake_secondary_LUTs:
1313 dirs.extend([os.path.join(config_directory, 'baked'),
1314 os.path.join(config_directory, 'baked', 'flame'),
1315 os.path.join(config_directory, 'baked', 'photoshop'),
1316 os.path.join(config_directory, 'baked', 'houdini'),
1317 os.path.join(config_directory, 'baked', 'lustre'),
1318 os.path.join(config_directory, 'baked', 'maya')])
1321 dirs.append(os.path.join(config_directory, 'custom'))
1324 not os.path.exists(d) and os.mkdir(d)
1326 return lut_directory
1329 def create_ACES_config(aces_ctl_directory,
1331 lut_resolution_1d=4096,
1332 lut_resolution_3d=64,
1333 bake_secondary_LUTs=True,
1334 multiple_displays=False,
1336 copy_custom_luts=True,
1338 prefix_colorspaces_with_family_names=True):
1340 Creates the ACES configuration.
1345 Parameter description.
1350 Return value description.
1353 if look_info is None:
1356 # Directory for custom LUTs
1357 custom_lut_dir = None
1358 if copy_custom_luts:
1359 custom_lut_dir = os.path.join(config_directory, 'custom')
1361 lut_directory = create_config_dir(config_directory,
1362 bake_secondary_LUTs,
1365 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1366 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1368 shaper_name = 'Output Shaper'
1369 config_data = generate_LUTs(odt_info,
1378 print('Creating config - with prefixes, with aliases')
1379 config = create_config(config_data,
1380 prefix=prefix_colorspaces_with_family_names,
1382 multiple_displays=multiple_displays,
1383 look_info=look_info,
1384 custom_lut_dir=custom_lut_dir)
1387 write_config(config,
1388 os.path.join(config_directory, 'config.ocio'))
1390 if bake_secondary_LUTs:
1391 generate_baked_LUTs(odt_info,
1393 os.path.join(config_directory, 'baked'),
1394 os.path.join(config_directory, 'config.ocio'),
1398 prefix=prefix_colorspaces_with_family_names)
1410 Parameter description.
1415 Return value description.
1420 usage = '%prog [options]\n'
1422 usage += 'An OCIO config generation script for ACES 1.0\n'
1424 usage += 'Command line examples'
1426 usage += ('Create a GUI-friendly ACES 1.0 config with no secondary, '
1428 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1429 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1430 '--dontBakeSecondaryLUTs')
1432 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1433 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1434 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1435 '--createMultipleDisplays')
1438 usage += 'Adding custom looks'
1440 usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style CDL '
1441 '(will be applied in the ACEScc colorspace): \n')
1442 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1443 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1444 '\n\t\t--addACESLookCDL ACESCDLName '
1445 '/path/to/SampleCDL.ccc cc03345')
1447 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1448 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1449 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1450 '\n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" '
1451 '/path/to/SampleCDL.ccc cc03345')
1453 usage += ('\tIn this example, the CDL will be applied in the '
1454 'ACEScc colorspace, but the user could choose other spaces '
1455 'by changing the argument after the name of the look. \n')
1457 usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style LUT '
1458 '(will be applied in the ACEScc colorspace): \n')
1459 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1460 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1461 '\n\t\t--addACESLookLUT ACESLUTName '
1462 '/path/to/SampleCDL.ccc cc03345')
1464 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1465 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1466 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1467 '\n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" '
1468 '/path/to/SampleCDL.ccc cc03345')
1470 usage += ('\tIn this example, the LUT will be applied in the '
1471 'ACEScc colorspace, but the user could choose other spaces '
1472 'by changing the argument after the name of the look. \n')
1477 def look_info_callback(option, opt_str, value, parser):
1478 print('look_info_callback')
1479 print(option, opt_str, value, parser)
1480 if opt_str == '--addCustomLookCDL':
1481 look_info.append(value)
1482 elif opt_str == '--addCustomLookLUT':
1483 look_info.append(value)
1484 elif opt_str == '--addACESLookCDL':
1485 look_info.append([value[0], 'ACES - ACEScc', value[1], value[2]])
1486 elif opt_str == '--addACESLookLUT':
1487 look_info.append([value[0], 'ACES - ACEScc', value[1]])
1489 p = optparse.OptionParser(description='',
1490 prog='create_aces_config',
1491 version='create_aces_config 1.0',
1493 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1494 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1495 p.add_option('--configDir', '-c', default=os.environ.get(
1496 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1497 p.add_option('--lutResolution1d', default=4096)
1498 p.add_option('--lutResolution3d', default=64)
1499 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1500 p.add_option('--keepTempImages', action='store_true', default=False)
1502 p.add_option('--createMultipleDisplays', action='store_true',
1505 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1506 action='callback', callback=look_info_callback)
1507 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1508 action='callback', callback=look_info_callback)
1509 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1510 action='callback', callback=look_info_callback)
1511 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1512 action='callback', callback=look_info_callback)
1513 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1515 options, arguments = p.parse_args()
1517 aces_ctl_directory = options.acesCTLDir
1518 config_directory = options.configDir
1519 lut_resolution_1d = int(options.lutResolution1d)
1520 lut_resolution_3d = int(options.lutResolution3d)
1521 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1522 cleanup_temp_images = not options.keepTempImages
1523 multiple_displays = options.createMultipleDisplays
1524 copy_custom_luts = options.copyCustomLUTs
1528 print('command line : \n%s\n' % ' '.join(sys.argv))
1530 assert aces_ctl_directory is not None, (
1531 'process: No "{0}" environment variable defined or no "ACES CTL" '
1532 'directory specified'.format(
1533 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1535 assert config_directory is not None, (
1536 'process: No "{0}" environment variable defined or no configuration '
1537 'directory specified'.format(
1538 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1540 return create_ACES_config(aces_ctl_directory,
1544 bake_secondary_luts,
1548 cleanup_temp_images)
1551 if __name__ == '__main__':