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():
314 print('Skipping alias creation for %s, alias %s, because lower cased names match' % (
315 colorspace.name, alias_name) )
318 print('Adding alias colorspace space %s, alias to %s' % (
319 alias_name, colorspace.name))
321 compact_family_name = family
323 description = colorspace.description
324 if colorspace.aces_transform_id:
325 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
327 ocio_colorspace_alias = ocio.ColorSpace(
329 bitDepth=colorspace.bit_depth,
330 description=description,
331 equalityGroup=colorspace.equality_group,
332 family=compact_family_name,
333 isData=colorspace.is_data,
334 allocation=colorspace.allocation_type,
335 allocationVars=colorspace.allocation_vars)
337 if colorspace.to_reference_transforms:
338 print('\tGenerating To-Reference transforms')
339 ocio_transform = generate_OCIO_transform(
340 [{'type': 'colorspace',
341 'src': colorspace.name,
342 'dst': reference_colorspace.name,
343 'direction': 'forward'}])
344 ocio_colorspace_alias.setTransform(
346 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
348 if colorspace.from_reference_transforms:
349 print('\tGenerating From-Reference transforms')
350 ocio_transform = generate_OCIO_transform(
351 [{'type': 'colorspace',
352 'src': reference_colorspace.name,
353 'dst': colorspace.name,
354 'direction': 'forward'}])
355 ocio_colorspace_alias.setTransform(
357 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
359 config.addColorSpace(ocio_colorspace_alias)
361 def colorspace_prefixed_name(colorspace):
362 prefix = colorspace.family.replace("/", " - ")
363 return "%s - %s" % (prefix, colorspace.name)
371 multiple_displays=False):
378 Parameter description.
383 Return value description.
387 look_colorspace = look[1]
393 print('Adding look %s - %s' % (look_name, ", ".join(look)) )
399 if not '$' in look_lut:
400 print( "Getting ready to copy look lut : %s" % look_lut )
401 shutil.copy2(look_lut, custom_lut_dir)
402 look_lut = os.path.split(look_lut)[1]
404 print( "Skipping LUT copy because path contains a context variable" )
410 print('Adding look to config' )
412 lk1.setName( look_name )
413 lk1.setProcessSpace( look_colorspace )
415 keys = {'type': 'lutFile',
417 'direction': 'forward'}
419 keys['cccid'] = look_cccid
421 ocio_transform = generate_OCIO_transform([keys])
422 lk1.setTransform( ocio_transform )
425 config.addLook( lk1 )
427 print( "Creating aliased colorspace")
430 # Create OCIO colorspace that references that look
431 # - Needed for some implementations that don't process looks well
432 # - Also needed for some implementations that don't expose looks well
434 look_aliases = ["look_%s" % compact(look_name)]
435 colorspace = ColorSpace(look_name,
436 aliases=look_aliases,
437 description="The %s Look colorspace" % look_name,
440 colorspace.from_reference_transforms = [{'type': 'look',
442 'src': reference_name,
443 'dst': reference_name,
444 'direction': 'forward'}]
446 print('Adding colorspace %s, alias to look %s to config data' % (
447 look_name, look_name))
449 # Add this colorspace into the main list of colorspaces
450 config_data['colorSpaces'].append(colorspace)
454 def integrate_looks_into_views(config,
458 multiple_displays=False):
465 Parameter description.
470 Return value description.
472 look_names = [look[0] for look in looks]
474 # Option 1 - Add a 'look' to each Display
475 # - Assumes there is a Display for each ACES Output Transform
476 if multiple_displays:
477 for look_name in look_names:
478 config_data['looks'].append(look_name)
481 # - Copy each Output Transform colorspace
482 # - For each copy, add a LookTransform at the head of the from_reference
484 # - Add these new copied colorspaces for the Displays / Views
486 for display, view_list in config_data['displays'].iteritems():
487 output_colorspace_copy = None
488 look_names_string = ""
489 for view_name, output_colorspace in view_list.iteritems():
490 if view_name == "Output Transform":
492 print( "Adding new View that incorporates looks" )
494 # Make a copy of the output colorspace
495 output_colorspace_copy = copy.deepcopy(output_colorspace)
497 #for look_name in look_names:
498 for i in range(len(look_names)):
499 look_name = look_names[i]
501 # Add the LookTransform to the head of the from_reference transform list
502 if output_colorspace_copy.from_reference_transforms:
503 output_colorspace_copy.from_reference_transforms.insert(i, {'type': 'look',
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[len(look_names) -1 -i]
513 output_colorspace_copy.to_reference_transforms.append({'type': 'look',
514 'look': inverse_look_name,
515 'src': reference_name,
516 'dst': reference_name,
517 'direction': 'inverse'})
519 if not look_name in config_data['looks']:
520 config_data['looks'].append(look_name)
522 look_names_string = ", ".join(look_names)
523 output_colorspace_copy.name = "%s with %s" % (output_colorspace.name, look_names_string)
524 output_colorspace_copy.aliases = ["out_%s" % compact(output_colorspace_copy.name)]
526 print( "Colorspace that incorporates looks created : %s" % output_colorspace_copy.name )
528 config_data['colorSpaces'].append(output_colorspace_copy)
530 if output_colorspace_copy:
531 print( "Adding colorspace that incorporates looks into view list" )
533 # Change the name of the View
534 view_list["Output Transform with %s" % look_names_string] = output_colorspace_copy
535 config_data['displays'][display] = view_list
537 #print( "Display : %s, View List : %s" % (display, ", ".join(view_list)) )
539 def create_config(config_data,
542 multiple_displays=False,
544 custom_lut_dir=None):
551 Parameter description.
556 Return value description.
560 alias_colorspaces = []
562 # Creating the *OCIO* configuration.
563 config = ocio.Config()
565 # Setting configuration description.
566 config.setDescription('An ACES config generated from python')
568 # Setting configuration search path.
569 searchPath = ['luts']
571 searchPath.append('custom')
572 config.setSearchPath(':'.join(searchPath))
574 # Defining the reference colorspace.
575 reference_data = config_data['referenceColorSpace']
577 # Adding the color space Family into the name
578 # Helps with applications that present colorspaces as one long list
580 prefixed_name = colorspace_prefixed_name(reference_data)
581 prefixed_names[reference_data.name] = prefixed_name
582 reference_data.name = prefixed_name
584 print('Adding the reference color space : %s' % reference_data.name)
586 reference = ocio.ColorSpace(
587 name=reference_data.name,
588 bitDepth=reference_data.bit_depth,
589 description=reference_data.description,
590 equalityGroup=reference_data.equality_group,
591 family=reference_data.family,
592 isData=reference_data.is_data,
593 allocation=reference_data.allocation_type,
594 allocationVars=reference_data.allocation_vars)
596 config.addColorSpace(reference)
600 if reference_data.aliases != []:
601 #add_colorspace_alias(config, reference_data,
602 # reference_data, reference_data.aliases)
603 # defer adding alias colorspaces until end. Helps with some applications
604 alias_colorspaces.append([reference_data, reference_data, reference_data.aliases])
609 #print( "color spaces : %s" % [x.name for x in sorted(config_data['colorSpaces'])])
612 # Add Looks and Look colorspaces
615 print('Adding looks')
617 config_data['looks'] = []
619 # Add looks and colorspaces
620 for look in look_info:
628 # Integrate looks with displays, views
629 integrate_looks_into_views(config,
637 print('Adding the regular color spaces')
639 # Creating the remaining colorspaces.
640 for colorspace in sorted(config_data['colorSpaces']):
641 # Adding the color space Family into the name
642 # Helps with applications that present colorspaces as one long list
644 prefixed_name = colorspace_prefixed_name(colorspace)
645 prefixed_names[colorspace.name] = prefixed_name
646 colorspace.name = prefixed_name
648 print('Creating new color space : %s' % colorspace.name)
650 description = colorspace.description
651 if colorspace.aces_transform_id:
652 description += "\n\nACES Transform ID : %s" % colorspace.aces_transform_id
654 ocio_colorspace = ocio.ColorSpace(
655 name=colorspace.name,
656 bitDepth=colorspace.bit_depth,
657 description=description,
658 equalityGroup=colorspace.equality_group,
659 family=colorspace.family,
660 isData=colorspace.is_data,
661 allocation=colorspace.allocation_type,
662 allocationVars=colorspace.allocation_vars)
664 if colorspace.to_reference_transforms:
665 print('\tGenerating To-Reference transforms')
666 ocio_transform = generate_OCIO_transform(
667 colorspace.to_reference_transforms)
668 ocio_colorspace.setTransform(
670 ocio.Constants.COLORSPACE_DIR_TO_REFERENCE)
672 if colorspace.from_reference_transforms:
673 print('\tGenerating From-Reference transforms')
674 ocio_transform = generate_OCIO_transform(
675 colorspace.from_reference_transforms)
676 ocio_colorspace.setTransform(
678 ocio.Constants.COLORSPACE_DIR_FROM_REFERENCE)
680 config.addColorSpace(ocio_colorspace)
683 # Add alias to normal colorspace, using compact name
686 if colorspace.aliases != []:
687 #add_colorspace_alias(config, reference_data,
688 # colorspace, colorspace.aliases)
689 # defer adding alias colorspaces until end. Helps with some applications
690 alias_colorspaces.append([reference_data, colorspace, colorspace.aliases])
697 # We add roles early so we can create alias colorspaces with the names of the roles
698 # before the rest of the colorspace aliases are added to the config.
700 print('Setting the roles')
703 set_config_default_roles(
705 color_picking=prefixed_names[config_data['roles']['color_picking']],
706 color_timing=prefixed_names[config_data['roles']['color_timing']],
707 compositing_log=prefixed_names[config_data['roles']['compositing_log']],
708 data=prefixed_names[config_data['roles']['data']],
709 default=prefixed_names[config_data['roles']['default']],
710 matte_paint=prefixed_names[config_data['roles']['matte_paint']],
711 reference=prefixed_names[config_data['roles']['reference']],
712 scene_linear=prefixed_names[config_data['roles']['scene_linear']],
713 texture_paint=prefixed_names[config_data['roles']['texture_paint']])
715 # Not allowed for the moment. role names can not overlap with colorspace names.
717 # Add the aliased colorspaces for each role
718 for role_name, role_colorspace_name in config_data['roles'].iteritems():
719 role_colorspace_prefixed_name = prefixed_names[role_colorspace_name]
721 print( "Finding colorspace : %s" % role_colorspace_prefixed_name )
722 # Find the colorspace pointed to by the role
723 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_prefixed_name]
724 role_colorspace = None
725 if len(role_colorspaces) > 0:
726 role_colorspace = role_colorspaces[0]
728 if reference_data.name == role_colorspace_prefixed_name:
729 role_colorspace = reference_data
732 print( "Adding an alias colorspace named %s, pointing to %s" % (
733 role_name, role_colorspace.name))
735 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
739 set_config_default_roles(
741 color_picking=config_data['roles']['color_picking'],
742 color_timing=config_data['roles']['color_timing'],
743 compositing_log=config_data['roles']['compositing_log'],
744 data=config_data['roles']['data'],
745 default=config_data['roles']['default'],
746 matte_paint=config_data['roles']['matte_paint'],
747 reference=config_data['roles']['reference'],
748 scene_linear=config_data['roles']['scene_linear'],
749 texture_paint=config_data['roles']['texture_paint'])
751 # Not allowed for the moment. role names can not overlap with colorspace names.
753 # Add the aliased colorspaces for each role
754 for role_name, role_colorspace_name in config_data['roles'].iteritems():
755 # Find the colorspace pointed to by the role
756 role_colorspaces = [colorspace for colorspace in config_data['colorSpaces'] if colorspace.name == role_colorspace_name]
757 role_colorspace = None
758 if len(role_colorspaces) > 0:
759 role_colorspace = role_colorspaces[0]
761 if reference_data.name == role_colorspace_name:
762 role_colorspace = reference_data
765 print( "Adding an alias colorspace named %s, pointing to %s" % (
766 role_name, role_colorspace.name))
768 add_colorspace_aliases(config, reference_data, role_colorspace, [role_name], 'Roles')
773 # We add these at the end as some applications use the order of the colorspaces
774 # definitions in the config to order the colorspaces in their selection lists.
775 # Other go alphabetically. This should keep the alias colorspaces out of the way
776 # for the apps that use the order of definition in the config.
777 print('Adding the alias colorspaces')
778 for reference, colorspace, aliases in alias_colorspaces:
779 add_colorspace_aliases(config, reference, colorspace, aliases)
783 print('Adding the diplays and views')
785 # Set the color_picking role to be the first Display's Output Transform View
786 default_display_name = config_data['defaultDisplay']
787 default_display_views = config_data['displays'][default_display_name]
788 default_display_colorspace = default_display_views['Output Transform']
790 set_config_default_roles(
792 color_picking=default_display_colorspace.name)
794 # Defining the *views* and *displays*.
798 # Defining a *generic* *display* and *view* setup.
799 if multiple_displays:
800 # Built list of looks to add to Displays
801 looks = config_data['looks'] if ('looks' in config_data) else []
802 looks = ", ".join(looks)
803 print( "Creating multiple displays, with looks : %s" % looks)
805 # Note: We don't reorder the Displays to put the 'defaultDisplay' first
806 # because OCIO will order them alphabetically when the config is written to disk.
808 # Create Displays, Views
809 for display, view_list in config_data['displays'].iteritems():
810 for view_name, colorspace in view_list.iteritems():
811 config.addDisplay(display, view_name, colorspace.name, looks)
812 if 'Output Transform' in view_name and looks != "":
813 # Add normal View, without looks
814 config.addDisplay(display, view_name, colorspace.name)
816 # Add View with looks
817 view_name_with_looks = "%s with %s" % (view_name, looks)
818 config.addDisplay(display, view_name_with_looks, colorspace.name, looks)
820 config.addDisplay(display, view_name, colorspace.name)
821 if not (view_name in views):
822 views.append(view_name)
823 displays.append(display)
825 # Defining the set of *views* and *displays* useful in a *GUI* context.
827 single_display_name = 'ACES'
828 #single_display_name = config_data['roles']['scene_linear']
829 displays.append(single_display_name)
831 # Make sure the default display is first
832 display_names = sorted(config_data['displays'])
833 display_names.insert(0, display_names.pop(display_names.index(default_display_name)))
835 # Built list of looks to add to Displays
836 looks = config_data['looks'] if ('looks' in config_data) else []
837 look_names = ", ".join(looks)
839 displays_views_colorspaces = []
841 # Create Displays, Views
842 for display in display_names:
843 view_list = config_data['displays'][display]
844 for view_name, colorspace in view_list.iteritems():
845 if 'Output Transform' in view_name:
846 #print( "Adding view for %s" % colorspace.name )
848 # We use the Display names as the View names in this case
849 # as there is a single Display that contains all views.
850 # This works for more applications than not, as of the time of this implementation.
852 # Maya 2016 doesn't like parentheses in View names
853 display_cleaned = replace(display, {')': '', '(': ''})
855 # If View includes looks
856 if 'with' in view_name:
857 # Integrate looks into view name
858 display_cleaned = "%s with %s" % (display_cleaned, look_names)
860 viewsWithLooksAtEnd = False
861 # Storing combo of display, view and colorspace name in a list so we can
862 # add them to the end of the list
863 if viewsWithLooksAtEnd:
864 displays_views_colorspaces.append([single_display_name, display_cleaned, colorspace.name])
868 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
871 if not (display_cleaned in views):
872 views.append(display_cleaned)
876 config.addDisplay(single_display_name, display_cleaned, colorspace.name)
879 if not (display_cleaned in views):
880 views.append(display_cleaned)
882 # Add to config any display, view combinations that were saved for later
883 # This list will be empty unless viewsWithLooksAtEnd is set to True above
884 for display_view_colorspace in displays_views_colorspaces:
885 single_display_name, display_cleaned, colorspace_name = display_view_colorspace
888 config.addDisplay(single_display_name, display_cleaned, colorspace_name)
891 if not (display_cleaned in views):
892 views.append(display_cleaned)
895 # Works with Nuke Studio and Mari, but not Nuke
896 # single_display_name = 'Utility'
897 # displays.append(single_display_name)
899 raw_display_space_name = config_data['roles']['data']
900 log_display_space_name = config_data['roles']['compositing_log']
902 # Find the newly-prefixed colorspace names
904 #print( prefixed_names )
905 raw_display_space_name = prefixed_names[raw_display_space_name]
906 log_display_space_name = prefixed_names[log_display_space_name]
908 config.addDisplay(single_display_name, 'Raw', raw_display_space_name)
910 config.addDisplay(single_display_name, 'Log', log_display_space_name)
913 # Setting the active *displays* and *views*.
914 config.setActiveDisplays(','.join(sorted(displays)))
915 config.setActiveViews(','.join(views))
919 # Make sure we didn't create a bad config
922 # Reset the colorspace names back to their non-prefixed versions
924 # Build the reverse lookup
925 prefixed_names_inverse = {}
926 for original, prefixed in prefixed_names.iteritems():
927 prefixed_names_inverse[prefixed] = original
929 # Reset the reference colorspace name
930 reference_data.name = prefixed_names_inverse[reference_data.name]
932 # Reset the rest of the colorspace names
934 for colorspace in config_data['colorSpaces']:
935 colorspace.name = prefixed_names_inverse[colorspace.name]
937 print( "Prefixed names")
938 for original, prefixed in prefixed_names.iteritems():
939 print( "%s, %s" % (original, prefixed) )
943 print( "Inverse Lookup of Prefixed names")
944 for prefixed, original in prefixed_names_inverse.iteritems():
945 print( "%s, %s" % (prefixed, original) )
951 def generate_LUTs(odt_info,
956 lut_resolution_1d=4096,
957 lut_resolution_3d=64,
965 Parameter description.
970 Colorspaces and transforms converting between those colorspaces and
971 the reference colorspace, *ACES*.
974 print('generateLUTs - begin')
977 # Initialize a few variables
978 config_data['displays'] = {}
979 config_data['colorSpaces'] = []
981 # -------------------------------------------------------------------------
982 # *ACES Color Spaces*
983 # -------------------------------------------------------------------------
989 aces_log_display_space,
991 aces_default_display) = aces.create_colorspaces(aces_ctl_directory,
1000 config_data['referenceColorSpace'] = aces_reference
1001 config_data['roles'] = aces_roles
1003 for cs in aces_colorspaces:
1004 config_data['colorSpaces'].append(cs)
1006 for name, data in aces_displays.iteritems():
1007 config_data['displays'][name] = data
1009 config_data['defaultDisplay'] = aces_default_display
1010 config_data['linearDisplaySpace'] = aces_reference
1011 config_data['logDisplaySpace'] = aces_log_display_space
1013 # -------------------------------------------------------------------------
1014 # *Camera Input Transforms*
1015 # -------------------------------------------------------------------------
1017 # *ARRI Log-C* to *ACES*.
1018 arri_colorSpaces = arri.create_colorspaces(lut_directory,
1020 for cs in arri_colorSpaces:
1021 config_data['colorSpaces'].append(cs)
1023 # *Canon-Log* to *ACES*.
1024 canon_colorspaces = canon.create_colorspaces(lut_directory,
1026 for cs in canon_colorspaces:
1027 config_data['colorSpaces'].append(cs)
1029 # *GoPro Protune* to *ACES*.
1030 gopro_colorspaces = gopro.create_colorspaces(lut_directory,
1032 for cs in gopro_colorspaces:
1033 config_data['colorSpaces'].append(cs)
1035 # *Panasonic V-Log* to *ACES*.
1036 panasonic_colorSpaces = panasonic.create_colorspaces(lut_directory,
1038 for cs in panasonic_colorSpaces:
1039 config_data['colorSpaces'].append(cs)
1041 # *RED* colorspaces to *ACES*.
1042 red_colorspaces = red.create_colorspaces(lut_directory,
1044 for cs in red_colorspaces:
1045 config_data['colorSpaces'].append(cs)
1047 # *S-Log* to *ACES*.
1048 sony_colorSpaces = sony.create_colorspaces(lut_directory,
1050 for cs in sony_colorSpaces:
1051 config_data['colorSpaces'].append(cs)
1053 # -------------------------------------------------------------------------
1054 # General Color Spaces
1055 # -------------------------------------------------------------------------
1056 general_colorSpaces = general.create_colorspaces(lut_directory,
1059 for cs in general_colorSpaces:
1060 config_data['colorSpaces'].append(cs)
1062 # The *Raw* color space
1063 raw = general.create_raw()
1064 config_data['colorSpaces'].append(raw)
1066 # Override certain roles, for now
1067 config_data['roles']['data'] = raw.name
1068 config_data['roles']['reference'] = raw.name
1069 config_data['roles']['texture_paint'] = raw.name
1071 print('generateLUTs - end')
1075 def generate_baked_LUTs(odt_info,
1081 lut_resolution_shaper=1024,
1089 Parameter description.
1094 Return value description.
1097 odt_info_C = dict(odt_info)
1099 # Uncomment if you would like to support the older behavior where ODTs
1100 # that have support for full and legal range output generate a LUT for each.
1102 # Create two entries for ODTs that have full and legal range support
1103 for odt_ctl_name, odt_values in odt_info.iteritems():
1104 if odt_values['transformHasFullLegalSwitch']:
1105 odt_name = odt_values['transformUserName']
1107 odt_values_legal = dict(odt_values)
1108 odt_values_legal['transformUserName'] = '%s - Legal' % odt_name
1109 odt_info_C['%s - Legal' % odt_ctl_name] = odt_values_legal
1111 odt_values_full = dict(odt_values)
1112 odt_values_full['transformUserName'] = '%s - Full' % odt_name
1113 odt_info_C['%s - Full' % odt_ctl_name] = odt_values_full
1115 del (odt_info_C[odt_ctl_name])
1118 # Generate appropriate LUTs for each ODT
1119 for odt_ctl_name, odt_values in odt_info_C.iteritems():
1120 odt_prefix = odt_values['transformUserNamePrefix']
1121 odt_name = odt_values['transformUserName']
1124 for input_space in ['ACEScc', 'ACESproxy']:
1125 args = ['--iconfig', config_path,
1128 args += ['--inputspace', "ACES - %s" % input_space]
1129 args += ['--outputspace', "Output - %s" % odt_name]
1131 args += ['--inputspace', input_space]
1132 args += ['--outputspace', odt_name]
1134 args += ['--description',
1135 '%s - %s for %s data' % (odt_prefix,
1139 args += ['--shaperspace', "Utility - %s" % shaper_name,
1140 '--shapersize', str(lut_resolution_shaper)]
1142 args += ['--shaperspace', shaper_name,
1143 '--shapersize', str(lut_resolution_shaper)]
1144 args += ['--cubesize', str(lut_resolution_3d)]
1145 args += ['--format',
1147 os.path.join(baked_directory,
1149 '%s for %s.icc' % (odt_name, input_space))]
1151 bake_lut = Process(description='bake a LUT',
1157 for input_space in ['ACEScc', 'ACESproxy']:
1158 args = ['--iconfig', config_path,
1161 args += ['--inputspace', "ACES - %s" % input_space]
1162 args += ['--outputspace', "Output - %s" % odt_name]
1164 args += ['--inputspace', input_space]
1165 args += ['--outputspace', odt_name]
1166 args += ['--description',
1167 '%s - %s for %s data' % (
1168 odt_prefix, odt_name, input_space)]
1170 args += ['--shaperspace', "Utility - %s" % shaper_name,
1171 '--shapersize', str(lut_resolution_shaper)]
1173 args += ['--shaperspace', shaper_name,
1174 '--shapersize', str(lut_resolution_shaper)]
1175 args += ['--cubesize', str(lut_resolution_3d)]
1177 fargs = ['--format',
1182 '%s for %s Flame.3dl' % (odt_name, input_space))]
1183 bake_lut = Process(description='bake a LUT',
1185 args=(args + fargs))
1188 largs = ['--format',
1193 '%s for %s Lustre.3dl' % (odt_name, input_space))]
1194 bake_lut = Process(description='bake a LUT',
1196 args=(args + largs))
1200 for input_space in ['ACEScg', 'ACES2065-1']:
1201 args = ['--iconfig', config_path,
1204 args += ['--inputspace', "ACES - %s" % input_space]
1205 args += ['--outputspace', "Output - %s" % odt_name]
1207 args += ['--inputspace', input_space]
1208 args += ['--outputspace', odt_name]
1209 args += ['--description',
1210 '%s - %s for %s data' % (
1211 odt_prefix, odt_name, input_space)]
1212 if input_space == 'ACEScg':
1213 lin_shaper_name = "%s - AP1" % shaper_name
1215 lin_shaper_name = shaper_name
1217 lin_shaper_name = "Utility - %s" % lin_shaper_name
1218 args += ['--shaperspace', lin_shaper_name,
1219 '--shapersize', str(lut_resolution_shaper)]
1221 args += ['--cubesize', str(lut_resolution_3d)]
1223 margs = ['--format',
1228 '%s for %s Maya.csp' % (odt_name, input_space))]
1229 bake_lut = Process(description='bake a LUT',
1231 args=(args + margs))
1234 hargs = ['--format',
1239 '%s for %s Houdini.lut' % (odt_name, input_space))]
1240 bake_lut = Process(description='bake a LUT',
1242 args=(args + hargs))
1246 def create_config_dir(config_directory,
1247 bake_secondary_LUTs=False,
1248 custom_lut_dir=None):
1255 Parameter description.
1260 Return value description.
1263 lut_directory = os.path.join(config_directory, 'luts')
1264 dirs = [config_directory, lut_directory]
1266 if bake_secondary_LUTs:
1267 dirs.extend([os.path.join(config_directory, 'baked'),
1268 os.path.join(config_directory, 'baked', 'flame'),
1269 os.path.join(config_directory, 'baked', 'photoshop'),
1270 os.path.join(config_directory, 'baked', 'houdini'),
1271 os.path.join(config_directory, 'baked', 'lustre'),
1272 os.path.join(config_directory, 'baked', 'maya')])
1275 dirs.append(os.path.join(config_directory, 'custom'))
1278 not os.path.exists(d) and os.mkdir(d)
1280 return lut_directory
1283 def create_ACES_config(aces_ctl_directory,
1285 lut_resolution_1d=4096,
1286 lut_resolution_3d=64,
1287 bake_secondary_LUTs=True,
1288 multiple_displays=False,
1290 copy_custom_luts=True,
1292 prefix_colorspaces_with_family_names=True):
1294 Creates the ACES configuration.
1299 Parameter description.
1304 Return value description.
1307 # Directory for custom LUTs
1308 custom_lut_dir = None
1309 if copy_custom_luts:
1310 custom_lut_dir = os.path.join(config_directory, "custom")
1312 lut_directory = create_config_dir(config_directory,
1313 bake_secondary_LUTs,
1316 odt_info = aces.get_ODTs_info(aces_ctl_directory)
1317 lmt_info = aces.get_LMTs_info(aces_ctl_directory)
1319 shaper_name = 'Output Shaper'
1320 config_data = generate_LUTs(odt_info,
1329 print('Creating config - with prefixes, with aliases')
1330 config = create_config(config_data,
1331 prefix=prefix_colorspaces_with_family_names,
1333 multiple_displays=multiple_displays,
1334 look_info=look_info,
1335 custom_lut_dir=custom_lut_dir)
1338 write_config(config,
1339 os.path.join(config_directory, 'config.ocio'))
1341 if bake_secondary_LUTs:
1342 generate_baked_LUTs(odt_info,
1344 os.path.join(config_directory, 'baked'),
1345 os.path.join(config_directory, 'config.ocio'),
1349 prefix=prefix_colorspaces_with_family_names)
1361 Parameter description.
1366 Return value description.
1371 usage = '%prog [options]\n'
1373 usage += 'An OCIO config generation script for ACES 1.0\n'
1375 usage += 'Command line examples'
1377 usage += 'Create a GUI-friendly ACES 1.0 config with no secondary, baked LUTs : \n'
1378 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --dontBakeSecondaryLUTs'
1380 usage += 'Create a more OCIO-compliant ACES 1.0 config : \n'
1381 usage += '\tcreate_aces_config -a /path/to/aces-dev/transforms/ctl --lutResolution1d 1024 --lutResolution3d 33 -c aces_1.0.0 --createMultipleDisplays'
1384 usage += 'Adding custom looks'
1386 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style CDL (will be applied in the ACEScc colorspace): \n'
1387 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'
1389 usage += 'Create a GUI-friendly ACES 1.0 config with an general CDL: \n'
1390 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'
1392 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'
1394 usage += 'Create a GUI-friendly ACES 1.0 config with an ACES-style LUT (will be applied in the ACEScc colorspace): \n'
1395 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'
1397 usage += 'Create a GUI-friendly ACES 1.0 config with an general LUT: \n'
1398 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'
1400 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'
1404 def look_info_callback(option, opt_str, value, parser):
1405 print( "look_info_callback" )
1406 print( option, opt_str, value, parser )
1407 if opt_str == "--addCustomLookCDL":
1408 look_info.append(value)
1409 elif opt_str == "--addCustomLookLUT":
1410 look_info.append(value)
1411 elif opt_str == "--addACESLookCDL":
1412 look_info.append([value[0], "ACES - ACEScc", value[1], value[2]])
1413 elif opt_str == "--addACESLookLUT":
1414 look_info.append([value[0], "ACES - ACEScc", value[1]])
1416 p = optparse.OptionParser(description='',
1417 prog='create_aces_config',
1418 version='create_aces_config 1.0',
1420 p.add_option('--acesCTLDir', '-a', default=os.environ.get(
1421 ACES_OCIO_CTL_DIRECTORY_ENVIRON, None))
1422 p.add_option('--configDir', '-c', default=os.environ.get(
1423 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON, None))
1424 p.add_option('--lutResolution1d', default=4096)
1425 p.add_option('--lutResolution3d', default=64)
1426 p.add_option('--dontBakeSecondaryLUTs', action='store_true', default=False)
1427 p.add_option('--keepTempImages', action='store_true', default=False)
1429 p.add_option('--createMultipleDisplays', action='store_true', default=False)
1431 p.add_option('--addCustomLookLUT', '', type='string', nargs=3,
1432 action="callback", callback=look_info_callback)
1433 p.add_option('--addCustomLookCDL', '', type='string', nargs=4,
1434 action="callback", callback=look_info_callback)
1435 p.add_option('--addACESLookLUT', '', type='string', nargs=2,
1436 action="callback", callback=look_info_callback)
1437 p.add_option('--addACESLookCDL', '', type='string', nargs=3,
1438 action="callback", callback=look_info_callback)
1439 p.add_option('--copyCustomLUTs', action='store_true', default=False)
1441 options, arguments = p.parse_args()
1443 aces_ctl_directory = options.acesCTLDir
1444 config_directory = options.configDir
1445 lut_resolution_1d = int(options.lutResolution1d)
1446 lut_resolution_3d = int(options.lutResolution3d)
1447 bake_secondary_luts = not options.dontBakeSecondaryLUTs
1448 cleanup_temp_images = not options.keepTempImages
1449 multiple_displays = options.createMultipleDisplays
1450 copy_custom_luts = options.copyCustomLUTs
1454 # TODO: Investigate the following statements.
1456 args_start = sys.argv.index('--') + 1
1457 args = sys.argv[args_start:]
1459 args_start = len(sys.argv) + 1
1462 print('command line : \n%s\n' % ' '.join(sys.argv))
1464 assert aces_ctl_directory is not None, (
1465 'process: No "{0}" environment variable defined or no "ACES CTL" '
1466 'directory specified'.format(
1467 ACES_OCIO_CTL_DIRECTORY_ENVIRON))
1469 assert config_directory is not None, (
1470 'process: No "{0}" environment variable defined or no configuration '
1471 'directory specified'.format(
1472 ACES_OCIO_CONFIGURATION_DIRECTORY_ENVIRON))
1474 return create_ACES_config(aces_ctl_directory,
1478 bake_secondary_luts,
1482 cleanup_temp_images)
1484 if __name__ == '__main__':