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():
320 'Skipping alias creation for %s, alias %s, 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:
331 description += '\n\nACES Transform ID : %s' % colorspace.aces_transform_id
333 ocio_colorspace_alias = ocio.ColorSpace(
335 bitDepth=colorspace.bit_depth,
336 description=description,
337 equalityGroup=colorspace.equality_group,
338 family=compact_family_name,
339 isData=colorspace.is_data,
340 allocation=colorspace.allocation_type,
341 allocationVars=colorspace.allocation_vars)
343 if colorspace.to_reference_transforms:
344 print('\tGenerating To-Reference transforms')
345 ocio_transform = generate_OCIO_transform(
346 [{'type': 'colorspace',
347 'src': colorspace.name,
348 'dst': reference_colorspace.name,
349 'direction': 'forward'}])
350 ocio_colorspace_alias.setTransform(
352 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
354 if colorspace.from_reference_transforms:
355 print('\tGenerating From-Reference transforms')
356 ocio_transform = generate_OCIO_transform(
357 [{'type': 'colorspace',
358 'src': reference_colorspace.name,
359 'dst': colorspace.name,
360 'direction': 'forward'}])
361 ocio_colorspace_alias.setTransform(
363 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
365 config.addColorSpace(ocio_colorspace_alias)
374 multiple_displays=False):
381 Parameter description.
386 Return value description.
389 look_name, look_colorspace, look_lut, look_cccid = unpack_default(look, 4)
391 print('Adding look %s - %s' % (look_name, ', '.join(look)))
397 if not '$' in look_lut:
398 print('Getting ready to copy look lut : %s' % look_lut)
399 shutil.copy2(look_lut, custom_lut_dir)
400 look_lut = os.path.split(look_lut)[1]
402 print('Skipping LUT copy because path contains a context variable')
408 print('Adding look to config')
410 lk1.setName(look_name)
411 lk1.setProcessSpace(look_colorspace)
413 keys = {'type': 'lutFile',
415 'direction': 'forward'}
417 keys['cccid'] = look_cccid
419 ocio_transform = generate_OCIO_transform([keys])
420 lk1.setTransform(ocio_transform)
425 print('Creating aliased colorspace')
428 # Create OCIO colorspace that references that look
429 # - Needed for some implementations that don't process looks well
430 # - Also needed for some implementations that don't expose looks well
432 look_aliases = ['look_%s' % compact(look_name)]
433 colorspace = ColorSpace(look_name,
434 aliases=look_aliases,
435 description='The %s Look colorspace' % look_name,
438 colorspace.from_reference_transforms = [{'type': 'look',
440 'src': reference_name,
441 'dst': reference_name,
442 'direction': 'forward'}]
444 print('Adding colorspace %s, alias to look %s to config data' % (
445 look_name, look_name))
447 # Add this colorspace into the main list of colorspaces
448 config_data['colorSpaces'].append(colorspace)
453 def integrate_looks_into_views(config,
457 multiple_displays=False):
464 Parameter description.
469 Return value description.
471 look_names = [look[0] for look in looks]
473 # Option 1 - Add a 'look' to each Display
474 # - Assumes there is a Display for each ACES Output Transform
475 if multiple_displays:
476 for look_name in look_names:
477 config_data['looks'].append(look_name)
480 # - Copy each Output Transform colorspace
481 # - For each copy, add a LookTransform at the head of the from_reference
483 # - Add these new copied colorspaces for the Displays / Views
485 for display, view_list in config_data['displays'].iteritems():
486 output_colorspace_copy = None
487 look_names_string = ''
488 for view_name, output_colorspace in view_list.iteritems():
489 if view_name == 'Output Transform':
491 print('Adding new View that incorporates looks')
493 # Make a copy of the output colorspace
494 output_colorspace_copy = copy.deepcopy(output_colorspace)
496 # for look_name in look_names:
497 for i in range(len(look_names)):
498 look_name = look_names[i]
500 # Add the LookTransform to the head of the from_reference transform list
501 if output_colorspace_copy.from_reference_transforms:
502 output_colorspace_copy.from_reference_transforms.insert(
505 'src': reference_name,
506 'dst': reference_name,
507 'direction': 'forward'})
509 # Add the LookTransform to the end of the to_reference transform list
510 if output_colorspace_copy.to_reference_transforms:
511 inverse_look_name = look_names[
512 len(look_names) - 1 - i]
514 output_colorspace_copy.to_reference_transforms.append(
516 'look': inverse_look_name,
517 'src': reference_name,
518 'dst': reference_name,
519 'direction': 'inverse'})
521 if not look_name in config_data['looks']:
522 config_data['looks'].append(look_name)
524 look_names_string = ', '.join(look_names)
525 output_colorspace_copy.name = '%s with %s' % (
526 output_colorspace.name, look_names_string)
527 output_colorspace_copy.aliases = [
528 'out_%s' % compact(output_colorspace_copy.name)]
531 'Colorspace that incorporates looks created : %s' % output_colorspace_copy.name)
533 config_data['colorSpaces'].append(output_colorspace_copy)
535 if output_colorspace_copy:
537 'Adding colorspace that incorporates looks into view list')
539 # Change the name of the View
541 'Output Transform with %s' % look_names_string] = output_colorspace_copy
542 config_data['displays'][display] = view_list
544 # print( 'Display : %s, View List : %s' % (display, ', '.join(view_list)) )
547 def create_config(config_data,
550 multiple_displays=False,
552 custom_lut_dir=None):
559 Parameter description.
564 Return value description.
567 if look_info is None:
571 alias_colorspaces = []
573 # Creating the *OCIO* configuration.
574 config = ocio.Config()
576 # Setting configuration description.
577 config.setDescription('An ACES config generated from python')
579 # Setting configuration search path.
580 searchPath = ['luts']
582 searchPath.append('custom')
583 config.setSearchPath(':'.join(searchPath))
585 # Defining the reference colorspace.
586 reference_data = config_data['referenceColorSpace']
588 # Adding the color space Family into the name
589 # Helps with applications that present colorspaces as one long list
591 prefixed_name = colorspace_prefixed_name(reference_data)
592 prefixed_names[reference_data.name] = prefixed_name
593 reference_data.name = prefixed_name
595 print('Adding the reference color space : %s' % reference_data.name)
597 reference = ocio.ColorSpace(
598 name=reference_data.name,
599 bitDepth=reference_data.bit_depth,
600 description=reference_data.description,
601 equalityGroup=reference_data.equality_group,
602 family=reference_data.family,
603 isData=reference_data.is_data,
604 allocation=reference_data.allocation_type,
605 allocationVars=reference_data.allocation_vars)
607 config.addColorSpace(reference)
611 if reference_data.aliases:
612 # add_colorspace_alias(config, reference_data,
613 # reference_data, reference_data.aliases)
614 # defer adding alias colorspaces until end. Helps with some applications
615 alias_colorspaces.append(
616 [reference_data, reference_data, reference_data.aliases])
620 # print( 'color spaces : %s' % [x.name for x in sorted(config_data['colorSpaces'])])
623 # Add Looks and Look colorspaces
626 print('Adding looks')
628 config_data['looks'] = []
630 # Add looks and colorspaces
631 for look in look_info:
639 # Integrate looks with displays, views
640 integrate_looks_into_views(config,
648 print('Adding the regular color spaces')
650 # Creating the remaining colorspaces.
651 for colorspace in sorted(config_data['colorSpaces']):
652 # Adding the color space Family into the name
653 # Helps with applications that present colorspaces as one long list
655 prefixed_name = colorspace_prefixed_name(colorspace)
656 prefixed_names[colorspace.name] = prefixed_name
657 colorspace.name = prefixed_name
659 print('Creating new color space : %s' % colorspace.name)
661 description = colorspace.description
662 if colorspace.aces_transform_id:
663 description += '\n\nACES Transform ID : %s' % colorspace.aces_transform_id
665 ocio_colorspace = ocio.ColorSpace(
666 name=colorspace.name,
667 bitDepth=colorspace.bit_depth,
668 description=description,
669 equalityGroup=colorspace.equality_group,
670 family=colorspace.family,
671 isData=colorspace.is_data,
672 allocation=colorspace.allocation_type,
673 allocationVars=colorspace.allocation_vars)
675 if colorspace.to_reference_transforms:
676 print('\tGenerating To-Reference transforms')
677 ocio_transform = generate_OCIO_transform(
678 colorspace.to_reference_transforms)
679 ocio_colorspace.setTransform(
681 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
683 if colorspace.from_reference_transforms:
684 print('\tGenerating From-Reference transforms')
685 ocio_transform = generate_OCIO_transform(
686 colorspace.from_reference_transforms)
687 ocio_colorspace.setTransform(
689 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
691 config.addColorSpace(ocio_colorspace)
694 # Add alias to normal colorspace, using compact name
697 if colorspace.aliases:
698 # add_colorspace_alias(config, reference_data,
699 # colorspace, colorspace.aliases)
700 # defer adding alias colorspaces until end. Helps with some applications
701 alias_colorspaces.append(
702 [reference_data, colorspace, colorspace.aliases])
709 # We add roles early so we can create alias colorspaces with the names of the roles
710 # before the rest of the colorspace aliases are added to the config.
712 print('Setting the roles')
715 set_config_default_roles(
717 color_picking=prefixed_names[
718 config_data['roles']['color_picking']],
719 color_timing=prefixed_names[config_data['roles']['color_timing']],
720 compositing_log=prefixed_names[
721 config_data['roles']['compositing_log']],
722 data=prefixed_names[config_data['roles']['data']],
723 default=prefixed_names[config_data['roles']['default']],
724 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
725 reference=prefixed_names[config_data['roles']['reference']],
726 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
727 texture_paint=prefixed_names[
728 config_data['roles']['texture_paint']])
730 # Not allowed for the moment. role names can not overlap with colorspace names.
732 # Add the aliased colorspaces for each role
733 for role_name, role_colorspace_name in config_data['roles'].iteritems():
734 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
736 print( 'Finding colorspace : %s' % role_colorspace_prefixed_name )
737 # Find the colorspace pointed to by the role
738 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_prefixed_name]
739 role_colorspace = None
740 if len(role_colorspaces) > 0:
741 role_colorspace = role_colorspaces[0]
743 if reference_data.name == role_colorspace_prefixed_name:
744 role_colorspace = reference_data
747 print( 'Adding an alias colorspace named %s, pointing to %s' % (
748 role_name, role_colorspace.name))
750 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
754 set_config_default_roles(
756 color_picking=config_data['roles']['color_picking'],
757 color_timing=config_data['roles']['color_timing'],
758 compositing_log=config_data['roles']['compositing_log'],
759 data=config_data['roles']['data'],
760 default=config_data['roles']['default'],
761 matte_paint=config_data['roles']['matte_paint'],
762 reference=config_data['roles']['reference'],
763 scene_linear=config_data['roles']['scene_linear'],
764 texture_paint=config_data['roles']['texture_paint'])
766 # Not allowed for the moment. role names can not overlap with colorspace names.
768 # Add the aliased colorspaces for each role
769 for role_name, role_colorspace_name in config_data['roles'].iteritems():
770 # Find the colorspace pointed to by the role
771 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_name]
772 role_colorspace = None
773 if len(role_colorspaces) > 0:
774 role_colorspace = role_colorspaces[0]
776 if reference_data.name == role_colorspace_name:
777 role_colorspace = reference_data
780 print( 'Adding an alias colorspace named %s, pointing to %s' % (
781 role_name, role_colorspace.name))
783 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
788 # We add these at the end as some applications use the order of the colorspaces
789 # definitions in the config to order the colorspaces in their selection lists.
790 # Other go alphabetically. This should keep the alias colorspaces out of the way
791 # for the apps that use the order of definition in the config.
792 print('Adding the alias colorspaces')
793 for reference, colorspace, aliases in alias_colorspaces:
794 add_colorspace_aliases(config, reference, colorspace, aliases)
798 print('Adding the diplays and views')
800 # Set the color_picking role to be the first Display's Output Transform View
801 default_display_name = config_data['defaultDisplay']
802 default_display_views = config_data['displays'][default_display_name]
803 default_display_colorspace = default_display_views['Output Transform']
805 set_config_default_roles(
807 color_picking=default_display_colorspace.name)
809 # Defining the *views* and *displays*.
813 # Defining a *generic* *display* and *view* setup.
814 if multiple_displays:
815 # Built list of looks to add to Displays
816 looks = config_data['looks'] if ('looks' in config_data) else []
817 looks = ', '.join(looks)
818 print('Creating multiple displays, with looks : %s' % looks)
820 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
821 # because OCIO will order them alphabetically when the config is written to disk.
823 # Create Displays, Views
824 for display, view_list in config_data['displays'].iteritems():
825 for view_name, colorspace in view_list.iteritems():
826 config.addDisplay(display, view_name, colorspace.name, looks)
827 if 'Output Transform' in view_name and looks != '':
828 # Add normal View, without looks
829 config.addDisplay(display, view_name, colorspace.name)
831 # Add View with looks
832 view_name_with_looks = '%s with %s' % (view_name, looks)
833 config.addDisplay(display, view_name_with_looks,
834 colorspace.name, looks)
836 config.addDisplay(display, view_name, colorspace.name)
837 if not (view_name in views):
838 views.append(view_name)
839 displays.append(display)
841 # Defining the set of *views* and *displays* useful in a *GUI* context.
843 single_display_name = 'ACES'
844 # single_display_name = config_data['roles']['scene_linear']
845 displays.append(single_display_name)
847 # Make sure the default display is first
848 display_names = sorted(config_data['displays'])
849 display_names.insert(0, display_names.pop(
850 display_names.index(default_display_name)))
852 # Built list of looks to add to Displays
853 looks = config_data['looks'] if ('looks' in config_data) else []
854 look_names = ', '.join(looks)
856 displays_views_colorspaces = []
858 # Create Displays, Views
859 for display in display_names:
860 view_list = config_data['displays'][display]
861 for view_name, colorspace in view_list.iteritems():
862 if 'Output Transform' in view_name:
863 # print( 'Adding view for %s' % colorspace.name )
865 # We use the Display names as the View names in this case
866 # as there is a single Display that contains all views.
867 # This works for more applications than not, as of the time of this implementation.
869 # Maya 2016 doesn't like parentheses in View names
870 display_cleaned = replace(display, {')': '', '(': ''})
872 # If View includes looks
873 if 'with' in view_name:
874 # Integrate looks into view name
875 display_cleaned = '%s with %s' % (
876 display_cleaned, look_names)
878 viewsWithLooksAtEnd = False
879 # Storing combo of display, view and colorspace name in a list so we can
880 # add them to the end of the list
881 if viewsWithLooksAtEnd:
882 displays_views_colorspaces.append(
883 [single_display_name, display_cleaned,
888 config.addDisplay(single_display_name,
889 display_cleaned, colorspace.name)
892 if not (display_cleaned in views):
893 views.append(display_cleaned)
897 config.addDisplay(single_display_name, display_cleaned,
901 if not (display_cleaned in views):
902 views.append(display_cleaned)
904 # Add to config any display, view combinations that were saved for later
905 # This list will be empty unless viewsWithLooksAtEnd is set to True above
906 for display_view_colorspace in displays_views_colorspaces:
907 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
910 config.addDisplay(single_display_name, display_cleaned,
914 if not (display_cleaned in views):
915 views.append(display_cleaned)
918 # Works with Nuke Studio and Mari, but not Nuke
919 # single_display_name = 'Utility'
920 # displays.append(single_display_name)
922 raw_display_space_name = config_data['roles']['data']
923 log_display_space_name = config_data['roles']['compositing_log']
925 # Find the newly-prefixed colorspace names
927 # print( prefixed_names )
928 raw_display_space_name = prefixed_names[raw_display_space_name]
929 log_display_space_name = prefixed_names[log_display_space_name]
931 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
933 config.addDisplay(single_display_name, 'Log', log_display_space_name)
936 # Setting the active *displays* and *views*.
937 config.setActiveDisplays(','.join(sorted(displays)))
938 config.setActiveViews(','.join(views))
942 # Make sure we didn't create a bad config
945 # Reset the colorspace names back to their non-prefixed versions
947 # Build the reverse lookup
948 prefixed_names_inverse = {}
949 for original, prefixed in prefixed_names.iteritems():
950 prefixed_names_inverse[prefixed] = original
952 # Reset the reference colorspace name
953 reference_data.name = prefixed_names_inverse[reference_data.name]
955 # Reset the rest of the colorspace names
957 for colorspace in config_data['colorSpaces']:
958 colorspace.name = prefixed_names_inverse[colorspace.name]
960 print('Prefixed names')
961 for original, prefixed in prefixed_names.iteritems():
962 print('%s, %s' % (original, prefixed))
966 print('Inverse Lookup of Prefixed names')
967 for prefixed, original in prefixed_names_inverse.iteritems():
968 print('%s, %s' % (prefixed, original))
974 def generate_LUTs(odt_info,
979 lut_resolution_1d=4096,
980 lut_resolution_3d=64,
988 Parameter description.
993 Colorspaces and transforms converting between those colorspaces and
994 the reference colorspace, *ACES*.
997 print('generateLUTs - begin')
1000 # Initialize a few variables
1001 config_data['displays'] = {}
1002 config_data['colorSpaces'] = []
1004 # -------------------------------------------------------------------------
1005 # *ACES Color Spaces*
1006 # -------------------------------------------------------------------------
1008 # *ACES* colorspaces
1012 aces_log_display_space,
1014 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1023 config_data['referenceColorSpace'] = aces_reference
1024 config_data['roles'] = aces_roles
1026 for cs in aces_colorspaces:
1027 config_data['colorSpaces'].append(cs)
1029 for name, data in aces_displays.iteritems():
1030 config_data['displays'][name] = data
1032 config_data['defaultDisplay'] = aces_default_display
1033 config_data['linearDisplaySpace'] = aces_reference
1034 config_data['logDisplaySpace'] = aces_log_display_space
1036 # -------------------------------------------------------------------------
1037 # *Camera Input Transforms*
1038 # -------------------------------------------------------------------------
1040 # *ARRI Log-C* to *ACES*.
1041 arri_colorSpaces = arri.create_colorspaces(lut_directory,
1043 for cs in arri_colorSpaces:
1044 config_data['colorSpaces'].append(cs)
1046 # *Canon-Log* to *ACES*.
1047 canon_colorspaces = canon.create_colorspaces(lut_directory,
1049 for cs in canon_colorspaces:
1050 config_data['colorSpaces'].append(cs)
1052 # *GoPro Protune* to *ACES*.
1053 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1055 for cs in gopro_colorspaces:
1056 config_data['colorSpaces'].append(cs)
1058 # *Panasonic V-Log* to *ACES*.
1059 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1061 for cs in panasonic_colorSpaces:
1062 config_data['colorSpaces'].append(cs)
1064 # *RED* colorspaces to *ACES*.
1065 red_colorspaces = red.create_colorspaces(lut_directory,
1067 for cs in red_colorspaces:
1068 config_data['colorSpaces'].append(cs)
1070 # *S-Log* to *ACES*.
1071 sony_colorSpaces = sony.create_colorspaces(lut_directory,
1073 for cs in sony_colorSpaces:
1074 config_data['colorSpaces'].append(cs)
1076 # -------------------------------------------------------------------------
1077 # General Color Spaces
1078 # -------------------------------------------------------------------------
1079 general_colorSpaces = general.create_colorspaces(lut_directory,
1082 for cs in general_colorSpaces:
1083 config_data['colorSpaces'].append(cs)
1085 # The *Raw* color space
1086 raw = general.create_raw()
1087 config_data['colorSpaces'].append(raw)
1089 # Override certain roles, for now
1090 config_data['roles']['data'] = raw.name
1091 config_data['roles']['reference'] = raw.name
1092 config_data['roles']['texture_paint'] = raw.name
1094 print('generateLUTs - end')
1098 def generate_baked_LUTs(odt_info,
1104 lut_resolution_shaper=1024,
1112 Parameter description.
1117 Return value description.
1120 odt_info_C = dict(odt_info)
1122 # Uncomment if you would like to support the older behavior where ODTs
1123 # that have support for full and legal range output generate a LUT for each.
1125 # Create two entries for ODTs that have full and legal range support
1126 for odt_ctl_name, odt_values in odt_info.iteritems():
1127 if odt_values['transformHasFullLegalSwitch']:
1128 odt_name = odt_values['transformUserName']
1130 odt_values_legal = dict(odt_values)
1131 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1132 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1134 odt_values_full = dict(odt_values)
1135 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1136 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1138 del (odt_info_C[odt_ctl_name])
1141 # Generate appropriate LUTs for each ODT
1142 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1143 odt_prefix = odt_values['transformUserNamePrefix']
1144 odt_name = odt_values['transformUserName']
1147 for input_space in ['ACEScc', 'ACESproxy']:
1148 args = ['--iconfig', config_path,
1151 args += ['--inputspace', 'ACES - %s' % input_space]
1152 args += ['--outputspace', 'Output - %s' % odt_name]
1154 args += ['--inputspace', input_space]
1155 args += ['--outputspace', odt_name]
1157 args += ['--description',
1158 '%s - %s for %s data' % (odt_prefix,
1162 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1163 '--shapersize', str(lut_resolution_shaper)]
1165 args += ['--shaperspace', shaper_name,
1166 '--shapersize', str(lut_resolution_shaper)]
1167 args += ['--cubesize', str(lut_resolution_3d)]
1168 args += ['--format',
1170 os.path.join(baked_directory,
1172 '%s for %s.icc' % (odt_name, input_space))]
1174 bake_lut = Process(description='bake a LUT',
1180 for input_space in ['ACEScc', 'ACESproxy']:
1181 args = ['--iconfig', config_path,
1184 args += ['--inputspace', 'ACES - %s' % input_space]
1185 args += ['--outputspace', 'Output - %s' % odt_name]
1187 args += ['--inputspace', input_space]
1188 args += ['--outputspace', odt_name]
1189 args += ['--description',
1190 '%s - %s for %s data' % (
1191 odt_prefix, odt_name, input_space)]
1193 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1194 '--shapersize', str(lut_resolution_shaper)]
1196 args += ['--shaperspace', shaper_name,
1197 '--shapersize', str(lut_resolution_shaper)]
1198 args += ['--cubesize', str(lut_resolution_3d)]
1200 fargs = ['--format',
1205 '%s for %s Flame.3dl' % (odt_name, input_space))]
1206 bake_lut = Process(description='bake a LUT',
1208 args=(args + fargs))
1211 largs = ['--format',
1216 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1217 bake_lut = Process(description='bake a LUT',
1219 args=(args + largs))
1223 for input_space in ['ACEScg', 'ACES2065-1']:
1224 args = ['--iconfig', config_path,
1227 args += ['--inputspace', 'ACES - %s' % input_space]
1228 args += ['--outputspace', 'Output - %s' % odt_name]
1230 args += ['--inputspace', input_space]
1231 args += ['--outputspace', odt_name]
1232 args += ['--description',
1233 '%s - %s for %s data' % (
1234 odt_prefix, odt_name, input_space)]
1235 if input_space == 'ACEScg':
1236 lin_shaper_name = '%s - AP1' % shaper_name
1238 lin_shaper_name = shaper_name
1240 lin_shaper_name = 'Utility - %s' % lin_shaper_name
1241 args += ['--shaperspace', lin_shaper_name,
1242 '--shapersize', str(lut_resolution_shaper)]
1244 args += ['--cubesize', str(lut_resolution_3d)]
1246 margs = ['--format',
1251 '%s for %s Maya.csp' % (odt_name, input_space))]
1252 bake_lut = Process(description='bake a LUT',
1254 args=(args + margs))
1257 hargs = ['--format',
1262 '%s for %s Houdini.lut' % (odt_name, input_space))]
1263 bake_lut = Process(description='bake a LUT',
1265 args=(args + hargs))
1269 def create_config_dir(config_directory,
1270 bake_secondary_LUTs=False,
1271 custom_lut_dir=None):
1278 Parameter description.
1283 Return value description.
1286 lut_directory = os.path.join(config_directory, 'luts')
1287 dirs = [config_directory, lut_directory]
1289 if bake_secondary_LUTs:
1290 dirs.extend([os.path.join(config_directory, 'baked'),
1291 os.path.join(config_directory, 'baked', 'flame'),
1292 os.path.join(config_directory, 'baked', 'photoshop'),
1293 os.path.join(config_directory, 'baked', 'houdini'),
1294 os.path.join(config_directory, 'baked', 'lustre'),
1295 os.path.join(config_directory, 'baked', 'maya')])
1298 dirs.append(os.path.join(config_directory, 'custom'))
1301 not os.path.exists(d) and os.mkdir(d)
1303 return lut_directory
1306 def create_ACES_config(aces_ctl_directory,
1308 lut_resolution_1d=4096,
1309 lut_resolution_3d=64,
1310 bake_secondary_LUTs=True,
1311 multiple_displays=False,
1313 copy_custom_luts=True,
1315 prefix_colorspaces_with_family_names=True):
1317 Creates the ACES configuration.
1322 Parameter description.
1327 Return value description.
1330 if look_info is None:
1333 # Directory for custom LUTs
1334 custom_lut_dir = None
1335 if copy_custom_luts:
1336 custom_lut_dir = os.path.join(config_directory, 'custom')
1338 lut_directory = create_config_dir(config_directory,
1339 bake_secondary_LUTs,
1342 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1343 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1345 shaper_name = 'Output Shaper'
1346 config_data = generate_LUTs(odt_info,
1355 print('Creating config - with prefixes, with aliases')
1356 config = create_config(config_data,
1357 prefix=prefix_colorspaces_with_family_names,
1359 multiple_displays=multiple_displays,
1360 look_info=look_info,
1361 custom_lut_dir=custom_lut_dir)
1364 write_config(config,
1365 os.path.join(config_directory, 'config.ocio'))
1367 if bake_secondary_LUTs:
1368 generate_baked_LUTs(odt_info,
1370 os.path.join(config_directory, 'baked'),
1371 os.path.join(config_directory, 'config.ocio'),
1375 prefix=prefix_colorspaces_with_family_names)
1387 Parameter description.
1392 Return value description.
1397 usage = '%prog [options]\n'
1399 usage += 'An OCIO config generation script for ACES 1.0\n'
1401 usage += 'Command line examples'
1403 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1404 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1406 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1407 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1410 usage += 'Adding custom looks'
1412 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1413 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookCDL ACESCDLName /path/to/SampleCDL.ccc cc03345'
1415 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1416 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1418 usage += '\tIn this example, the CDL will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1420 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1421 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addACESLookLUT ACESLUTName /path/to/SampleCDL.ccc cc03345'
1423 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1424 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 \n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1426 usage += '\tIn this example, the LUT will be applied in the ACEScc colorspace, but the user could choose other spaces by changing the argument after the name of the look. \n'
1431 def look_info_callback(option, opt_str, value, parser):
1432 print('look_info_callback')
1433 print(option, opt_str, value, parser)
1434 if opt_str == '--addCustomLookCDL':
1435 look_info.append(value)
1436 elif opt_str == '--addCustomLookLUT':
1437 look_info.append(value)
1438 elif opt_str == '--addACESLookCDL':
1439 look_info.append([value[0], 'ACES - ACEScc', value[1], value[2]])
1440 elif opt_str == '--addACESLookLUT':
1441 look_info.append([value[0], 'ACES - ACEScc', value[1]])
1443 p = optparse.OptionParser(description='',
1444 prog='create_aces_config',
1445 version='create_aces_config 1.0',
1447 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1448 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1449 p.add_option('--configDir', '-c', default=os.environ.get(
1450 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1451 p.add_option('--lutResolution1d', default=4096)
1452 p.add_option('--lutResolution3d', default=64)
1453 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1454 p.add_option('--keepTempImages', action='store_true', default=False)
1456 p.add_option('--createMultipleDisplays', action='store_true',
1459 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1460 action='callback', callback=look_info_callback)
1461 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1462 action='callback', callback=look_info_callback)
1463 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1464 action='callback', callback=look_info_callback)
1465 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1466 action='callback', callback=look_info_callback)
1467 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1469 options, arguments = p.parse_args()
1471 aces_ctl_directory = options.acesCTLDir
1472 config_directory = options.configDir
1473 lut_resolution_1d = int(options.lutResolution1d)
1474 lut_resolution_3d = int(options.lutResolution3d)
1475 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1476 cleanup_temp_images = not options.keepTempImages
1477 multiple_displays = options.createMultipleDisplays
1478 copy_custom_luts = options.copyCustomLUTs
1482 # TODO: Investigate the following statements.
1484 args_start = sys.argv.index('--') + 1
1485 args = sys.argv[args_start:]
1487 args_start = len(sys.argv) + 1
1490 print('command line : \n%s\n' % ' '.join(sys.argv))
1492 assert aces_ctl_directory is not None, (
1493 'process: No "{0}" environment variable defined or no "ACES CTL" '
1494 'directory specified'.format(
1495 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1497 assert config_directory is not None, (
1498 'process: No "{0}" environment variable defined or no configuration '
1499 'directory specified'.format(
1500 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1502 return create_ACES_config(aces_ctl_directory,
1506 bake_secondary_luts,
1510 cleanup_temp_images)
1513 if __name__ == '__main__':