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.
568 alias_colorspaces = []
570 # Creating the *OCIO* configuration.
571 config = ocio.Config()
573 # Setting configuration description.
574 config.setDescription('An ACES config generated from python')
576 # Setting configuration search path.
577 searchPath = ['luts']
579 searchPath.append('custom')
580 config.setSearchPath(':'.join(searchPath))
582 # Defining the reference colorspace.
583 reference_data = config_data['referenceColorSpace']
585 # Adding the color space Family into the name
586 # Helps with applications that present colorspaces as one long list
588 prefixed_name = colorspace_prefixed_name(reference_data)
589 prefixed_names[reference_data.name] = prefixed_name
590 reference_data.name = prefixed_name
592 print('Adding the reference color space : %s' % reference_data.name)
594 reference = ocio.ColorSpace(
595 name=reference_data.name,
596 bitDepth=reference_data.bit_depth,
597 description=reference_data.description,
598 equalityGroup=reference_data.equality_group,
599 family=reference_data.family,
600 isData=reference_data.is_data,
601 allocation=reference_data.allocation_type,
602 allocationVars=reference_data.allocation_vars)
604 config.addColorSpace(reference)
608 if reference_data.aliases != []:
609 # add_colorspace_alias(config, reference_data,
610 # reference_data, reference_data.aliases)
611 # defer adding alias colorspaces until end. Helps with some applications
612 alias_colorspaces.append(
613 [reference_data, reference_data, reference_data.aliases])
617 # print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
620 # Add Looks and Look colorspaces
623 print('Adding looks')
625 config_data['looks'] = []
627 # Add looks and colorspaces
628 for look in look_info:
636 # Integrate looks with displays, views
637 integrate_looks_into_views(config,
645 print('Adding the regular color spaces')
647 # Creating the remaining colorspaces.
648 for colorspace in sorted(config_data['colorSpaces']):
649 # Adding the color space Family into the name
650 # Helps with applications that present colorspaces as one long list
652 prefixed_name = colorspace_prefixed_name(colorspace)
653 prefixed_names[colorspace.name] = prefixed_name
654 colorspace.name = prefixed_name
656 print('Creating new color space : %s' % colorspace.name)
658 description = colorspace.description
659 if colorspace.aces_transform_id:
660 description += "\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. Helps with some applications
698 alias_colorspaces.append(
699 [reference_data, colorspace, colorspace.aliases])
706 # We add roles early so we can create alias colorspaces with the names of the roles
707 # before the rest of the colorspace aliases are added to the config.
709 print('Setting the roles')
712 set_config_default_roles(
714 color_picking=prefixed_names[
715 config_data['roles']['color_picking']],
716 color_timing=prefixed_names[config_data['roles']['color_timing']],
717 compositing_log=prefixed_names[
718 config_data['roles']['compositing_log']],
719 data=prefixed_names[config_data['roles']['data']],
720 default=prefixed_names[config_data['roles']['default']],
721 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
722 reference=prefixed_names[config_data['roles']['reference']],
723 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
724 texture_paint=prefixed_names[
725 config_data['roles']['texture_paint']])
727 # Not allowed for the moment. role names can not overlap with colorspace names.
729 # Add the aliased colorspaces for each role
730 for role_name, role_colorspace_name in config_data['roles'].iteritems():
731 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
733 print( "Finding colorspace : %s" % role_colorspace_prefixed_name )
734 # Find the colorspace pointed to by the role
735 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_prefixed_name]
736 role_colorspace = None
737 if len(role_colorspaces) > 0:
738 role_colorspace = role_colorspaces[0]
740 if reference_data.name == role_colorspace_prefixed_name:
741 role_colorspace = reference_data
744 print( "Adding an alias colorspace named %s, pointing to %s" % (
745 role_name, role_colorspace.name))
747 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
751 set_config_default_roles(
753 color_picking=config_data['roles']['color_picking'],
754 color_timing=config_data['roles']['color_timing'],
755 compositing_log=config_data['roles']['compositing_log'],
756 data=config_data['roles']['data'],
757 default=config_data['roles']['default'],
758 matte_paint=config_data['roles']['matte_paint'],
759 reference=config_data['roles']['reference'],
760 scene_linear=config_data['roles']['scene_linear'],
761 texture_paint=config_data['roles']['texture_paint'])
763 # Not allowed for the moment. role names can not overlap with colorspace names.
765 # Add the aliased colorspaces for each role
766 for role_name, role_colorspace_name in config_data['roles'].iteritems():
767 # Find the colorspace pointed to by the role
768 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_name]
769 role_colorspace = None
770 if len(role_colorspaces) > 0:
771 role_colorspace = role_colorspaces[0]
773 if reference_data.name == role_colorspace_name:
774 role_colorspace = reference_data
777 print( "Adding an alias colorspace named %s, pointing to %s" % (
778 role_name, role_colorspace.name))
780 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
785 # We add these at the end as some applications use the order of the colorspaces
786 # definitions in the config to order the colorspaces in their selection lists.
787 # Other go alphabetically. This should keep the alias colorspaces out of the way
788 # for the apps that use the order of definition in the config.
789 print('Adding the alias colorspaces')
790 for reference, colorspace, aliases in alias_colorspaces:
791 add_colorspace_aliases(config, reference, colorspace, aliases)
795 print('Adding the diplays and views')
797 # Set the color_picking role to be the first Display's Output Transform View
798 default_display_name = config_data['defaultDisplay']
799 default_display_views = config_data['displays'][default_display_name]
800 default_display_colorspace = default_display_views['Output Transform']
802 set_config_default_roles(
804 color_picking=default_display_colorspace.name)
806 # Defining the *views* and *displays*.
810 # Defining a *generic* *display* and *view* setup.
811 if multiple_displays:
812 # Built list of looks to add to Displays
813 looks = config_data['looks'] if ('looks' in config_data) else []
814 looks = ", ".join(looks)
815 print("Creating multiple displays, with looks : %s" % looks)
817 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
818 # because OCIO will order them alphabetically when the config is written to disk.
820 # Create Displays, Views
821 for display, view_list in config_data['displays'].iteritems():
822 for view_name, colorspace in view_list.iteritems():
823 config.addDisplay(display, view_name, colorspace.name, looks)
824 if 'Output Transform' in view_name and looks != "":
825 # Add normal View, without looks
826 config.addDisplay(display, view_name, colorspace.name)
828 # Add View with looks
829 view_name_with_looks = "%s with %s" % (view_name, looks)
830 config.addDisplay(display, view_name_with_looks,
831 colorspace.name, looks)
833 config.addDisplay(display, view_name, colorspace.name)
834 if not (view_name in views):
835 views.append(view_name)
836 displays.append(display)
838 # Defining the set of *views* and *displays* useful in a *GUI* context.
840 single_display_name = 'ACES'
841 # single_display_name = config_data['roles']['scene_linear']
842 displays.append(single_display_name)
844 # Make sure the default display is first
845 display_names = sorted(config_data['displays'])
846 display_names.insert(0, display_names.pop(
847 display_names.index(default_display_name)))
849 # Built list of looks to add to Displays
850 looks = config_data['looks'] if ('looks' in config_data) else []
851 look_names = ", ".join(looks)
853 displays_views_colorspaces = []
855 # Create Displays, Views
856 for display in display_names:
857 view_list = config_data['displays'][display]
858 for view_name, colorspace in view_list.iteritems():
859 if 'Output Transform' in view_name:
860 # print( "Adding view for %s" % colorspace.name )
862 # We use the Display names as the View names in this case
863 # as there is a single Display that contains all views.
864 # This works for more applications than not, as of the time of this implementation.
866 # Maya 2016 doesn't like parentheses in View names
867 display_cleaned = replace(display, {')': '', '(': ''})
869 # If View includes looks
870 if 'with' in view_name:
871 # Integrate looks into view name
872 display_cleaned = "%s with %s" % (
873 display_cleaned, look_names)
875 viewsWithLooksAtEnd = False
876 # Storing combo of display, view and colorspace name in a list so we can
877 # add them to the end of the list
878 if viewsWithLooksAtEnd:
879 displays_views_colorspaces.append(
880 [single_display_name, display_cleaned,
885 config.addDisplay(single_display_name,
886 display_cleaned, colorspace.name)
889 if not (display_cleaned in views):
890 views.append(display_cleaned)
894 config.addDisplay(single_display_name, display_cleaned,
898 if not (display_cleaned in views):
899 views.append(display_cleaned)
901 # Add to config any display, view combinations that were saved for later
902 # This list will be empty unless viewsWithLooksAtEnd is set to True above
903 for display_view_colorspace in displays_views_colorspaces:
904 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
907 config.addDisplay(single_display_name, display_cleaned,
911 if not (display_cleaned in views):
912 views.append(display_cleaned)
915 # Works with Nuke Studio and Mari, but not Nuke
916 # single_display_name = 'Utility'
917 # displays.append(single_display_name)
919 raw_display_space_name = config_data['roles']['data']
920 log_display_space_name = config_data['roles']['compositing_log']
922 # Find the newly-prefixed colorspace names
924 # print( prefixed_names )
925 raw_display_space_name = prefixed_names[raw_display_space_name]
926 log_display_space_name = prefixed_names[log_display_space_name]
928 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
930 config.addDisplay(single_display_name, 'Log', log_display_space_name)
933 # Setting the active *displays* and *views*.
934 config.setActiveDisplays(','.join(sorted(displays)))
935 config.setActiveViews(','.join(views))
939 # Make sure we didn't create a bad config
942 # Reset the colorspace names back to their non-prefixed versions
944 # Build the reverse lookup
945 prefixed_names_inverse = {}
946 for original, prefixed in prefixed_names.iteritems():
947 prefixed_names_inverse[prefixed] = original
949 # Reset the reference colorspace name
950 reference_data.name = prefixed_names_inverse[reference_data.name]
952 # Reset the rest of the colorspace names
954 for colorspace in config_data['colorSpaces']:
955 colorspace.name = prefixed_names_inverse[colorspace.name]
957 print("Prefixed names")
958 for original, prefixed in prefixed_names.iteritems():
959 print("%s, %s" % (original, prefixed))
963 print("Inverse Lookup of Prefixed names")
964 for prefixed, original in prefixed_names_inverse.iteritems():
965 print("%s, %s" % (prefixed, original))
971 def generate_LUTs(odt_info,
976 lut_resolution_1d=4096,
977 lut_resolution_3d=64,
985 Parameter description.
990 Colorspaces and transforms converting between those colorspaces and
991 the reference colorspace, *ACES*.
994 print('generateLUTs - begin')
997 # Initialize a few variables
998 config_data['displays'] = {}
999 config_data['colorSpaces'] = []
1001 # -------------------------------------------------------------------------
1002 # *ACES Color Spaces*
1003 # -------------------------------------------------------------------------
1005 # *ACES* colorspaces
1009 aces_log_display_space,
1011 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1020 config_data['referenceColorSpace'] = aces_reference
1021 config_data['roles'] = aces_roles
1023 for cs in aces_colorspaces:
1024 config_data['colorSpaces'].append(cs)
1026 for name, data in aces_displays.iteritems():
1027 config_data['displays'][name] = data
1029 config_data['defaultDisplay'] = aces_default_display
1030 config_data['linearDisplaySpace'] = aces_reference
1031 config_data['logDisplaySpace'] = aces_log_display_space
1033 # -------------------------------------------------------------------------
1034 # *Camera Input Transforms*
1035 # -------------------------------------------------------------------------
1037 # *ARRI Log-C* to *ACES*.
1038 arri_colorSpaces = arri.create_colorspaces(lut_directory,
1040 for cs in arri_colorSpaces:
1041 config_data['colorSpaces'].append(cs)
1043 # *Canon-Log* to *ACES*.
1044 canon_colorspaces = canon.create_colorspaces(lut_directory,
1046 for cs in canon_colorspaces:
1047 config_data['colorSpaces'].append(cs)
1049 # *GoPro Protune* to *ACES*.
1050 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1052 for cs in gopro_colorspaces:
1053 config_data['colorSpaces'].append(cs)
1055 # *Panasonic V-Log* to *ACES*.
1056 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1058 for cs in panasonic_colorSpaces:
1059 config_data['colorSpaces'].append(cs)
1061 # *RED* colorspaces to *ACES*.
1062 red_colorspaces = red.create_colorspaces(lut_directory,
1064 for cs in red_colorspaces:
1065 config_data['colorSpaces'].append(cs)
1067 # *S-Log* to *ACES*.
1068 sony_colorSpaces = sony.create_colorspaces(lut_directory,
1070 for cs in sony_colorSpaces:
1071 config_data['colorSpaces'].append(cs)
1073 # -------------------------------------------------------------------------
1074 # General Color Spaces
1075 # -------------------------------------------------------------------------
1076 general_colorSpaces = general.create_colorspaces(lut_directory,
1079 for cs in general_colorSpaces:
1080 config_data['colorSpaces'].append(cs)
1082 # The *Raw* color space
1083 raw = general.create_raw()
1084 config_data['colorSpaces'].append(raw)
1086 # Override certain roles, for now
1087 config_data['roles']['data'] = raw.name
1088 config_data['roles']['reference'] = raw.name
1089 config_data['roles']['texture_paint'] = raw.name
1091 print('generateLUTs - end')
1095 def generate_baked_LUTs(odt_info,
1101 lut_resolution_shaper=1024,
1109 Parameter description.
1114 Return value description.
1117 odt_info_C = dict(odt_info)
1119 # Uncomment if you would like to support the older behavior where ODTs
1120 # that have support for full and legal range output generate a LUT for each.
1122 # Create two entries for ODTs that have full and legal range support
1123 for odt_ctl_name, odt_values in odt_info.iteritems():
1124 if odt_values['transformHasFullLegalSwitch']:
1125 odt_name = odt_values['transformUserName']
1127 odt_values_legal = dict(odt_values)
1128 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1129 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1131 odt_values_full = dict(odt_values)
1132 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1133 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1135 del (odt_info_C[odt_ctl_name])
1138 # Generate appropriate LUTs for each ODT
1139 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1140 odt_prefix = odt_values['transformUserNamePrefix']
1141 odt_name = odt_values['transformUserName']
1144 for input_space in ['ACEScc', 'ACESproxy']:
1145 args = ['--iconfig', config_path,
1148 args += ['--inputspace', "ACES - %s" % input_space]
1149 args += ['--outputspace', "Output - %s" % odt_name]
1151 args += ['--inputspace', input_space]
1152 args += ['--outputspace', odt_name]
1154 args += ['--description',
1155 '%s - %s for %s data' % (odt_prefix,
1159 args += ['--shaperspace', "Utility - %s" % shaper_name,
1160 '--shapersize', str(lut_resolution_shaper)]
1162 args += ['--shaperspace', shaper_name,
1163 '--shapersize', str(lut_resolution_shaper)]
1164 args += ['--cubesize', str(lut_resolution_3d)]
1165 args += ['--format',
1167 os.path.join(baked_directory,
1169 '%s for %s.icc' % (odt_name, input_space))]
1171 bake_lut = Process(description='bake a LUT',
1177 for input_space in ['ACEScc', 'ACESproxy']:
1178 args = ['--iconfig', config_path,
1181 args += ['--inputspace', "ACES - %s" % input_space]
1182 args += ['--outputspace', "Output - %s" % odt_name]
1184 args += ['--inputspace', input_space]
1185 args += ['--outputspace', odt_name]
1186 args += ['--description',
1187 '%s - %s for %s data' % (
1188 odt_prefix, odt_name, input_space)]
1190 args += ['--shaperspace', "Utility - %s" % shaper_name,
1191 '--shapersize', str(lut_resolution_shaper)]
1193 args += ['--shaperspace', shaper_name,
1194 '--shapersize', str(lut_resolution_shaper)]
1195 args += ['--cubesize', str(lut_resolution_3d)]
1197 fargs = ['--format',
1202 '%s for %s Flame.3dl' % (odt_name, input_space))]
1203 bake_lut = Process(description='bake a LUT',
1205 args=(args + fargs))
1208 largs = ['--format',
1213 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1214 bake_lut = Process(description='bake a LUT',
1216 args=(args + largs))
1220 for input_space in ['ACEScg', 'ACES2065-1']:
1221 args = ['--iconfig', config_path,
1224 args += ['--inputspace', "ACES - %s" % input_space]
1225 args += ['--outputspace', "Output - %s" % odt_name]
1227 args += ['--inputspace', input_space]
1228 args += ['--outputspace', odt_name]
1229 args += ['--description',
1230 '%s - %s for %s data' % (
1231 odt_prefix, odt_name, input_space)]
1232 if input_space == 'ACEScg':
1233 lin_shaper_name = "%s - AP1" % shaper_name
1235 lin_shaper_name = shaper_name
1237 lin_shaper_name = "Utility - %s" % lin_shaper_name
1238 args += ['--shaperspace', lin_shaper_name,
1239 '--shapersize', str(lut_resolution_shaper)]
1241 args += ['--cubesize', str(lut_resolution_3d)]
1243 margs = ['--format',
1248 '%s for %s Maya.csp' % (odt_name, input_space))]
1249 bake_lut = Process(description='bake a LUT',
1251 args=(args + margs))
1254 hargs = ['--format',
1259 '%s for %s Houdini.lut' % (odt_name, input_space))]
1260 bake_lut = Process(description='bake a LUT',
1262 args=(args + hargs))
1266 def create_config_dir(config_directory,
1267 bake_secondary_LUTs=False,
1268 custom_lut_dir=None):
1275 Parameter description.
1280 Return value description.
1283 lut_directory = os.path.join(config_directory, 'luts')
1284 dirs = [config_directory, lut_directory]
1286 if bake_secondary_LUTs:
1287 dirs.extend([os.path.join(config_directory, 'baked'),
1288 os.path.join(config_directory, 'baked', 'flame'),
1289 os.path.join(config_directory, 'baked', 'photoshop'),
1290 os.path.join(config_directory, 'baked', 'houdini'),
1291 os.path.join(config_directory, 'baked', 'lustre'),
1292 os.path.join(config_directory, 'baked', 'maya')])
1295 dirs.append(os.path.join(config_directory, 'custom'))
1298 not os.path.exists(d) and os.mkdir(d)
1300 return lut_directory
1303 def create_ACES_config(aces_ctl_directory,
1305 lut_resolution_1d=4096,
1306 lut_resolution_3d=64,
1307 bake_secondary_LUTs=True,
1308 multiple_displays=False,
1310 copy_custom_luts=True,
1312 prefix_colorspaces_with_family_names=True):
1314 Creates the ACES configuration.
1319 Parameter description.
1324 Return value description.
1327 # Directory for custom LUTs
1328 custom_lut_dir = None
1329 if copy_custom_luts:
1330 custom_lut_dir = os.path.join(config_directory, "custom")
1332 lut_directory = create_config_dir(config_directory,
1333 bake_secondary_LUTs,
1336 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1337 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1339 shaper_name = 'Output Shaper'
1340 config_data = generate_LUTs(odt_info,
1349 print('Creating config - with prefixes, with aliases')
1350 config = create_config(config_data,
1351 prefix=prefix_colorspaces_with_family_names,
1353 multiple_displays=multiple_displays,
1354 look_info=look_info,
1355 custom_lut_dir=custom_lut_dir)
1358 write_config(config,
1359 os.path.join(config_directory, 'config.ocio'))
1361 if bake_secondary_LUTs:
1362 generate_baked_LUTs(odt_info,
1364 os.path.join(config_directory, 'baked'),
1365 os.path.join(config_directory, 'config.ocio'),
1369 prefix=prefix_colorspaces_with_family_names)
1381 Parameter description.
1386 Return value description.
1391 usage = '%prog [options]\n'
1393 usage += 'An OCIO config generation script for ACES 1.0\n'
1395 usage += 'Command line examples'
1397 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1398 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1400 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1401 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1404 usage += 'Adding custom looks'
1406 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1407 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'
1409 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1410 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'
1412 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'
1414 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1415 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'
1417 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1418 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'
1420 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'
1425 def look_info_callback(option, opt_str, value, parser):
1426 print("look_info_callback")
1427 print(option, opt_str, value, parser)
1428 if opt_str == "--addCustomLookCDL":
1429 look_info.append(value)
1430 elif opt_str == "--addCustomLookLUT":
1431 look_info.append(value)
1432 elif opt_str == "--addACESLookCDL":
1433 look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1434 elif opt_str == "--addACESLookLUT":
1435 look_info.append([value[0], "ACES - ACEScc", value[1]])
1437 p = optparse.OptionParser(description='',
1438 prog='create_aces_config',
1439 version='create_aces_config 1.0',
1441 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1442 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1443 p.add_option('--configDir', '-c', default=os.environ.get(
1444 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1445 p.add_option('--lutResolution1d', default=4096)
1446 p.add_option('--lutResolution3d', default=64)
1447 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1448 p.add_option('--keepTempImages', action='store_true', default=False)
1450 p.add_option('--createMultipleDisplays', action='store_true',
1453 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1454 action="callback", callback=look_info_callback)
1455 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1456 action="callback", callback=look_info_callback)
1457 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1458 action="callback", callback=look_info_callback)
1459 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1460 action="callback", callback=look_info_callback)
1461 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1463 options, arguments = p.parse_args()
1465 aces_ctl_directory = options.acesCTLDir
1466 config_directory = options.configDir
1467 lut_resolution_1d = int(options.lutResolution1d)
1468 lut_resolution_3d = int(options.lutResolution3d)
1469 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1470 cleanup_temp_images = not options.keepTempImages
1471 multiple_displays = options.createMultipleDisplays
1472 copy_custom_luts = options.copyCustomLUTs
1476 # TODO: Investigate the following statements.
1478 args_start = sys.argv.index('--') + 1
1479 args = sys.argv[args_start:]
1481 args_start = len(sys.argv) + 1
1484 print('command line : \n%s\n' % ' '.join(sys.argv))
1486 assert aces_ctl_directory is not None, (
1487 'process: No "{0}" environment variable defined or no "ACES CTL" '
1488 'directory specified'.format(
1489 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1491 assert config_directory is not None, (
1492 'process: No "{0}" environment variable defined or no configuration '
1493 'directory specified'.format(
1494 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1496 return create_ACES_config(aces_ctl_directory,
1500 bake_secondary_luts,
1504 cleanup_temp_images)
1507 if __name__ == '__main__':