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:
185 if transform['type'] == 'lutFile':
187 ocio_transform = ocio.FileTransform()
189 if 'path' in transform:
190 ocio_transform.setSrc(transform['path'])
192 if 'cccid' in transform:
193 ocio_transform.setCCCId(transform['cccid'])
195 if 'interpolation' in transform:
196 ocio_transform.setInterpolation(transform['interpolation'])
198 ocio_transform.setInterpolation(ocio.Constants.INTERP_BEST)
200 if 'direction' in transform:
201 ocio_transform.setDirection(
202 direction_options[transform['direction']])
204 ocio_transforms.append(ocio_transform)
207 elif transform['type'] == 'matrix':
208 ocio_transform = ocio.MatrixTransform()
209 # MatrixTransform member variables can't be initialized directly.
210 # Each must be set individually.
211 ocio_transform.setMatrix(transform['matrix'])
213 if 'offset' in transform:
214 ocio_transform.setOffset(transform['offset'])
216 if 'direction' in transform:
217 ocio_transform.setDirection(
218 direction_options[transform['direction']])
220 ocio_transforms.append(ocio_transform)
223 elif transform['type'] == 'exponent':
224 ocio_transform = ocio.ExponentTransform()
226 if 'value' in transform:
227 ocio_transform.setValue(transform['value'])
229 ocio_transforms.append(ocio_transform)
232 elif transform['type'] == 'log':
233 ocio_transform = ocio.LogTransform()
235 if 'base' in transform:
236 ocio_transform.setBase(transform['base'])
238 if 'direction' in transform:
239 ocio_transform.setDirection(
240 direction_options[transform['direction']])
242 ocio_transforms.append(ocio_transform)
244 # color space transform
245 elif transform['type'] == 'colorspace':
246 ocio_transform = ocio.ColorSpaceTransform()
248 if 'src' in transform:
249 ocio_transform.setSrc(transform['src'])
251 if 'dst' in transform:
252 ocio_transform.setDst(transform['dst'])
254 if 'direction' in transform:
255 ocio_transform.setDirection(
256 direction_options[transform['direction']])
258 ocio_transforms.append(ocio_transform)
261 elif transform['type'] == 'look':
262 ocio_transform = ocio.LookTransform()
263 if 'look' in transform:
264 ocio_transform.setLooks(transform['look'])
266 if 'src' in transform:
267 ocio_transform.setSrc(transform['src'])
269 if 'dst' in transform:
270 ocio_transform.setDst(transform['dst'])
272 if 'direction' in transform:
273 ocio_transform.setDirection(
274 direction_options[transform['direction']])
276 ocio_transforms.append(ocio_transform)
280 print('Ignoring unknown transform type : %s' % transform['type'])
282 if len(ocio_transforms) > 1:
283 group_transform = ocio.GroupTransform()
284 for transform in ocio_transforms:
285 group_transform.push_back(transform)
286 transform = group_transform
288 transform = ocio_transforms[0]
293 def add_colorspace_aliases(config,
294 reference_colorspace,
296 colorspace_alias_names,
304 Parameter description.
309 Return value description.
312 for alias_name in colorspace_alias_names:
313 if alias_name.lower() == colorspace.name.lower():
314 print('Skipping alias creation for %s, alias %s, '
315 'because lower cased names match' % (
316 colorspace.name, alias_name))
319 print('Adding alias colorspace space %s, alias to %s' % (
320 alias_name, colorspace.name))
322 compact_family_name = family
324 description = colorspace.description
325 if colorspace.aces_transform_id:
327 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
329 ocio_colorspace_alias = ocio.ColorSpace(
331 bitDepth=colorspace.bit_depth,
332 description=description,
333 equalityGroup=colorspace.equality_group,
334 family=compact_family_name,
335 isData=colorspace.is_data,
336 allocation=colorspace.allocation_type,
337 allocationVars=colorspace.allocation_vars)
339 if colorspace.to_reference_transforms:
340 print('\tGenerating To-Reference transforms')
341 ocio_transform = generate_OCIO_transform(
342 [{'type': 'colorspace',
343 'src': colorspace.name,
344 'dst': reference_colorspace.name,
345 'direction': 'forward'}])
346 ocio_colorspace_alias.setTransform(
348 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
350 if colorspace.from_reference_transforms:
351 print('\tGenerating From-Reference transforms')
352 ocio_transform = generate_OCIO_transform(
353 [{'type': 'colorspace',
354 'src': reference_colorspace.name,
355 'dst': colorspace.name,
356 'direction': 'forward'}])
357 ocio_colorspace_alias.setTransform(
359 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
361 config.addColorSpace(ocio_colorspace_alias)
375 Parameter description.
380 Return value description.
383 look_name, look_colorspace, look_lut, look_cccid = unpack_default(look, 4)
385 print('Adding look %s - %s' % (look_name, ', '.join(look)))
391 if '$' not in look_lut:
392 print('Getting ready to copy look lut : %s' % look_lut)
393 shutil.copy2(look_lut, custom_lut_dir)
394 look_lut = os.path.split(look_lut)[1]
396 print('Skipping LUT copy because path contains a context variable')
402 print('Adding look to config')
404 lk1.setName(look_name)
405 lk1.setProcessSpace(look_colorspace)
407 keys = {'type': 'lutFile',
409 'direction': 'forward'}
411 keys['cccid'] = look_cccid
413 ocio_transform = generate_OCIO_transform([keys])
414 lk1.setTransform(ocio_transform)
419 print('Creating aliased colorspace')
422 # Create OCIO colorspace that references that look
423 # - Needed for some implementations that don't process looks well
424 # - Also needed for some implementations that don't expose looks well
426 look_aliases = ['look_%s' % compact(look_name)]
427 colorspace = ColorSpace(look_name,
428 aliases=look_aliases,
429 description='The %s Look colorspace' % look_name,
432 colorspace.from_reference_transforms = [{'type': 'look',
434 'src': reference_name,
435 'dst': reference_name,
436 'direction': 'forward'}]
438 print('Adding colorspace %s, alias to look %s to config data' % (
439 look_name, look_name))
441 # Add this colorspace into the main list of colorspaces
442 config_data['colorSpaces'].append(colorspace)
447 def integrate_looks_into_views(looks,
450 multiple_displays=False):
457 Parameter description.
462 Return value description.
464 look_names = [look[0] for look in looks]
466 # Option 1 - Add a 'look' to each Display
467 # - Assumes there is a Display for each ACES Output Transform
468 if multiple_displays:
469 for look_name in look_names:
470 config_data['looks'].append(look_name)
473 # - Copy each Output Transform colorspace
474 # - For each copy, add a LookTransform at the head of the from_reference
476 # - Add these new copied colorspaces for the Displays / Views
478 for display, view_list in config_data['displays'].iteritems():
479 output_colorspace_c = None
480 look_names_string = ''
481 for view_name, output_colorspace in view_list.iteritems():
482 if view_name == 'Output Transform':
484 print('Adding new View that incorporates looks')
486 # Make a copy of the output colorspace
487 output_colorspace_c = copy.deepcopy(output_colorspace)
489 # for look_name in look_names:
490 for i, look_name in enumerate(look_names):
491 look_name = look_names[i]
493 # Add the LookTransform to the head of the
494 # from_reference transform list.
495 if output_colorspace_c.from_reference_transforms:
496 output_colorspace_c.from_reference_transforms.insert(
499 'src': reference_name,
500 'dst': reference_name,
501 'direction': 'forward'})
503 # Add the LookTransform to the end of
504 # the to_reference transform list.
505 if output_colorspace_c.to_reference_transforms:
506 inverse_look_name = look_names[
507 len(look_names) - 1 - i]
509 output_colorspace_c.to_reference_transforms.append(
511 'look': inverse_look_name,
512 'src': reference_name,
513 'dst': reference_name,
514 'direction': 'inverse'})
516 if look_name not in config_data['looks']:
517 config_data['looks'].append(look_name)
519 look_names_string = ', '.join(look_names)
520 output_colorspace_c.name = '%s with %s' % (
521 output_colorspace.name, look_names_string)
522 output_colorspace_c.aliases = [
523 'out_%s' % compact(output_colorspace_c.name)]
525 print('Colorspace that incorporates looks '
526 'created : %s' % output_colorspace_c.name)
528 config_data['colorSpaces'].append(output_colorspace_c)
530 if output_colorspace_c:
531 print('Adding colorspace that incorporates looks '
534 # Change the name of the View
535 view_list['Output Transform with %s' % look_names_string] = (
537 config_data['displays'][display] = view_list
539 # print('Display : %s, View List : %s' % (
540 # display, ', '.join(view_list)) )
543 def create_config(config_data,
546 multiple_displays=False,
548 custom_lut_dir=None):
555 Parameter description.
560 Return value description.
563 if look_info is None:
567 alias_colorspaces = []
569 # Creating the *OCIO* configuration.
570 config = ocio.Config()
572 # Setting configuration description.
573 config.setDescription('An ACES config generated from python')
575 # Setting configuration search path.
576 search_path = ['luts']
578 search_path.append('custom')
579 config.setSearchPath(':'.join(search_path))
581 # Defining the reference colorspace.
582 reference_data = config_data['referenceColorSpace']
584 # Adding the color space Family into the name
585 # Helps with applications that present colorspaces as one long list
587 prefixed_name = colorspace_prefixed_name(reference_data)
588 prefixed_names[reference_data.name] = prefixed_name
589 reference_data.name = prefixed_name
591 print('Adding the reference color space : %s' % reference_data.name)
593 reference = ocio.ColorSpace(
594 name=reference_data.name,
595 bitDepth=reference_data.bit_depth,
596 description=reference_data.description,
597 equalityGroup=reference_data.equality_group,
598 family=reference_data.family,
599 isData=reference_data.is_data,
600 allocation=reference_data.allocation_type,
601 allocationVars=reference_data.allocation_vars)
603 config.addColorSpace(reference)
607 if reference_data.aliases:
608 # add_colorspace_alias(config, reference_data,
609 # reference_data, reference_data.aliases)
610 # defer adding alias colorspaces until end.
611 # Helps with some applications.
612 alias_colorspaces.append(
613 [reference_data, reference_data, reference_data.aliases])
617 # print('color spaces : %s' % [
618 # x.name for x in sorted(config_data['colorSpaces'])])
621 # Add Looks and Look colorspaces
624 print('Adding looks')
626 config_data['looks'] = []
628 # Add looks and colorspaces
629 for look in look_info:
636 # Integrate looks with displays, views
637 integrate_looks_into_views(look_info,
644 print('Adding the regular color spaces')
646 # Creating the remaining colorspaces.
647 for colorspace in sorted(config_data['colorSpaces']):
648 # Adding the color space Family into the name
649 # Helps with applications that present colorspaces as one long list
651 prefixed_name = colorspace_prefixed_name(colorspace)
652 prefixed_names[colorspace.name] = prefixed_name
653 colorspace.name = prefixed_name
655 print('Creating new color space : %s' % colorspace.name)
657 description = colorspace.description
658 if colorspace.aces_transform_id:
660 '\n\nACES Transform ID : %s' % colorspace.aces_transform_id)
662 ocio_colorspace = ocio.ColorSpace(
663 name=colorspace.name,
664 bitDepth=colorspace.bit_depth,
665 description=description,
666 equalityGroup=colorspace.equality_group,
667 family=colorspace.family,
668 isData=colorspace.is_data,
669 allocation=colorspace.allocation_type,
670 allocationVars=colorspace.allocation_vars)
672 if colorspace.to_reference_transforms:
673 print('\tGenerating To-Reference transforms')
674 ocio_transform = generate_OCIO_transform(
675 colorspace.to_reference_transforms)
676 ocio_colorspace.setTransform(
678 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
680 if colorspace.from_reference_transforms:
681 print('\tGenerating From-Reference transforms')
682 ocio_transform = generate_OCIO_transform(
683 colorspace.from_reference_transforms)
684 ocio_colorspace.setTransform(
686 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
688 config.addColorSpace(ocio_colorspace)
691 # Add alias to normal colorspace, using compact name
694 if colorspace.aliases:
695 # add_colorspace_alias(config, reference_data,
696 # colorspace, colorspace.aliases)
697 # defer adding alias colorspaces until end.
698 # Helps with some applications.
699 alias_colorspaces.append(
700 [reference_data, colorspace, colorspace.aliases])
707 # We add roles early so we can create alias colorspaces with the names
708 # of the roles before the rest of the colorspace aliases are added
710 print('Setting the roles')
713 set_config_default_roles(
715 color_picking=prefixed_names[
716 config_data['roles']['color_picking']],
717 color_timing=prefixed_names[config_data['roles']['color_timing']],
718 compositing_log=prefixed_names[
719 config_data['roles']['compositing_log']],
720 data=prefixed_names[config_data['roles']['data']],
721 default=prefixed_names[config_data['roles']['default']],
722 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
723 reference=prefixed_names[config_data['roles']['reference']],
724 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
725 texture_paint=prefixed_names[
726 config_data['roles']['texture_paint']])
728 # Not allowed for the moment. role names can not overlap
729 # with colorspace names.
731 # Add the aliased colorspaces for each role
732 for role_name, role_colorspace_name in config_data['roles'].iteritems():
733 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
735 print( 'Finding colorspace : %s' % role_colorspace_prefixed_name )
736 # Find the colorspace pointed to by the role
737 role_colorspaces = [colorspace
738 for colorspace in config_data['colorSpaces']
739 if colorspace.name == role_colorspace_prefixed_name]
740 role_colorspace = None
741 if len(role_colorspaces) > 0:
742 role_colorspace = role_colorspaces[0]
744 if reference_data.name == role_colorspace_prefixed_name:
745 role_colorspace = reference_data
748 print( 'Adding an alias colorspace named %s, pointing to %s' % (
749 role_name, role_colorspace.name))
751 add_colorspace_aliases(
752 config, reference_data, role_colorspace, [role_name], 'Roles')
756 set_config_default_roles(
758 color_picking=config_data['roles']['color_picking'],
759 color_timing=config_data['roles']['color_timing'],
760 compositing_log=config_data['roles']['compositing_log'],
761 data=config_data['roles']['data'],
762 default=config_data['roles']['default'],
763 matte_paint=config_data['roles']['matte_paint'],
764 reference=config_data['roles']['reference'],
765 scene_linear=config_data['roles']['scene_linear'],
766 texture_paint=config_data['roles']['texture_paint'])
768 # Not allowed for the moment. role names can not overlap
769 # with colorspace names.
771 # Add the aliased colorspaces for each role
772 for role_name, role_colorspace_name in config_data['roles'].iteritems():
773 # Find the colorspace pointed to by the role
774 role_colorspaces = [colorspace
775 for colorspace in config_data['colorSpaces']
776 if colorspace.name == role_colorspace_name]
777 role_colorspace = None
778 if len(role_colorspaces) > 0:
779 role_colorspace = role_colorspaces[0]
781 if reference_data.name == role_colorspace_name:
782 role_colorspace = reference_data
785 print( 'Adding an alias colorspace named %s, pointing to %s' % (
786 role_name, role_colorspace.name))
788 add_colorspace_aliases(
789 config, reference_data, role_colorspace, [role_name], 'Roles')
794 # We add these at the end as some applications use the order of the
795 # colorspaces definitions in the config to order the colorspaces
796 # in their selection lists.
797 # Other go alphabetically. This should keep the alias colorspaces out
798 # of the way for the apps that use the order of definition in the config.
799 print('Adding the alias colorspaces')
800 for reference, colorspace, aliases in alias_colorspaces:
801 add_colorspace_aliases(config, reference, colorspace, aliases)
805 print('Adding the diplays and views')
807 # Set the color_picking role to be
808 # the first Display's Output Transform View.
809 default_display_name = config_data['defaultDisplay']
810 default_display_views = config_data['displays'][default_display_name]
811 default_display_colorspace = default_display_views['Output Transform']
813 set_config_default_roles(
815 color_picking=default_display_colorspace.name)
817 # Defining the *views* and *displays*.
821 # Defining a *generic* *display* and *view* setup.
822 if multiple_displays:
823 # Built list of looks to add to Displays
824 looks = config_data['looks'] if ('looks' in config_data) else []
825 looks = ', '.join(looks)
826 print('Creating multiple displays, with looks : %s' % looks)
828 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
829 # because OCIO will order them alphabetically
830 # when the config is written to disk.
832 # Create Displays, Views
833 for display, view_list in config_data['displays'].iteritems():
834 for view_name, colorspace in view_list.iteritems():
835 config.addDisplay(display, view_name, colorspace.name, looks)
836 if 'Output Transform' in view_name and looks != '':
837 # Add normal View, without looks
838 config.addDisplay(display, view_name, colorspace.name)
840 # Add View with looks
841 view_name_with_looks = '%s with %s' % (view_name, looks)
842 config.addDisplay(display, view_name_with_looks,
843 colorspace.name, looks)
845 config.addDisplay(display, view_name, colorspace.name)
846 if not (view_name in views):
847 views.append(view_name)
848 displays.append(display)
850 # Defining the set of *views* and *displays* useful in a *GUI* context.
852 single_display_name = 'ACES'
853 # single_display_name = config_data['roles']['scene_linear']
854 displays.append(single_display_name)
856 # Make sure the default display is first
857 display_names = sorted(config_data['displays'])
858 display_names.insert(0, display_names.pop(
859 display_names.index(default_display_name)))
861 # Built list of looks to add to Displays
862 looks = config_data['looks'] if ('looks' in config_data) else []
863 look_names = ', '.join(looks)
865 displays_views_colorspaces = []
867 # Create Displays, Views
868 for display in display_names:
869 view_list = config_data['displays'][display]
870 for view_name, colorspace in view_list.iteritems():
871 if 'Output Transform' in view_name:
872 # print( 'Adding view for %s' % colorspace.name )
874 # We use the Display names as the View names in this case
875 # as there is a single Display that contains all views.
876 # This works for more applications than not,
877 # as of the time of this implementation.
879 # Maya 2016 doesn't like parentheses in View names
880 display_cleaned = replace(display, {')': '', '(': ''})
882 # If View includes looks
883 if 'with' in view_name:
884 # Integrate looks into view name
885 display_cleaned = '%s with %s' % (
886 display_cleaned, look_names)
888 views_with_looks_at_end = False
889 # Storing combo of display, view and colorspace name
890 # in a list so we can add them to the end of the list.
891 if views_with_looks_at_end:
892 displays_views_colorspaces.append(
893 [single_display_name, display_cleaned,
898 config.addDisplay(single_display_name,
899 display_cleaned, colorspace.name)
902 if not (display_cleaned in views):
903 views.append(display_cleaned)
907 config.addDisplay(single_display_name, display_cleaned,
911 if not (display_cleaned in views):
912 views.append(display_cleaned)
914 # Add to config any display, view combinations that were saved
915 # for later. This list will be empty unless views_with_looks_at_end is
917 for display_view_colorspace in displays_views_colorspaces:
918 single_display_name, display_cleaned, colorspace_name = (
919 display_view_colorspace)
922 config.addDisplay(single_display_name, display_cleaned,
926 if not (display_cleaned in views):
927 views.append(display_cleaned)
930 # Works with Nuke Studio and Mari, but not Nuke
931 # single_display_name = 'Utility'
932 # displays.append(single_display_name)
934 raw_display_space_name = config_data['roles']['data']
935 log_display_space_name = config_data['roles']['compositing_log']
937 # Find the newly-prefixed colorspace names
939 # print( prefixed_names )
940 raw_display_space_name = prefixed_names[raw_display_space_name]
941 log_display_space_name = prefixed_names[log_display_space_name]
943 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
945 config.addDisplay(single_display_name, 'Log', log_display_space_name)
948 # Setting the active *displays* and *views*.
949 config.setActiveDisplays(','.join(sorted(displays)))
950 config.setActiveViews(','.join(views))
954 # Make sure we didn't create a bad config
957 # Reset the colorspace names back to their non-prefixed versions
959 # Build the reverse lookup
960 prefixed_names_inverse = {}
961 for original, prefixed in prefixed_names.iteritems():
962 prefixed_names_inverse[prefixed] = original
964 # Reset the reference colorspace name
965 reference_data.name = prefixed_names_inverse[reference_data.name]
967 # Reset the rest of the colorspace names
969 for colorspace in config_data['colorSpaces']:
970 colorspace.name = prefixed_names_inverse[colorspace.name]
972 print('Prefixed names')
973 for original, prefixed in prefixed_names.iteritems():
974 print('%s, %s' % (original, prefixed))
978 print('Inverse Lookup of Prefixed names')
979 for prefixed, original in prefixed_names_inverse.iteritems():
980 print('%s, %s' % (prefixed, original))
986 def generate_LUTs(odt_info,
991 lut_resolution_1d=4096,
992 lut_resolution_3d=64,
1000 Parameter description.
1005 Colorspaces and transforms converting between those colorspaces and
1006 the reference colorspace, *ACES*.
1009 print('generateLUTs - begin')
1012 # Initialize a few variables
1013 config_data['displays'] = {}
1014 config_data['colorSpaces'] = []
1016 # -------------------------------------------------------------------------
1017 # *ACES Color Spaces*
1018 # -------------------------------------------------------------------------
1020 # *ACES* colorspaces
1024 aces_log_display_space,
1026 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1035 config_data['referenceColorSpace'] = aces_reference
1036 config_data['roles'] = aces_roles
1038 for cs in aces_colorspaces:
1039 config_data['colorSpaces'].append(cs)
1041 for name, data in aces_displays.iteritems():
1042 config_data['displays'][name] = data
1044 config_data['defaultDisplay'] = aces_default_display
1045 config_data['linearDisplaySpace'] = aces_reference
1046 config_data['logDisplaySpace'] = aces_log_display_space
1048 # -------------------------------------------------------------------------
1049 # *Camera Input Transforms*
1050 # -------------------------------------------------------------------------
1052 # *ARRI Log-C* to *ACES*.
1053 arri_colorspaces = arri.create_colorspaces(lut_directory,
1055 for cs in arri_colorspaces:
1056 config_data['colorSpaces'].append(cs)
1058 # *Canon-Log* to *ACES*.
1059 canon_colorspaces = canon.create_colorspaces(lut_directory,
1061 for cs in canon_colorspaces:
1062 config_data['colorSpaces'].append(cs)
1064 # *GoPro Protune* to *ACES*.
1065 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1067 for cs in gopro_colorspaces:
1068 config_data['colorSpaces'].append(cs)
1070 # *Panasonic V-Log* to *ACES*.
1071 panasonic_colorspaces = panasonic.create_colorspaces(lut_directory,
1073 for cs in panasonic_colorspaces:
1074 config_data['colorSpaces'].append(cs)
1076 # *RED* colorspaces to *ACES*.
1077 red_colorspaces = red.create_colorspaces(lut_directory,
1079 for cs in red_colorspaces:
1080 config_data['colorSpaces'].append(cs)
1082 # *S-Log* to *ACES*.
1083 sony_colorspaces = sony.create_colorspaces(lut_directory,
1085 for cs in sony_colorspaces:
1086 config_data['colorSpaces'].append(cs)
1088 # -------------------------------------------------------------------------
1089 # General Color Spaces
1090 # -------------------------------------------------------------------------
1091 general_colorspaces = general.create_colorspaces(lut_directory,
1093 for cs in general_colorspaces:
1094 config_data['colorSpaces'].append(cs)
1096 # The *Raw* color space
1097 raw = general.create_raw()
1098 config_data['colorSpaces'].append(raw)
1100 # Override certain roles, for now
1101 config_data['roles']['data'] = raw.name
1102 config_data['roles']['reference'] = raw.name
1103 config_data['roles']['texture_paint'] = raw.name
1105 print('generateLUTs - end')
1109 def generate_baked_LUTs(odt_info,
1114 lut_resolution_shaper=1024,
1122 Parameter description.
1127 Return value description.
1130 odt_info_C = dict(odt_info)
1132 # Uncomment if you would like to support the older behavior where ODTs
1133 # that have support for full and legal range output generate
1136 # Create two entries for ODTs that have full and legal range support
1137 for odt_ctl_name, odt_values in odt_info.iteritems():
1138 if odt_values['transformHasFullLegalSwitch']:
1139 odt_name = odt_values['transformUserName']
1141 odt_values_legal = dict(odt_values)
1142 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1143 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1145 odt_values_full = dict(odt_values)
1146 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1147 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1149 del (odt_info_C[odt_ctl_name])
1152 # Generate appropriate LUTs for each ODT
1153 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1154 odt_prefix = odt_values['transformUserNamePrefix']
1155 odt_name = odt_values['transformUserName']
1158 for input_space in ['ACEScc', 'ACESproxy']:
1159 args = ['--iconfig', config_path,
1162 args += ['--inputspace', 'ACES - %s' % input_space]
1163 args += ['--outputspace', 'Output - %s' % odt_name]
1165 args += ['--inputspace', input_space]
1166 args += ['--outputspace', odt_name]
1168 args += ['--description',
1169 '%s - %s for %s data' % (odt_prefix,
1173 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1174 '--shapersize', str(lut_resolution_shaper)]
1176 args += ['--shaperspace', shaper_name,
1177 '--shapersize', str(lut_resolution_shaper)]
1178 args += ['--cubesize', str(lut_resolution_3d)]
1179 args += ['--format',
1181 os.path.join(baked_directory,
1183 '%s for %s.icc' % (odt_name, input_space))]
1185 bake_lut = Process(description='bake a LUT',
1191 for input_space in ['ACEScc', 'ACESproxy']:
1192 args = ['--iconfig', config_path,
1195 args += ['--inputspace', 'ACES - %s' % input_space]
1196 args += ['--outputspace', 'Output - %s' % odt_name]
1198 args += ['--inputspace', input_space]
1199 args += ['--outputspace', odt_name]
1200 args += ['--description',
1201 '%s - %s for %s data' % (
1202 odt_prefix, odt_name, input_space)]
1204 args += ['--shaperspace', 'Utility - %s' % shaper_name,
1205 '--shapersize', str(lut_resolution_shaper)]
1207 args += ['--shaperspace', shaper_name,
1208 '--shapersize', str(lut_resolution_shaper)]
1209 args += ['--cubesize', str(lut_resolution_3d)]
1211 fargs = ['--format',
1216 '%s for %s Flame.3dl' % (odt_name, input_space))]
1217 bake_lut = Process(description='bake a LUT',
1219 args=(args + fargs))
1222 largs = ['--format',
1227 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1228 bake_lut = Process(description='bake a LUT',
1230 args=(args + largs))
1234 for input_space in ['ACEScg', 'ACES2065-1']:
1235 args = ['--iconfig', config_path,
1238 args += ['--inputspace', 'ACES - %s' % input_space]
1239 args += ['--outputspace', 'Output - %s' % odt_name]
1241 args += ['--inputspace', input_space]
1242 args += ['--outputspace', odt_name]
1243 args += ['--description',
1244 '%s - %s for %s data' % (
1245 odt_prefix, odt_name, input_space)]
1246 if input_space == 'ACEScg':
1247 lin_shaper_name = '%s - AP1' % shaper_name
1249 lin_shaper_name = shaper_name
1251 lin_shaper_name = 'Utility - %s' % lin_shaper_name
1252 args += ['--shaperspace', lin_shaper_name,
1253 '--shapersize', str(lut_resolution_shaper)]
1255 args += ['--cubesize', str(lut_resolution_3d)]
1257 margs = ['--format',
1262 '%s for %s Maya.csp' % (odt_name, input_space))]
1263 bake_lut = Process(description='bake a LUT',
1265 args=(args + margs))
1268 hargs = ['--format',
1273 '%s for %s Houdini.lut' % (odt_name, input_space))]
1274 bake_lut = Process(description='bake a LUT',
1276 args=(args + hargs))
1280 def create_config_dir(config_directory,
1281 bake_secondary_luts=False,
1282 custom_lut_dir=None):
1289 Parameter description.
1294 Return value description.
1297 lut_directory = os.path.join(config_directory, 'luts')
1298 dirs = [config_directory, lut_directory]
1300 if bake_secondary_luts:
1301 dirs.extend([os.path.join(config_directory, 'baked'),
1302 os.path.join(config_directory, 'baked', 'flame'),
1303 os.path.join(config_directory, 'baked', 'photoshop'),
1304 os.path.join(config_directory, 'baked', 'houdini'),
1305 os.path.join(config_directory, 'baked', 'lustre'),
1306 os.path.join(config_directory, 'baked', 'maya')])
1309 dirs.append(os.path.join(config_directory, 'custom'))
1312 not os.path.exists(d) and os.mkdir(d)
1314 return lut_directory
1317 def create_ACES_config(aces_ctl_directory,
1319 lut_resolution_1d=4096,
1320 lut_resolution_3d=64,
1321 bake_secondary_luts=True,
1322 multiple_displays=False,
1324 copy_custom_luts=True,
1326 prefix_colorspaces_with_family_names=True):
1328 Creates the ACES configuration.
1333 Parameter description.
1338 Return value description.
1341 if look_info is None:
1344 # Directory for custom LUTs
1345 custom_lut_dir = None
1346 if copy_custom_luts:
1347 custom_lut_dir = os.path.join(config_directory, 'custom')
1349 lut_directory = create_config_dir(config_directory,
1350 bake_secondary_luts,
1353 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1354 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1356 shaper_name = 'Output Shaper'
1357 config_data = generate_LUTs(odt_info,
1366 print('Creating config - with prefixes, with aliases')
1367 config = create_config(config_data,
1368 prefix=prefix_colorspaces_with_family_names,
1370 multiple_displays=multiple_displays,
1371 look_info=look_info,
1372 custom_lut_dir=custom_lut_dir)
1375 write_config(config,
1376 os.path.join(config_directory, 'config.ocio'))
1378 if bake_secondary_luts:
1379 generate_baked_LUTs(odt_info,
1381 os.path.join(config_directory, 'baked'),
1382 os.path.join(config_directory, 'config.ocio'),
1385 prefix=prefix_colorspaces_with_family_names)
1397 Parameter description.
1402 Return value description.
1407 usage = '%prog [options]\n'
1409 usage += 'An OCIO config generation script for ACES 1.0\n'
1411 usage += 'Command line examples'
1413 usage += ('Create a GUI-friendly ACES 1.0 config with no secondary, '
1415 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1416 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1417 '--dontBakeSecondaryLUTs')
1419 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1420 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1421 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1422 '--createMultipleDisplays')
1425 usage += 'Adding custom looks'
1427 usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style CDL '
1428 '(will be applied in the ACEScc colorspace): \n')
1429 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1430 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1431 '\n\t\t--addACESLookCDL ACESCDLName '
1432 '/path/to/SampleCDL.ccc cc03345')
1434 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1435 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1436 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1437 '\n\t\t--addCustomLookCDL CustomCDLName "ACES - ACEScc" '
1438 '/path/to/SampleCDL.ccc cc03345')
1440 usage += ('\tIn this example, the CDL will be applied in the '
1441 'ACEScc colorspace, but the user could choose other spaces '
1442 'by changing the argument after the name of the look. \n')
1444 usage += ('Create a GUI-friendly ACES 1.0 config with an ACES-style LUT '
1445 '(will be applied in the ACEScc colorspace): \n')
1446 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1447 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1448 '\n\t\t--addACESLookLUT ACESLUTName '
1449 '/path/to/SampleCDL.ccc cc03345')
1451 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1452 usage += ('\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl '
1453 '--lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 '
1454 '\n\t\t--addCustomLookLUT CustomLUTName "ACES - ACEScc" '
1455 '/path/to/SampleCDL.ccc cc03345')
1457 usage += ('\tIn this example, the LUT will be applied in the '
1458 'ACEScc colorspace, but the user could choose other spaces '
1459 'by changing the argument after the name of the look. \n')
1464 def look_info_callback(option, opt_str, value, parser):
1465 print('look_info_callback')
1466 print(option, opt_str, value, parser)
1467 if opt_str == '--addCustomLookCDL':
1468 look_info.append(value)
1469 elif opt_str == '--addCustomLookLUT':
1470 look_info.append(value)
1471 elif opt_str == '--addACESLookCDL':
1472 look_info.append([value[0], 'ACES - ACEScc', value[1], value[2]])
1473 elif opt_str == '--addACESLookLUT':
1474 look_info.append([value[0], 'ACES - ACEScc', value[1]])
1476 p = optparse.OptionParser(description='',
1477 prog='create_aces_config',
1478 version='create_aces_config 1.0',
1480 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1481 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1482 p.add_option('--configDir', '-c', default=os.environ.get(
1483 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1484 p.add_option('--lutResolution1d', default=4096)
1485 p.add_option('--lutResolution3d', default=64)
1486 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1487 p.add_option('--keepTempImages', action='store_true', default=False)
1489 p.add_option('--createMultipleDisplays', action='store_true',
1492 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1493 action='callback', callback=look_info_callback)
1494 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1495 action='callback', callback=look_info_callback)
1496 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1497 action='callback', callback=look_info_callback)
1498 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1499 action='callback', callback=look_info_callback)
1500 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1502 options, arguments = p.parse_args()
1504 aces_ctl_directory = options.acesCTLDir
1505 config_directory = options.configDir
1506 lut_resolution_1d = int(options.lutResolution1d)
1507 lut_resolution_3d = int(options.lutResolution3d)
1508 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1509 cleanup_temp_images = not options.keepTempImages
1510 multiple_displays = options.createMultipleDisplays
1511 copy_custom_luts = options.copyCustomLUTs
1515 print('command line : \n%s\n' % ' '.join(sys.argv))
1517 assert aces_ctl_directory is not None, (
1518 'process: No "{0}" environment variable defined or no "ACES CTL" '
1519 'directory specified'.format(
1520 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1522 assert config_directory is not None, (
1523 'process: No "{0}" environment variable defined or no configuration '
1524 'directory specified'.format(
1525 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1527 return create_ACES_config(aces_ctl_directory,
1531 bake_secondary_luts,
1535 cleanup_temp_images)
1538 if __name__ == '__main__':