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 replace, ColorSpace, compact
28 __author__ = 'ACES Developers'
29 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
31 __maintainer__ = 'ACES Developers'
32 __email__ = 'aces@oscars.org'
33 __status__ = 'Production'
35 __all__ = ['ACES_OCIO_CTL_DIRECTORY_ENVIRON',
36 'ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON',
37 'set_config_default_roles',
39 'generate_OCIO_transform',
40 'add_colorspace_alias',
43 'generate_baked_LUTs',
48 ACES_OCIO_CTL_DIRECTORY_ENVIRON = 'ACES_OCIO_CTL_DIRECTORY'
49 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON = 'ACES_OCIO_CONFIGURATION_DIRECTORY'
52 def set_config_default_roles(config,
63 compositing_linear=''):
65 Sets given *OCIO* configuration default roles.
71 color_picking : str or unicode
72 Color picking role title.
73 color_timing : str or unicode
74 Color timing role title.
75 compositing_log : str or unicode
76 Compositing log role title.
79 default : str or unicode
81 matte_paint : str or unicode
82 Matte painting role title.
83 reference : str or unicode
85 scene_linear : str or unicode
86 Scene linear role title.
87 texture_paint : str or unicode
88 Texture painting role title.
97 config.setRole(ocio.Constants.ROLE_COLOR_PICKING, color_picking)
99 config.setRole(ocio.Constants.ROLE_COLOR_TIMING, color_timing)
101 config.setRole(ocio.Constants.ROLE_COMPOSITING_LOG, compositing_log)
103 config.setRole(ocio.Constants.ROLE_DATA, data)
105 config.setRole(ocio.Constants.ROLE_DEFAULT, default)
107 config.setRole(ocio.Constants.ROLE_MATTE_PAINT, matte_paint)
109 config.setRole(ocio.Constants.ROLE_REFERENCE, reference)
111 config.setRole(ocio.Constants.ROLE_TEXTURE_PAINT, texture_paint)
113 # 'rendering' and 'compositing_linear' roles default to the 'scene_linear'
114 # value if not set explicitly
116 config.setRole("rendering", rendering)
117 if compositing_linear:
118 config.setRole("compositing_linear", compositing_linear)
120 config.setRole(ocio.Constants.ROLE_SCENE_LINEAR, scene_linear)
122 config.setRole("rendering", scene_linear)
123 if not compositing_linear:
124 config.setRole("compositing_linear", scene_linear)
129 def write_config(config, config_path, sanity_check=True):
131 Writes the configuration to given path.
136 Parameter description.
141 Return value description.
149 print 'Configuration was not written due to a failed Sanity Check'
152 with open(config_path, mode='w') as fp:
153 fp.write(config.serialize())
156 def generate_OCIO_transform(transforms):
163 Parameter description.
168 Return value description.
171 interpolation_options = {
172 'linear': ocio.Constants.INTERP_LINEAR,
173 'nearest': ocio.Constants.INTERP_NEAREST,
174 'tetrahedral': ocio.Constants.INTERP_TETRAHEDRAL}
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():
315 'Skipping alias creation for %s, alias %s, 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:
326 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
328 ocio_colorspace_alias = ocio.ColorSpace(
330 bitDepth=colorspace.bit_depth,
331 description=description,
332 equalityGroup=colorspace.equality_group,
333 family=compact_family_name,
334 isData=colorspace.is_data,
335 allocation=colorspace.allocation_type,
336 allocationVars=colorspace.allocation_vars)
338 if colorspace.to_reference_transforms:
339 print('\tGenerating To-Reference transforms')
340 ocio_transform = generate_OCIO_transform(
341 [{'type': 'colorspace',
342 'src': colorspace.name,
343 'dst': reference_colorspace.name,
344 'direction': 'forward'}])
345 ocio_colorspace_alias.setTransform(
347 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
349 if colorspace.from_reference_transforms:
350 print('\tGenerating From-Reference transforms')
351 ocio_transform = generate_OCIO_transform(
352 [{'type': 'colorspace',
353 'src': reference_colorspace.name,
354 'dst': colorspace.name,
355 'direction': 'forward'}])
356 ocio_colorspace_alias.setTransform(
358 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
360 config.addColorSpace(ocio_colorspace_alias)
363 def colorspace_prefixed_name(colorspace):
364 prefix = colorspace.family.replace("/", " - ")
365 return "%s - %s" % (prefix, colorspace.name)
374 multiple_displays=False):
381 Parameter description.
386 Return value description.
390 look_colorspace = look[1]
396 print('Adding look %s - %s' % (look_name, ", ".join(look)))
402 if not '$' in look_lut:
403 print("Getting ready to copy look lut : %s" % look_lut)
404 shutil.copy2(look_lut, custom_lut_dir)
405 look_lut = os.path.split(look_lut)[1]
407 print("Skipping LUT copy because path contains a context variable")
413 print('Adding look to config')
415 lk1.setName(look_name)
416 lk1.setProcessSpace(look_colorspace)
418 keys = {'type': 'lutFile',
420 'direction': 'forward'}
422 keys['cccid'] = look_cccid
424 ocio_transform = generate_OCIO_transform([keys])
425 lk1.setTransform(ocio_transform)
430 print("Creating aliased colorspace")
433 # Create OCIO colorspace that references that look
434 # - Needed for some implementations that don't process looks well
435 # - Also needed for some implementations that don't expose looks well
437 look_aliases = ["look_%s" % compact(look_name)]
438 colorspace = ColorSpace(look_name,
439 aliases=look_aliases,
440 description="The %s Look colorspace" % look_name,
443 colorspace.from_reference_transforms = [{'type': 'look',
445 'src': reference_name,
446 'dst': reference_name,
447 'direction': 'forward'}]
449 print('Adding colorspace %s, alias to look %s to config data' % (
450 look_name, look_name))
452 # Add this colorspace into the main list of colorspaces
453 config_data['colorSpaces'].append(colorspace)
458 def integrate_looks_into_views(config,
462 multiple_displays=False):
469 Parameter description.
474 Return value description.
476 look_names = [look[0] for look in looks]
478 # Option 1 - Add a 'look' to each Display
479 # - Assumes there is a Display for each ACES Output Transform
480 if multiple_displays:
481 for look_name in look_names:
482 config_data['looks'].append(look_name)
485 # - Copy each Output Transform colorspace
486 # - For each copy, add a LookTransform at the head of the from_reference
488 # - Add these new copied colorspaces for the Displays / Views
490 for display, view_list in config_data['displays'].iteritems():
491 output_colorspace_copy = None
492 look_names_string = ""
493 for view_name, output_colorspace in view_list.iteritems():
494 if view_name == "Output Transform":
496 print("Adding new View that incorporates looks")
498 # Make a copy of the output colorspace
499 output_colorspace_copy = copy.deepcopy(output_colorspace)
501 # for look_name in look_names:
502 for i in range(len(look_names)):
503 look_name = look_names[i]
505 # Add the LookTransform to the head of the from_reference transform list
506 if output_colorspace_copy.from_reference_transforms:
507 output_colorspace_copy.from_reference_transforms.insert(
510 'src': reference_name,
511 'dst': reference_name,
512 'direction': 'forward'})
514 # Add the LookTransform to the end of the to_reference transform list
515 if output_colorspace_copy.to_reference_transforms:
516 inverse_look_name = look_names[
517 len(look_names) - 1 - i]
519 output_colorspace_copy.to_reference_transforms.append(
521 'look': inverse_look_name,
522 'src': reference_name,
523 'dst': reference_name,
524 'direction': 'inverse'})
526 if not look_name in config_data['looks']:
527 config_data['looks'].append(look_name)
529 look_names_string = ", ".join(look_names)
530 output_colorspace_copy.name = "%s with %s" % (
531 output_colorspace.name, look_names_string)
532 output_colorspace_copy.aliases = [
533 "out_%s" % compact(output_colorspace_copy.name)]
536 "Colorspace that incorporates looks created : %s" % output_colorspace_copy.name)
538 config_data['colorSpaces'].append(output_colorspace_copy)
540 if output_colorspace_copy:
542 "Adding colorspace that incorporates looks into view list")
544 # Change the name of the View
546 "Output Transform with %s" % look_names_string] = output_colorspace_copy
547 config_data['displays'][display] = view_list
549 # print( "Display : %s, View List : %s" % (display, ", ".join(view_list)) )
552 def create_config(config_data,
555 multiple_displays=False,
557 custom_lut_dir=None):
564 Parameter description.
569 Return value description.
573 alias_colorspaces = []
575 # Creating the *OCIO* configuration.
576 config = ocio.Config()
578 # Setting configuration description.
579 config.setDescription('An ACES config generated from python')
581 # Setting configuration search path.
582 searchPath = ['luts']
584 searchPath.append('custom')
585 config.setSearchPath(':'.join(searchPath))
587 # Defining the reference colorspace.
588 reference_data = config_data['referenceColorSpace']
590 # Adding the color space Family into the name
591 # Helps with applications that present colorspaces as one long list
593 prefixed_name = colorspace_prefixed_name(reference_data)
594 prefixed_names[reference_data.name] = prefixed_name
595 reference_data.name = prefixed_name
597 print('Adding the reference color space : %s' % reference_data.name)
599 reference = ocio.ColorSpace(
600 name=reference_data.name,
601 bitDepth=reference_data.bit_depth,
602 description=reference_data.description,
603 equalityGroup=reference_data.equality_group,
604 family=reference_data.family,
605 isData=reference_data.is_data,
606 allocation=reference_data.allocation_type,
607 allocationVars=reference_data.allocation_vars)
609 config.addColorSpace(reference)
613 if reference_data.aliases != []:
614 # add_colorspace_alias(config, reference_data,
615 # reference_data, reference_data.aliases)
616 # defer adding alias colorspaces until end. Helps with some applications
617 alias_colorspaces.append(
618 [reference_data, reference_data, reference_data.aliases])
622 # print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
625 # Add Looks and Look colorspaces
628 print('Adding looks')
630 config_data['looks'] = []
632 # Add looks and colorspaces
633 for look in look_info:
641 # Integrate looks with displays, views
642 integrate_looks_into_views(config,
650 print('Adding the regular color spaces')
652 # Creating the remaining colorspaces.
653 for colorspace in sorted(config_data['colorSpaces']):
654 # Adding the color space Family into the name
655 # Helps with applications that present colorspaces as one long list
657 prefixed_name = colorspace_prefixed_name(colorspace)
658 prefixed_names[colorspace.name] = prefixed_name
659 colorspace.name = prefixed_name
661 print('Creating new color space : %s' % colorspace.name)
663 description = colorspace.description
664 if colorspace.aces_transform_id:
665 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
667 ocio_colorspace = ocio.ColorSpace(
668 name=colorspace.name,
669 bitDepth=colorspace.bit_depth,
670 description=description,
671 equalityGroup=colorspace.equality_group,
672 family=colorspace.family,
673 isData=colorspace.is_data,
674 allocation=colorspace.allocation_type,
675 allocationVars=colorspace.allocation_vars)
677 if colorspace.to_reference_transforms:
678 print('\tGenerating To-Reference transforms')
679 ocio_transform = generate_OCIO_transform(
680 colorspace.to_reference_transforms)
681 ocio_colorspace.setTransform(
683 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
685 if colorspace.from_reference_transforms:
686 print('\tGenerating From-Reference transforms')
687 ocio_transform = generate_OCIO_transform(
688 colorspace.from_reference_transforms)
689 ocio_colorspace.setTransform(
691 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
693 config.addColorSpace(ocio_colorspace)
696 # Add alias to normal colorspace, using compact name
699 if colorspace.aliases != []:
700 # add_colorspace_alias(config, reference_data,
701 # colorspace, colorspace.aliases)
702 # defer adding alias colorspaces until end. Helps with some applications
703 alias_colorspaces.append(
704 [reference_data, colorspace, colorspace.aliases])
711 # We add roles early so we can create alias colorspaces with the names of the roles
712 # before the rest of the colorspace aliases are added to the config.
714 print('Setting the roles')
717 set_config_default_roles(
719 color_picking=prefixed_names[
720 config_data['roles']['color_picking']],
721 color_timing=prefixed_names[config_data['roles']['color_timing']],
722 compositing_log=prefixed_names[
723 config_data['roles']['compositing_log']],
724 data=prefixed_names[config_data['roles']['data']],
725 default=prefixed_names[config_data['roles']['default']],
726 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
727 reference=prefixed_names[config_data['roles']['reference']],
728 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
729 texture_paint=prefixed_names[
730 config_data['roles']['texture_paint']])
732 # Not allowed for the moment. role names can not overlap with colorspace names.
734 # Add the aliased colorspaces for each role
735 for role_name, role_colorspace_name in config_data['roles'].iteritems():
736 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
738 print( "Finding colorspace : %s" % role_colorspace_prefixed_name )
739 # Find the colorspace pointed to by the role
740 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_prefixed_name]
741 role_colorspace = None
742 if len(role_colorspaces) > 0:
743 role_colorspace = role_colorspaces[0]
745 if reference_data.name == role_colorspace_prefixed_name:
746 role_colorspace = reference_data
749 print( "Adding an alias colorspace named %s, pointing to %s" % (
750 role_name, role_colorspace.name))
752 add_colorspace_aliases(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 with colorspace names.
770 # Add the aliased colorspaces for each role
771 for role_name, role_colorspace_name in config_data['roles'].iteritems():
772 # Find the colorspace pointed to by the role
773 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_name]
774 role_colorspace = None
775 if len(role_colorspaces) > 0:
776 role_colorspace = role_colorspaces[0]
778 if reference_data.name == role_colorspace_name:
779 role_colorspace = reference_data
782 print( "Adding an alias colorspace named %s, pointing to %s" % (
783 role_name, role_colorspace.name))
785 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
790 # We add these at the end as some applications use the order of the colorspaces
791 # definitions in the config to order the colorspaces in their selection lists.
792 # Other go alphabetically. This should keep the alias colorspaces out of the way
793 # for the apps that use the order of definition in the config.
794 print('Adding the alias colorspaces')
795 for reference, colorspace, aliases in alias_colorspaces:
796 add_colorspace_aliases(config, reference, colorspace, aliases)
800 print('Adding the diplays and views')
802 # Set the color_picking role to be the first Display's Output Transform View
803 default_display_name = config_data['defaultDisplay']
804 default_display_views = config_data['displays'][default_display_name]
805 default_display_colorspace = default_display_views['Output Transform']
807 set_config_default_roles(
809 color_picking=default_display_colorspace.name)
811 # Defining the *views* and *displays*.
815 # Defining a *generic* *display* and *view* setup.
816 if multiple_displays:
817 # Built list of looks to add to Displays
818 looks = config_data['looks'] if ('looks' in config_data) else []
819 looks = ", ".join(looks)
820 print("Creating multiple displays, with looks : %s" % looks)
822 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
823 # because OCIO will order them alphabetically when the config is written to disk.
825 # Create Displays, Views
826 for display, view_list in config_data['displays'].iteritems():
827 for view_name, colorspace in view_list.iteritems():
828 config.addDisplay(display, view_name, colorspace.name, looks)
829 if 'Output Transform' in view_name and looks != "":
830 # Add normal View, without looks
831 config.addDisplay(display, view_name, colorspace.name)
833 # Add View with looks
834 view_name_with_looks = "%s with %s" % (view_name, looks)
835 config.addDisplay(display, view_name_with_looks,
836 colorspace.name, looks)
838 config.addDisplay(display, view_name, colorspace.name)
839 if not (view_name in views):
840 views.append(view_name)
841 displays.append(display)
843 # Defining the set of *views* and *displays* useful in a *GUI* context.
845 single_display_name = 'ACES'
846 # single_display_name = config_data['roles']['scene_linear']
847 displays.append(single_display_name)
849 # Make sure the default display is first
850 display_names = sorted(config_data['displays'])
851 display_names.insert(0, display_names.pop(
852 display_names.index(default_display_name)))
854 # Built list of looks to add to Displays
855 looks = config_data['looks'] if ('looks' in config_data) else []
856 look_names = ", ".join(looks)
858 displays_views_colorspaces = []
860 # Create Displays, Views
861 for display in display_names:
862 view_list = config_data['displays'][display]
863 for view_name, colorspace in view_list.iteritems():
864 if 'Output Transform' in view_name:
865 # print( "Adding view for %s" % colorspace.name )
867 # We use the Display names as the View names in this case
868 # as there is a single Display that contains all views.
869 # This works for more applications than not, as of the time of this implementation.
871 # Maya 2016 doesn't like parentheses in View names
872 display_cleaned = replace(display, {')': '', '(': ''})
874 # If View includes looks
875 if 'with' in view_name:
876 # Integrate looks into view name
877 display_cleaned = "%s with %s" % (
878 display_cleaned, look_names)
880 viewsWithLooksAtEnd = False
881 # Storing combo of display, view and colorspace name in a list so we can
882 # add them to the end of the list
883 if viewsWithLooksAtEnd:
884 displays_views_colorspaces.append(
885 [single_display_name, display_cleaned,
890 config.addDisplay(single_display_name,
891 display_cleaned, colorspace.name)
894 if not (display_cleaned in views):
895 views.append(display_cleaned)
899 config.addDisplay(single_display_name, display_cleaned,
903 if not (display_cleaned in views):
904 views.append(display_cleaned)
906 # Add to config any display, view combinations that were saved for later
907 # This list will be empty unless viewsWithLooksAtEnd is set to True above
908 for display_view_colorspace in displays_views_colorspaces:
909 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
912 config.addDisplay(single_display_name, display_cleaned,
916 if not (display_cleaned in views):
917 views.append(display_cleaned)
920 # Works with Nuke Studio and Mari, but not Nuke
921 # single_display_name = 'Utility'
922 # displays.append(single_display_name)
924 raw_display_space_name = config_data['roles']['data']
925 log_display_space_name = config_data['roles']['compositing_log']
927 # Find the newly-prefixed colorspace names
929 # print( prefixed_names )
930 raw_display_space_name = prefixed_names[raw_display_space_name]
931 log_display_space_name = prefixed_names[log_display_space_name]
933 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
935 config.addDisplay(single_display_name, 'Log', log_display_space_name)
938 # Setting the active *displays* and *views*.
939 config.setActiveDisplays(','.join(sorted(displays)))
940 config.setActiveViews(','.join(views))
944 # Make sure we didn't create a bad config
947 # Reset the colorspace names back to their non-prefixed versions
949 # Build the reverse lookup
950 prefixed_names_inverse = {}
951 for original, prefixed in prefixed_names.iteritems():
952 prefixed_names_inverse[prefixed] = original
954 # Reset the reference colorspace name
955 reference_data.name = prefixed_names_inverse[reference_data.name]
957 # Reset the rest of the colorspace names
959 for colorspace in config_data['colorSpaces']:
960 colorspace.name = prefixed_names_inverse[colorspace.name]
962 print("Prefixed names")
963 for original, prefixed in prefixed_names.iteritems():
964 print("%s, %s" % (original, prefixed))
968 print("Inverse Lookup of Prefixed names")
969 for prefixed, original in prefixed_names_inverse.iteritems():
970 print("%s, %s" % (prefixed, original))
976 def generate_LUTs(odt_info,
981 lut_resolution_1d=4096,
982 lut_resolution_3d=64,
990 Parameter description.
995 Colorspaces and transforms converting between those colorspaces and
996 the reference colorspace, *ACES*.
999 print('generateLUTs - begin')
1002 # Initialize a few variables
1003 config_data['displays'] = {}
1004 config_data['colorSpaces'] = []
1006 # -------------------------------------------------------------------------
1007 # *ACES Color Spaces*
1008 # -------------------------------------------------------------------------
1010 # *ACES* colorspaces
1014 aces_log_display_space,
1016 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1025 config_data['referenceColorSpace'] = aces_reference
1026 config_data['roles'] = aces_roles
1028 for cs in aces_colorspaces:
1029 config_data['colorSpaces'].append(cs)
1031 for name, data in aces_displays.iteritems():
1032 config_data['displays'][name] = data
1034 config_data['defaultDisplay'] = aces_default_display
1035 config_data['linearDisplaySpace'] = aces_reference
1036 config_data['logDisplaySpace'] = aces_log_display_space
1038 # -------------------------------------------------------------------------
1039 # *Camera Input Transforms*
1040 # -------------------------------------------------------------------------
1042 # *ARRI Log-C* to *ACES*.
1043 arri_colorSpaces = arri.create_colorspaces(lut_directory,
1045 for cs in arri_colorSpaces:
1046 config_data['colorSpaces'].append(cs)
1048 # *Canon-Log* to *ACES*.
1049 canon_colorspaces = canon.create_colorspaces(lut_directory,
1051 for cs in canon_colorspaces:
1052 config_data['colorSpaces'].append(cs)
1054 # *GoPro Protune* to *ACES*.
1055 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1057 for cs in gopro_colorspaces:
1058 config_data['colorSpaces'].append(cs)
1060 # *Panasonic V-Log* to *ACES*.
1061 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1063 for cs in panasonic_colorSpaces:
1064 config_data['colorSpaces'].append(cs)
1066 # *RED* colorspaces to *ACES*.
1067 red_colorspaces = red.create_colorspaces(lut_directory,
1069 for cs in red_colorspaces:
1070 config_data['colorSpaces'].append(cs)
1072 # *S-Log* to *ACES*.
1073 sony_colorSpaces = sony.create_colorspaces(lut_directory,
1075 for cs in sony_colorSpaces:
1076 config_data['colorSpaces'].append(cs)
1078 # -------------------------------------------------------------------------
1079 # General Color Spaces
1080 # -------------------------------------------------------------------------
1081 general_colorSpaces = general.create_colorspaces(lut_directory,
1084 for cs in general_colorSpaces:
1085 config_data['colorSpaces'].append(cs)
1087 # The *Raw* color space
1088 raw = general.create_raw()
1089 config_data['colorSpaces'].append(raw)
1091 # Override certain roles, for now
1092 config_data['roles']['data'] = raw.name
1093 config_data['roles']['reference'] = raw.name
1094 config_data['roles']['texture_paint'] = raw.name
1096 print('generateLUTs - end')
1100 def generate_baked_LUTs(odt_info,
1106 lut_resolution_shaper=1024,
1114 Parameter description.
1119 Return value description.
1122 odt_info_C = dict(odt_info)
1124 # Uncomment if you would like to support the older behavior where ODTs
1125 # that have support for full and legal range output generate a LUT for each.
1127 # Create two entries for ODTs that have full and legal range support
1128 for odt_ctl_name, odt_values in odt_info.iteritems():
1129 if odt_values['transformHasFullLegalSwitch']:
1130 odt_name = odt_values['transformUserName']
1132 odt_values_legal = dict(odt_values)
1133 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1134 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1136 odt_values_full = dict(odt_values)
1137 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1138 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1140 del (odt_info_C[odt_ctl_name])
1143 # Generate appropriate LUTs for each ODT
1144 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1145 odt_prefix = odt_values['transformUserNamePrefix']
1146 odt_name = odt_values['transformUserName']
1149 for input_space in ['ACEScc', 'ACESproxy']:
1150 args = ['--iconfig', config_path,
1153 args += ['--inputspace', "ACES - %s" % input_space]
1154 args += ['--outputspace', "Output - %s" % odt_name]
1156 args += ['--inputspace', input_space]
1157 args += ['--outputspace', odt_name]
1159 args += ['--description',
1160 '%s - %s for %s data' % (odt_prefix,
1164 args += ['--shaperspace', "Utility - %s" % shaper_name,
1165 '--shapersize', str(lut_resolution_shaper)]
1167 args += ['--shaperspace', shaper_name,
1168 '--shapersize', str(lut_resolution_shaper)]
1169 args += ['--cubesize', str(lut_resolution_3d)]
1170 args += ['--format',
1172 os.path.join(baked_directory,
1174 '%s for %s.icc' % (odt_name, input_space))]
1176 bake_lut = Process(description='bake a LUT',
1182 for input_space in ['ACEScc', 'ACESproxy']:
1183 args = ['--iconfig', config_path,
1186 args += ['--inputspace', "ACES - %s" % input_space]
1187 args += ['--outputspace', "Output - %s" % odt_name]
1189 args += ['--inputspace', input_space]
1190 args += ['--outputspace', odt_name]
1191 args += ['--description',
1192 '%s - %s for %s data' % (
1193 odt_prefix, odt_name, input_space)]
1195 args += ['--shaperspace', "Utility - %s" % shaper_name,
1196 '--shapersize', str(lut_resolution_shaper)]
1198 args += ['--shaperspace', shaper_name,
1199 '--shapersize', str(lut_resolution_shaper)]
1200 args += ['--cubesize', str(lut_resolution_3d)]
1202 fargs = ['--format',
1207 '%s for %s Flame.3dl' % (odt_name, input_space))]
1208 bake_lut = Process(description='bake a LUT',
1210 args=(args + fargs))
1213 largs = ['--format',
1218 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1219 bake_lut = Process(description='bake a LUT',
1221 args=(args + largs))
1225 for input_space in ['ACEScg', 'ACES2065-1']:
1226 args = ['--iconfig', config_path,
1229 args += ['--inputspace', "ACES - %s" % input_space]
1230 args += ['--outputspace', "Output - %s" % odt_name]
1232 args += ['--inputspace', input_space]
1233 args += ['--outputspace', odt_name]
1234 args += ['--description',
1235 '%s - %s for %s data' % (
1236 odt_prefix, odt_name, input_space)]
1237 if input_space == 'ACEScg':
1238 lin_shaper_name = "%s - AP1" % shaper_name
1240 lin_shaper_name = shaper_name
1242 lin_shaper_name = "Utility - %s" % lin_shaper_name
1243 args += ['--shaperspace', lin_shaper_name,
1244 '--shapersize', str(lut_resolution_shaper)]
1246 args += ['--cubesize', str(lut_resolution_3d)]
1248 margs = ['--format',
1253 '%s for %s Maya.csp' % (odt_name, input_space))]
1254 bake_lut = Process(description='bake a LUT',
1256 args=(args + margs))
1259 hargs = ['--format',
1264 '%s for %s Houdini.lut' % (odt_name, input_space))]
1265 bake_lut = Process(description='bake a LUT',
1267 args=(args + hargs))
1271 def create_config_dir(config_directory,
1272 bake_secondary_LUTs=False,
1273 custom_lut_dir=None):
1280 Parameter description.
1285 Return value description.
1288 lut_directory = os.path.join(config_directory, 'luts')
1289 dirs = [config_directory, lut_directory]
1291 if bake_secondary_LUTs:
1292 dirs.extend([os.path.join(config_directory, 'baked'),
1293 os.path.join(config_directory, 'baked', 'flame'),
1294 os.path.join(config_directory, 'baked', 'photoshop'),
1295 os.path.join(config_directory, 'baked', 'houdini'),
1296 os.path.join(config_directory, 'baked', 'lustre'),
1297 os.path.join(config_directory, 'baked', 'maya')])
1300 dirs.append(os.path.join(config_directory, 'custom'))
1303 not os.path.exists(d) and os.mkdir(d)
1305 return lut_directory
1308 def create_ACES_config(aces_ctl_directory,
1310 lut_resolution_1d=4096,
1311 lut_resolution_3d=64,
1312 bake_secondary_LUTs=True,
1313 multiple_displays=False,
1315 copy_custom_luts=True,
1317 prefix_colorspaces_with_family_names=True):
1319 Creates the ACES configuration.
1324 Parameter description.
1329 Return value description.
1332 # Directory for custom LUTs
1333 custom_lut_dir = None
1334 if copy_custom_luts:
1335 custom_lut_dir = os.path.join(config_directory, "custom")
1337 lut_directory = create_config_dir(config_directory,
1338 bake_secondary_LUTs,
1341 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1342 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1344 shaper_name = 'Output Shaper'
1345 config_data = generate_LUTs(odt_info,
1354 print('Creating config - with prefixes, with aliases')
1355 config = create_config(config_data,
1356 prefix=prefix_colorspaces_with_family_names,
1358 multiple_displays=multiple_displays,
1359 look_info=look_info,
1360 custom_lut_dir=custom_lut_dir)
1363 write_config(config,
1364 os.path.join(config_directory, 'config.ocio'))
1366 if bake_secondary_LUTs:
1367 generate_baked_LUTs(odt_info,
1369 os.path.join(config_directory, 'baked'),
1370 os.path.join(config_directory, 'config.ocio'),
1374 prefix=prefix_colorspaces_with_family_names)
1386 Parameter description.
1391 Return value description.
1396 usage = '%prog [options]\n'
1398 usage += 'An OCIO config generation script for ACES 1.0\n'
1400 usage += 'Command line examples'
1402 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1403 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1405 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1406 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1409 usage += 'Adding custom looks'
1411 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1412 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'
1414 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \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--addCustomLookCDL CustomCDLName "ACES - ACEScc" /path/to/SampleCDL.ccc cc03345'
1417 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'
1419 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1420 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'
1422 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1423 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'
1425 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'
1430 def look_info_callback(option, opt_str, value, parser):
1431 print("look_info_callback")
1432 print(option, opt_str, value, parser)
1433 if opt_str == "--addCustomLookCDL":
1434 look_info.append(value)
1435 elif opt_str == "--addCustomLookLUT":
1436 look_info.append(value)
1437 elif opt_str == "--addACESLookCDL":
1438 look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1439 elif opt_str == "--addACESLookLUT":
1440 look_info.append([value[0], "ACES - ACEScc", value[1]])
1442 p = optparse.OptionParser(description='',
1443 prog='create_aces_config',
1444 version='create_aces_config 1.0',
1446 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1447 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1448 p.add_option('--configDir', '-c', default=os.environ.get(
1449 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1450 p.add_option('--lutResolution1d', default=4096)
1451 p.add_option('--lutResolution3d', default=64)
1452 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1453 p.add_option('--keepTempImages', action='store_true', default=False)
1455 p.add_option('--createMultipleDisplays', action='store_true',
1458 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1459 action="callback", callback=look_info_callback)
1460 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1461 action="callback", callback=look_info_callback)
1462 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1463 action="callback", callback=look_info_callback)
1464 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1465 action="callback", callback=look_info_callback)
1466 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1468 options, arguments = p.parse_args()
1470 aces_ctl_directory = options.acesCTLDir
1471 config_directory = options.configDir
1472 lut_resolution_1d = int(options.lutResolution1d)
1473 lut_resolution_3d = int(options.lutResolution3d)
1474 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1475 cleanup_temp_images = not options.keepTempImages
1476 multiple_displays = options.createMultipleDisplays
1477 copy_custom_luts = options.copyCustomLUTs
1481 # TODO: Investigate the following statements.
1483 args_start = sys.argv.index('--') + 1
1484 args = sys.argv[args_start:]
1486 args_start = len(sys.argv) + 1
1489 print('command line : \n%s\n' % ' '.join(sys.argv))
1491 assert aces_ctl_directory is not None, (
1492 'process: No "{0}" environment variable defined or no "ACES CTL" '
1493 'directory specified'.format(
1494 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1496 assert config_directory is not None, (
1497 'process: No "{0}" environment variable defined or no configuration '
1498 'directory specified'.format(
1499 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1501 return create_ACES_config(aces_ctl_directory,
1505 bake_secondary_luts,
1509 cleanup_temp_images)
1512 if __name__ == '__main__':