The working space is now ACEScg. The scene_linear, rendering and compositing_linear...
[OpenColorIO-Configs.git] / aces_1.0.0 / python / aces_ocio / colorspaces / aces.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Implements support for *ACES* colorspaces conversions and transfer functions.
6 """
7
8 from __future__ import division
9
10 import math
11 import numpy
12 import os
13 import pprint
14 import string
15 import shutil
16
17 import PyOpenColorIO as ocio
18
19 from aces_ocio.generate_lut import (
20     generate_1d_LUT_from_CTL,
21     generate_3d_LUT_from_CTL,
22     write_SPI_1d)
23 from aces_ocio.utilities import (
24     ColorSpace,
25     mat44_from_mat33,
26     sanitize,
27     compact)
28
29
30 __author__ = 'ACES Developers'
31 __copyright__ = 'Copyright (C) 2014 - 2015 - ACES Developers'
32 __license__ = ''
33 __maintainer__ = 'ACES Developers'
34 __email__ = 'aces@oscars.org'
35 __status__ = 'Production'
36
37 __all__ = ['ACES_AP1_TO_AP0',
38            'ACES_AP0_TO_XYZ',
39            'create_ACES',
40            'create_ACEScc',
41            'create_ACESproxy',
42            'create_ACEScg',
43            'create_ADX',
44            'create_ACES_LMT',
45            'create_ACES_RRT_plus_ODT',
46            'create_generic_log',
47            'create_LMTs',
48            'create_ODTs',
49            'get_transform_info',
50            'get_ODTs_info',
51            'get_LMTs_info',
52            'create_colorspaces']
53
54 # Matrix converting *ACES AP1* primaries to *ACES AP0*.
55 ACES_AP1_TO_AP0 = [0.6954522414, 0.1406786965, 0.1638690622,
56                    0.0447945634, 0.8596711185, 0.0955343182,
57                    -0.0055258826, 0.0040252103, 1.0015006723]
58
59 # Matrix converting *ACES AP0* primaries to *ACES AP1*.
60 ACES_AP0_TO_AP1 = [1.4514393161, -0.2365107469, -0.2149285693,
61                    -0.0765537734, 1.1762296998, -0.0996759264,
62                    0.0083161484, -0.0060324498, 0.9977163014]
63
64 # Matrix converting *ACES AP0* primaries to *XYZ*.
65 ACES_AP0_TO_XYZ = [0.9525523959, 0.0000000000, 0.0000936786,
66                    0.3439664498, 0.7281660966, -0.0721325464,
67                    0.0000000000, 0.0000000000, 1.0088251844]
68
69 # Matrix converting *ACES AP0* primaries to *XYZ*.
70 ACES_XYZ_TO_AP0 = [1.0498110175, 0.0000000000, -0.0000974845,
71                    -0.4959030231, 1.3733130458, 0.0982400361,
72                    0.0000000000, 0.0000000000, 0.9912520182]
73
74
75 def create_ACES():
76     """
77     Object description.
78
79     Parameters
80     ----------
81     parameter : type
82         Parameter description.
83
84     Returns
85     -------
86     type
87          Return value description.
88     """
89
90     # Defining the reference colorspace.
91     aces2065_1 = ColorSpace('ACES2065-1')
92     aces2065_1.description = (
93         'The Academy Color Encoding System reference color space')
94     aces2065_1.equality_group = ''
95     aces2065_1.aliases = ["lin_ap0", "aces"]
96     aces2065_1.family = 'ACES'
97     aces2065_1.is_data = False
98     aces2065_1.allocation_type = ocio.Constants.ALLOCATION_LG2
99     aces2065_1.allocation_vars = [-8, 5, 0.00390625]
100
101     return aces2065_1
102
103
104 def create_ACEScc(aces_ctl_directory,
105                   lut_directory,
106                   lut_resolution_1d,
107                   cleanup,
108                   name='ACEScc',
109                   min_value=0,
110                   max_value=1,
111                   input_scale=1):
112     """
113     Creates the *ACEScc* colorspace.
114
115     Parameters
116     ----------
117     parameter : type
118         Parameter description.
119
120     Returns
121     -------
122     Colorspace
123          *ACEScc* colorspace.
124     """
125
126     cs = ColorSpace(name)
127     cs.description = 'The %s color space' % name
128     cs.aliases = ["acescc_ap1"]
129     cs.equality_group = ''
130     cs.family = 'ACES'
131     cs.is_data = False
132     cs.allocation_type = ocio.Constants.ALLOCATION_UNIFORM
133     cs.allocation_vars = [min_value, max_value]
134
135     ctls = [os.path.join(aces_ctl_directory,
136                          'ACEScc',
137                          'ACEScsc.ACEScc_to_ACES.a1.0.0.ctl')]
138     lut = '%s_to_linear.spi1d' % name
139
140     lut = sanitize(lut)
141
142     generate_1d_LUT_from_CTL(
143         os.path.join(lut_directory, lut),
144         ctls,
145         lut_resolution_1d,
146         'float',
147         input_scale,
148         1,
149         {'transferFunctionOnly': 1},
150         cleanup,
151         aces_ctl_directory,
152         min_value,
153         max_value,
154         1)
155
156     cs.to_reference_transforms = []
157     cs.to_reference_transforms.append({
158         'type': 'lutFile',
159         'path': lut,
160         'interpolation': 'linear',
161         'direction': 'forward'})
162
163     # *AP1* primaries to *AP0* primaries.
164     cs.to_reference_transforms.append({
165         'type': 'matrix',
166         'matrix': mat44_from_mat33(ACES_AP1_TO_AP0),
167         'direction': 'forward'})
168
169     cs.from_reference_transforms = []
170     return cs
171
172
173 def create_ACESproxy(aces_ctl_directory,
174                      lut_directory,
175                      lut_resolution_1d,
176                      cleanup,
177                      name='ACESproxy'):
178     """
179     Creates the *ACESproxy* colorspace.
180
181     Parameters
182     ----------
183     parameter : type
184         Parameter description.
185
186     Returns
187     -------
188     Colorspace
189          *ACESproxy* colorspace.
190     """
191
192     cs = ColorSpace(name)
193     cs.description = 'The %s color space' % name
194     cs.aliases = ["acesproxy_ap1"]
195     cs.equality_group = ''
196     cs.family = 'ACES'
197     cs.is_data = False
198
199     ctls = [os.path.join(aces_ctl_directory,
200                          'ACESproxy',
201                          'ACEScsc.ACESproxy10i_to_ACES.a1.0.0.ctl'),
202             # This transform gets back to the *AP1* primaries.
203             # Useful as the 1d LUT is only covering the transfer function.
204             # The primaries switch is covered by the matrix below:
205             os.path.join(aces_ctl_directory,
206                          'ACEScg',
207                          'ACEScsc.ACES_to_ACEScg.a1.0.0.ctl')]
208     lut = '%s_to_linear.spi1d' % name
209
210     lut = sanitize(lut)
211
212     generate_1d_LUT_from_CTL(
213         os.path.join(lut_directory, lut),
214         ctls,
215         lut_resolution_1d,
216         'uint16',
217         64,
218         1,
219         {},
220         cleanup,
221         aces_ctl_directory,
222         0,
223         1,
224         1)
225
226     cs.to_reference_transforms = []
227     cs.to_reference_transforms.append({
228         'type': 'lutFile',
229         'path': lut,
230         'interpolation': 'linear',
231         'direction': 'forward'})
232
233     # *AP1* primaries to *AP0* primaries.
234     cs.to_reference_transforms.append({
235         'type': 'matrix',
236         'matrix': mat44_from_mat33(ACES_AP1_TO_AP0),
237         'direction': 'forward'})
238
239     cs.from_reference_transforms = []
240     return cs
241
242
243 # -------------------------------------------------------------------------
244 # *ACEScg*
245 # -------------------------------------------------------------------------
246 def create_ACEScg(aces_ctl_directory,
247                   lut_directory,
248                   lut_resolution_1d,
249                   cleanup,
250                   name='ACEScg'):
251     """
252     Creates the *ACEScg* colorspace.
253
254     Parameters
255     ----------
256     parameter : type
257         Parameter description.
258
259     Returns
260     -------
261     Colorspace
262          *ACEScg* colorspace.
263     """
264
265     cs = ColorSpace(name)
266     cs.description = 'The %s color space' % name
267     cs.aliases = ["lin_ap1"]
268     cs.equality_group = ''
269     cs.family = 'ACES'
270     cs.is_data = False
271     cs.allocation_type = ocio.Constants.ALLOCATION_LG2
272     cs.allocation_vars = [-8, 5, 0.00390625]
273
274     cs.to_reference_transforms = []
275
276     # *AP1* primaries to *AP0* primaries.
277     cs.to_reference_transforms.append({
278         'type': 'matrix',
279         'matrix': mat44_from_mat33(ACES_AP1_TO_AP0),
280         'direction': 'forward'})
281
282     cs.from_reference_transforms = []
283     return cs
284
285
286 # -------------------------------------------------------------------------
287 # *ADX*
288 # -------------------------------------------------------------------------
289 def create_ADX(lut_directory,
290                lut_resolution_1d,
291                bit_depth=10,
292                name='ADX'):
293     """
294     Creates the *ADX* colorspace.
295
296     Parameters
297     ----------
298     parameter : type
299         Parameter description.
300
301     Returns
302     -------
303     Colorspace
304          *ADX* colorspace.
305     """
306
307     name = '%s%s' % (name, bit_depth)
308     cs = ColorSpace(name)
309     cs.description = '%s color space - used for film scans' % name
310     cs.aliases = ["adx%s" % str(bit_depth)]
311     cs.equality_group = ''
312     cs.family = 'ADX'
313     cs.is_data = False
314
315     if bit_depth == 10:
316         cs.bit_depth = ocio.Constants.BIT_DEPTH_UINT10
317         ADX_to_CDD = [1023 / 500, 0, 0, 0,
318                       0, 1023 / 500, 0, 0,
319                       0, 0, 1023 / 500, 0,
320                       0, 0, 0, 1]
321         offset = [-95 / 500, -95 / 500, -95 / 500, 0]
322     elif bit_depth == 16:
323         cs.bit_depth = ocio.Constants.BIT_DEPTH_UINT16
324         ADX_to_CDD = [65535 / 8000, 0, 0, 0,
325                       0, 65535 / 8000, 0, 0,
326                       0, 0, 65535 / 8000, 0,
327                       0, 0, 0, 1]
328         offset = [-1520 / 8000, -1520 / 8000, -1520 / 8000, 0]
329
330     cs.to_reference_transforms = []
331
332     # Converting from *ADX* to *Channel-Dependent Density*.
333     cs.to_reference_transforms.append({
334         'type': 'matrix',
335         'matrix': ADX_to_CDD,
336         'offset': offset,
337         'direction': 'forward'})
338
339     # Convert from Channel-Dependent Density to Channel-Independent Density
340     cs.to_reference_transforms.append({
341         'type': 'matrix',
342         'matrix': [0.75573, 0.22197, 0.02230, 0,
343                    0.05901, 0.96928, -0.02829, 0,
344                    0.16134, 0.07406, 0.76460, 0,
345                    0, 0, 0, 1],
346         'direction': 'forward'})
347
348     # Copied from *Alex Fry*'s *adx_cid_to_rle.py*
349     def create_CID_to_RLE_LUT():
350
351         def interpolate_1D(x, xp, fp):
352             return numpy.interp(x, xp, fp)
353
354         LUT_1D_xp = [-0.190000000000000,
355                      0.010000000000000,
356                      0.028000000000000,
357                      0.054000000000000,
358                      0.095000000000000,
359                      0.145000000000000,
360                      0.220000000000000,
361                      0.300000000000000,
362                      0.400000000000000,
363                      0.500000000000000,
364                      0.600000000000000]
365
366         LUT_1D_fp = [-6.000000000000000,
367                      -2.721718645000000,
368                      -2.521718645000000,
369                      -2.321718645000000,
370                      -2.121718645000000,
371                      -1.921718645000000,
372                      -1.721718645000000,
373                      -1.521718645000000,
374                      -1.321718645000000,
375                      -1.121718645000000,
376                      -0.926545676714876]
377
378         REF_PT = ((7120 - 1520) / 8000 * (100 / 55) -
379                   math.log(0.18, 10))
380
381         def cid_to_rle(x):
382             if x <= 0.6:
383                 return interpolate_1D(x, LUT_1D_xp, LUT_1D_fp)
384             return (100 / 55) * x - REF_PT
385
386         def fit(value, from_min, from_max, to_min, to_max):
387             if from_min == from_max:
388                 raise ValueError('from_min == from_max')
389             return (value - from_min) / (from_max - from_min) * (
390                 to_max - to_min) + to_min
391
392         num_samples = 2 ** 12
393         domain = (-0.19, 3)
394         data = []
395         for i in xrange(num_samples):
396             x = i / (num_samples - 1)
397             x = fit(x, 0, 1, domain[0], domain[1])
398             data.append(cid_to_rle(x))
399
400         lut = 'ADX_CID_to_RLE.spi1d'
401         write_SPI_1d(os.path.join(lut_directory, lut),
402                      domain[0],
403                      domain[1],
404                      data,
405                      num_samples, 1)
406
407         return lut
408
409     # Converting *Channel Independent Density* values to
410     # *Relative Log Exposure* values.
411     lut = create_CID_to_RLE_LUT()
412     cs.to_reference_transforms.append({
413         'type': 'lutFile',
414         'path': lut,
415         'interpolation': 'linear',
416         'direction': 'forward'})
417
418     # Converting *Relative Log Exposure* values to
419     # *Relative Exposure* values.
420     cs.to_reference_transforms.append({
421         'type': 'log',
422         'base': 10,
423         'direction': 'inverse'})
424
425     # Convert *Relative Exposure* values to *ACES* values.
426     cs.to_reference_transforms.append({
427         'type': 'matrix',
428         'matrix': [0.72286, 0.12630, 0.15084, 0,
429                    0.11923, 0.76418, 0.11659, 0,
430                    0.01427, 0.08213, 0.90359, 0,
431                    0, 0, 0, 1],
432         'direction': 'forward'})
433
434     cs.from_reference_transforms = []
435     return cs
436
437
438 # -------------------------------------------------------------------------
439 # *Generic Log Transform*
440 # -------------------------------------------------------------------------
441 def create_generic_log(aces_ctl_directory,
442                        lut_directory,
443                        lut_resolution_1d,
444                        cleanup,
445                        name='log',
446                        aliases=[],
447                        min_value=0,
448                        max_value=1,
449                        input_scale=1,
450                        middle_grey=0.18,
451                        min_exposure=-6,
452                        max_exposure=6.5):
453     """
454     Creates the *Generic Log* colorspace.
455
456     Parameters
457     ----------
458     parameter : type
459         Parameter description.
460
461     Returns
462     -------
463     Colorspace
464          *Generic Log* colorspace.
465     """
466
467     cs = ColorSpace(name)
468     cs.description = 'The %s color space' % name
469     cs.aliases = aliases
470     cs.equality_group = name
471     cs.family = 'Utility'
472     cs.is_data = False
473
474     ctls = [os.path.join(
475         aces_ctl_directory,
476         'utilities',
477         'ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl')]
478     lut = '%s_to_linear.spi1d' % name
479
480     lut = sanitize(lut)
481
482     generate_1d_LUT_from_CTL(
483         os.path.join(lut_directory, lut),
484         ctls,
485         lut_resolution_1d,
486         'float',
487         input_scale,
488         1,
489         {'middleGrey': middle_grey,
490          'minExposure': min_exposure,
491          'maxExposure': max_exposure},
492         cleanup,
493         aces_ctl_directory,
494         min_value,
495         max_value,
496         1)
497
498     cs.to_reference_transforms = []
499     cs.to_reference_transforms.append({
500         'type': 'lutFile',
501         'path': lut,
502         'interpolation': 'linear',
503         'direction': 'forward'})
504
505     cs.from_reference_transforms = []
506     return cs
507
508
509 # -------------------------------------------------------------------------
510 # *base Dolby PQ Transform*
511 # -------------------------------------------------------------------------
512 def create_dolbypq(aces_CTL_directory,
513                    lut_directory,
514                    lut_resolution_1d,
515                    cleanup,
516                    name='pq',
517                    aliases=[],
518                    min_value=0.0,
519                    max_value=1.0,
520                    input_scale=1.0):
521     cs = ColorSpace(name)
522     cs.description = 'The %s color space' % name
523     cs.aliases = aliases
524     cs.equality_group = name
525     cs.family = 'Utility'
526     cs.is_data = False
527
528     ctls = [os.path.join(
529         aces_CTL_directory,
530         'utilities',
531         'ACESlib.OCIO_shaper_dolbypq_to_lin.a1.0.0.ctl')]
532     lut = '%s_to_linear.spi1d' % name
533
534     lut = sanitize(lut)
535
536     generate_1d_LUT_from_CTL(
537         os.path.join(lut_directory, lut),
538         ctls,
539         lut_resolution_1d,
540         'float',
541         input_scale,
542         1.0,
543         {},
544         cleanup,
545         aces_CTL_directory,
546         min_value,
547         max_value)
548
549     cs.to_reference_transforms = []
550     cs.to_reference_transforms.append({
551         'type': 'lutFile',
552         'path': lut,
553         'interpolation': 'linear',
554         'direction': 'forward'})
555
556     cs.from_reference_transforms = []
557     return cs
558
559
560 # -------------------------------------------------------------------------
561 # *Dolby PQ Transform that considers a fixed linear range*
562 # -------------------------------------------------------------------------
563 def create_dolbypq_scaled(aces_CTL_directory,
564                           lut_directory,
565                           lut_resolution_1d,
566                           cleanup,
567                           name='pq',
568                           aliases=[],
569                           min_value=0.0,
570                           max_value=1.0,
571                           input_scale=1.0,
572                           middle_grey=0.18,
573                           min_exposure=-6.0,
574                           max_exposure=6.5):
575     cs = ColorSpace(name)
576     cs.description = 'The %s color space' % name
577     cs.aliases = aliases
578     cs.equality_group = name
579     cs.family = 'Utility'
580     cs.is_data = False
581
582     ctls = [os.path.join(
583         aces_CTL_directory,
584         'utilities',
585         'ACESlib.OCIO_shaper_dolbypq_to_lin_param.a1.0.0.ctl')]
586     lut = '%s_to_linear.spi1d' % name
587
588     lut = sanitize(lut)
589
590     generate_1d_LUT_from_CTL(
591         os.path.join(lut_directory, lut),
592         ctls,
593         lut_resolution_1d,
594         'float',
595         input_scale,
596         1.0,
597         {'middleGrey': middle_grey,
598          'minExposure': min_exposure,
599          'maxExposure': max_exposure},
600         cleanup,
601         aces_CTL_directory,
602         min_value,
603         max_value)
604
605     cs.to_reference_transforms = []
606     cs.to_reference_transforms.append({
607         'type': 'lutFile',
608         'path': lut,
609         'interpolation': 'linear',
610         'direction': 'forward'})
611
612     cs.from_reference_transforms = []
613     return cs
614
615
616 # -------------------------------------------------------------------------
617 # *Individual LMT*
618 # -------------------------------------------------------------------------
619 def create_ACES_LMT(lmt_name,
620                     lmt_values,
621                     shaper_info,
622                     aces_ctl_directory,
623                     lut_directory,
624                     lut_resolution_1d=1024,
625                     lut_resolution_3d=64,
626                     cleanup=True,
627                     aliases=None):
628     """
629     Creates the *ACES LMT* colorspace.
630
631     Parameters
632     ----------
633     parameter : type
634         Parameter description.
635
636     Returns
637     -------
638     Colorspace
639          *ACES LMT* colorspace.
640     """
641
642     if aliases is None:
643         aliases = []
644
645     cs = ColorSpace('%s' % lmt_name)
646     cs.description = 'The ACES Look Transform: %s' % lmt_name
647     cs.aliases = aliases
648     cs.equality_group = ''
649     cs.family = 'Look'
650     cs.is_data = False
651     cs.allocation_type = ocio.Constants.ALLOCATION_LG2
652     cs.allocation_vars = [-8, 5, 0.00390625]
653
654     pprint.pprint(lmt_values)
655
656     # Generating the *shaper* transform.
657     (shaper_name,
658      shaper_to_ACES_CTL,
659      shaper_from_ACES_CTL,
660      shaper_input_scale,
661      shaper_params) = shaper_info
662
663     # Add the shaper transform
664     shaper_lut = '%s_to_linear.spi1d' % shaper_name
665     shaper_lut = sanitize(shaper_lut)
666
667     shaper_OCIO_transform = {
668         'type': 'lutFile',
669         'path': shaper_lut,
670         'interpolation': 'linear',
671         'direction': 'inverse'}
672
673     # Generating the forward transform.
674     cs.from_reference_transforms = []
675
676     if 'transformCTL' in lmt_values:
677         ctls = [shaper_to_ACES_CTL % aces_ctl_directory,
678                 os.path.join(aces_ctl_directory,
679                              lmt_values['transformCTL'])]
680         lut = '%s.%s.spi3d' % (shaper_name, lmt_name)
681
682         lut = sanitize(lut)
683
684         generate_3d_LUT_from_CTL(
685             os.path.join(lut_directory, lut),
686             ctls,
687             lut_resolution_3d,
688             'float',
689             1 / shaper_input_scale,
690             1,
691             shaper_params,
692             cleanup,
693             aces_ctl_directory)
694
695         cs.from_reference_transforms.append(shaper_OCIO_transform)
696         cs.from_reference_transforms.append({
697             'type': 'lutFile',
698             'path': lut,
699             'interpolation': 'tetrahedral',
700             'direction': 'forward'})
701
702     # Generating the inverse transform.
703     cs.to_reference_transforms = []
704
705     if 'transformCTLInverse' in lmt_values:
706         ctls = [os.path.join(aces_ctl_directory,
707                              lmt_values['transformCTLInverse']),
708                 shaper_from_ACES_CTL % aces_ctl_directory]
709         lut = 'Inverse.%s.%s.spi3d' % (odt_name, shaper_name)
710
711         lut = sanitize(lut)
712
713         generate_3d_LUT_from_CTL(
714             os.path.join(lut_directory, lut),
715             ctls,
716             lut_resolution_3d,
717             'half',
718             1,
719             shaper_input_scale,
720             shaper_params,
721             cleanup,
722             aces_ctl_directory,
723             0,
724             1,
725             1)
726
727         cs.to_reference_transforms.append({
728             'type': 'lutFile',
729             'path': lut,
730             'interpolation': 'tetrahedral',
731             'direction': 'forward'})
732
733         shaper_inverse = shaper_OCIO_transform.copy()
734         shaper_inverse['direction'] = 'forward'
735         cs.to_reference_transforms.append(shaper_inverse)
736
737     return cs
738
739
740 # -------------------------------------------------------------------------
741 # *LMTs*
742 # -------------------------------------------------------------------------
743 def create_LMTs(aces_ctl_directory,
744                 lut_directory,
745                 lut_resolution_1d,
746                 lut_resolution_3d,
747                 lmt_info,
748                 shaper_name,
749                 cleanup):
750     """
751     Object description.
752
753     Parameters
754     ----------
755     parameter : type
756         Parameter description.
757
758     Returns
759     -------
760     type
761          Return value description.
762     """
763
764     colorspaces = []
765
766     # -------------------------------------------------------------------------
767     # *LMT Shaper*
768     # -------------------------------------------------------------------------
769     lmt_lut_resolution_1d = max(4096, lut_resolution_1d)
770     lmt_lut_resolution_3d = max(65, lut_resolution_3d)
771
772     # Defining the *Log 2* shaper.
773     lmt_shaper_name = 'LMT Shaper'
774     lmt_shaper_name_aliases = ['crv_lmtshaper']
775     lmt_params = {
776         'middleGrey': 0.18,
777         'minExposure': -10,
778         'maxExposure': 6.5}
779
780     lmt_shaper = create_generic_log(aces_ctl_directory,
781                                     lut_directory,
782                                     lmt_lut_resolution_1d,
783                                     cleanup,
784                                     name=lmt_shaper_name,
785                                     middle_grey=lmt_params['middleGrey'],
786                                     min_exposure=lmt_params['minExposure'],
787                                     max_exposure=lmt_params['maxExposure'],
788                                     aliases=lmt_shaper_name_aliases)
789     colorspaces.append(lmt_shaper)
790
791     shaper_input_scale_generic_log2 = 1
792
793     # *Log 2* shaper name and *CTL* transforms bundled up.
794     lmt_shaper_data = [
795         lmt_shaper_name,
796         os.path.join('%s',
797                      'utilities',
798                      'ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl'),
799         os.path.join('%s',
800                      'utilities',
801                      'ACESlib.OCIO_shaper_lin_to_log2_param.a1.0.0.ctl'),
802         shaper_input_scale_generic_log2,
803         lmt_params]
804
805     sorted_LMTs = sorted(lmt_info.iteritems(), key=lambda x: x[1])
806     print(sorted_LMTs)
807     for lmt in sorted_LMTs:
808         lmt_name, lmt_values = lmt
809         lmt_aliases = ["look_%s" % compact(lmt_values['transformUserName'])]
810         cs = create_ACES_LMT(
811             lmt_values['transformUserName'],
812             lmt_values,
813             lmt_shaper_data,
814             aces_ctl_directory,
815             lut_directory,
816             lmt_lut_resolution_1d,
817             lmt_lut_resolution_3d,
818             cleanup,
819             lmt_aliases)
820         colorspaces.append(cs)
821
822     return colorspaces
823
824
825 # -------------------------------------------------------------------------
826 # *ACES RRT* with supplied *ODT*.
827 # -------------------------------------------------------------------------
828 def create_ACES_RRT_plus_ODT(odt_name,
829                              odt_values,
830                              shaper_info,
831                              aces_ctl_directory,
832                              lut_directory,
833                              lut_resolution_1d=1024,
834                              lut_resolution_3d=64,
835                              cleanup=True,
836                              aliases=None):
837     """
838     Object description.
839
840     Parameters
841     ----------
842     parameter : type
843         Parameter description.
844
845     Returns
846     -------
847     type
848          Return value description.
849     """
850
851     if aliases is None:
852         aliases = []
853
854     cs = ColorSpace('%s' % odt_name)
855     cs.description = '%s - %s Output Transform' % (
856         odt_values['transformUserNamePrefix'], odt_name)
857     cs.aliases = aliases
858     cs.equality_group = ''
859     cs.family = 'Output'
860     cs.is_data = False
861
862     pprint.pprint(odt_values)
863
864     # Generating the *shaper* transform.
865     (shaper_name,
866      shaper_to_ACES_CTL,
867      shaper_from_ACES_CTL,
868      shaper_input_scale,
869      shaper_params) = shaper_info
870
871     if 'legalRange' in odt_values:
872         shaper_params['legalRange'] = odt_values['legalRange']
873     else:
874         shaper_params['legalRange'] = 0
875
876     # Add the shaper transform
877     shaper_lut = '%s_to_linear.spi1d' % shaper_name
878     shaper_lut = sanitize(shaper_lut)
879
880     shaper_OCIO_transform = {
881         'type': 'lutFile',
882         'path': shaper_lut,
883         'interpolation': 'linear',
884         'direction': 'inverse'}
885
886     # Generating the *forward* transform.
887     cs.from_reference_transforms = []
888
889     if 'transformLUT' in odt_values:
890         transform_LUT_file_name = os.path.basename(
891             odt_values['transformLUT'])
892         lut = os.path.join(lut_directory, transform_LUT_file_name)
893         shutil.copy(odt_values['transformLUT'], lut)
894
895         cs.from_reference_transforms.append(shaper_OCIO_transform)
896         cs.from_reference_transforms.append({
897             'type': 'lutFile',
898             'path': transform_LUT_file_name,
899             'interpolation': 'tetrahedral',
900             'direction': 'forward'})
901     elif 'transformCTL' in odt_values:
902         ctls = [
903             shaper_to_ACES_CTL % aces_ctl_directory,
904             os.path.join(aces_ctl_directory,
905                          'rrt',
906                          'RRT.a1.0.0.ctl'),
907             os.path.join(aces_ctl_directory,
908                          'odt',
909                          odt_values['transformCTL'])]
910         lut = '%s.RRT.a1.0.0.%s.spi3d' % (shaper_name, odt_name)
911
912         lut = sanitize(lut)
913
914         generate_3d_LUT_from_CTL(
915             os.path.join(lut_directory, lut),
916             # shaperLUT,
917             ctls,
918             lut_resolution_3d,
919             'float',
920             1 / shaper_input_scale,
921             1,
922             shaper_params,
923             cleanup,
924             aces_ctl_directory)
925
926         cs.from_reference_transforms.append(shaper_OCIO_transform)
927         cs.from_reference_transforms.append({
928             'type': 'lutFile',
929             'path': lut,
930             'interpolation': 'tetrahedral',
931             'direction': 'forward'})
932
933     # Generating the *inverse* transform.
934     cs.to_reference_transforms = []
935
936     if 'transformLUTInverse' in odt_values:
937         transform_LUT_inverse_file_name = os.path.basename(
938             odt_values['transformLUTInverse'])
939         lut = os.path.join(lut_directory, transform_LUT_inverse_file_name)
940         shutil.copy(odt_values['transformLUTInverse'], lut)
941
942         cs.to_reference_transforms.append({
943             'type': 'lutFile',
944             'path': transform_LUT_inverse_file_name,
945             'interpolation': 'tetrahedral',
946             'direction': 'forward'})
947
948         shaper_inverse = shaper_OCIO_transform.copy()
949         shaper_inverse['direction'] = 'forward'
950         cs.to_reference_transforms.append(shaper_inverse)
951     elif 'transformCTLInverse' in odt_values:
952         ctls = [os.path.join(aces_ctl_directory,
953                              'odt',
954                              odt_values['transformCTLInverse']),
955                 os.path.join(aces_ctl_directory,
956                              'rrt',
957                              'InvRRT.a1.0.0.ctl'),
958                 shaper_from_ACES_CTL % aces_ctl_directory]
959         lut = 'InvRRT.a1.0.0.%s.%s.spi3d' % (odt_name, shaper_name)
960
961         lut = sanitize(lut)
962
963         generate_3d_LUT_from_CTL(
964             os.path.join(lut_directory, lut),
965             # None,
966             ctls,
967             lut_resolution_3d,
968             'half',
969             1,
970             shaper_input_scale,
971             shaper_params,
972             cleanup,
973             aces_ctl_directory)
974
975         cs.to_reference_transforms.append({
976             'type': 'lutFile',
977             'path': lut,
978             'interpolation': 'tetrahedral',
979             'direction': 'forward'})
980
981         shaper_inverse = shaper_OCIO_transform.copy()
982         shaper_inverse['direction'] = 'forward'
983         cs.to_reference_transforms.append(shaper_inverse)
984
985     return cs
986
987
988 # -------------------------------------------------------------------------
989 # *ODTs*
990 # -------------------------------------------------------------------------
991 def create_ODTs(aces_ctl_directory,
992                 lut_directory,
993                 lut_resolution_1d,
994                 lut_resolution_3d,
995                 odt_info,
996                 shaper_name,
997                 cleanup,
998                 linear_display_space,
999                 log_display_space):
1000     """
1001     Object description.
1002
1003     Parameters
1004     ----------
1005     parameter : type
1006         Parameter description.
1007
1008     Returns
1009     -------
1010     type
1011          Return value description.
1012     """
1013
1014     colorspaces = []
1015     displays = {}
1016
1017     # -------------------------------------------------------------------------
1018     # *RRT / ODT* Shaper Options
1019     # -------------------------------------------------------------------------
1020     shaper_data = {}
1021
1022     # Defining the *Log 2* shaper.
1023     log2_shaper_name = shaper_name
1024     log2_shaper_name_aliases = ["crv_%s" % compact(log2_shaper_name)]
1025     log2_params = {
1026         'middleGrey': 0.18,
1027         'minExposure': -6,
1028         'maxExposure': 6.5}
1029
1030     log2_shaper_colorspace = create_generic_log(
1031         aces_ctl_directory,
1032         lut_directory,
1033         lut_resolution_1d,
1034         cleanup,
1035         name=log2_shaper_name,
1036         middle_grey=log2_params['middleGrey'],
1037         min_exposure=log2_params['minExposure'],
1038         max_exposure=log2_params['maxExposure'],
1039         aliases=log2_shaper_name_aliases)
1040     colorspaces.append(log2_shaper_colorspace)
1041
1042     shaper_input_scale_generic_log2 = 1
1043
1044     # *Log 2* shaper name and *CTL* transforms bundled up.
1045     log2_shaper_data = [
1046         log2_shaper_name,
1047         os.path.join('%s',
1048                      'utilities',
1049                      'ACESlib.OCIO_shaper_log2_to_lin_param.a1.0.0.ctl'),
1050         os.path.join('%s',
1051                      'utilities',
1052                      'ACESlib.OCIO_shaper_lin_to_log2_param.a1.0.0.ctl'),
1053         shaper_input_scale_generic_log2,
1054         log2_params]
1055
1056     shaper_data[log2_shaper_name] = log2_shaper_data
1057
1058     # Space with a more user-friendly name. Direct copy otherwise.
1059     log2_shaper_copy_name = "Log2 Shaper"
1060     log2_shaper_copy_colorspace = ColorSpace(log2_shaper_copy_name)
1061     log2_shaper_copy_colorspace.description = 'The %s color space' % log2_shaper_copy_name
1062     log2_shaper_copy_colorspace.aliases = ["crv_%s" % compact(log2_shaper_copy_name)]
1063     log2_shaper_copy_colorspace.equality_group = log2_shaper_copy_name
1064     log2_shaper_copy_colorspace.family = log2_shaper_colorspace.family
1065     log2_shaper_copy_colorspace.is_data = log2_shaper_colorspace.is_data
1066     log2_shaper_copy_colorspace.to_reference_transforms = list(
1067         log2_shaper_colorspace.to_reference_transforms)
1068     log2_shaper_copy_colorspace.from_reference_transforms = list(
1069         log2_shaper_colorspace.from_reference_transforms)
1070     colorspaces.append(log2_shaper_copy_colorspace)
1071
1072     # Defining the *Log2 shaper that includes the AP1* primaries.
1073     log2_shaper_api1_name = "%s - AP1" % "Log2 Shaper"
1074     log2_shaper_api1_colorspace = ColorSpace(log2_shaper_api1_name)
1075     log2_shaper_api1_colorspace.description = 'The %s color space' % log2_shaper_api1_name
1076     log2_shaper_api1_colorspace.aliases = [
1077         "%s_ap1" % compact(log2_shaper_copy_name)]
1078     log2_shaper_api1_colorspace.equality_group = log2_shaper_api1_name
1079     log2_shaper_api1_colorspace.family = log2_shaper_colorspace.family
1080     log2_shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data
1081     log2_shaper_api1_colorspace.to_reference_transforms = list(
1082         log2_shaper_colorspace.to_reference_transforms)
1083     log2_shaper_api1_colorspace.from_reference_transforms = list(
1084         log2_shaper_colorspace.from_reference_transforms)
1085
1086     # *AP1* primaries to *AP0* primaries.
1087     log2_shaper_api1_colorspace.to_reference_transforms.append({
1088         'type': 'matrix',
1089         'matrix': mat44_from_mat33(ACES_AP1_TO_AP0),
1090         'direction': 'forward'
1091     })
1092     colorspaces.append(log2_shaper_api1_colorspace)
1093
1094     # Defining the *Log2 shaper that includes the AP1* primaries.
1095     # Named with 'shaper_name' variable. Needed for some LUT baking steps.
1096     shaper_api1_name = "%s - AP1" % shaper_name
1097     shaper_api1_colorspace = ColorSpace(shaper_api1_name)
1098     shaper_api1_colorspace.description = 'The %s color space' % shaper_api1_name
1099     shaper_api1_colorspace.aliases = ["%s_ap1" % compact(shaper_name)]
1100     shaper_api1_colorspace.equality_group = shaper_api1_name
1101     shaper_api1_colorspace.family = log2_shaper_colorspace.family
1102     shaper_api1_colorspace.is_data = log2_shaper_colorspace.is_data
1103     shaper_api1_colorspace.to_reference_transforms = list(
1104         log2_shaper_api1_colorspace.to_reference_transforms)
1105     shaper_api1_colorspace.from_reference_transforms = list(
1106         log2_shaper_api1_colorspace.from_reference_transforms)
1107     colorspaces.append(shaper_api1_colorspace)
1108
1109     # Define the base *Dolby PQ Shaper*
1110     #
1111     dolbypq_shaper_name = "Dolby PQ 10000"
1112     dolbypq_shaper_name_aliases = ["crv_%s" % "dolbypq_10000"]
1113
1114     dolbypq_shaper_colorspace = create_dolbypq(
1115         aces_ctl_directory,
1116         lut_directory,
1117         lut_resolution_1d,
1118         cleanup,
1119         name=dolbypq_shaper_name,
1120         aliases=dolbypq_shaper_name_aliases)
1121     colorspaces.append(dolbypq_shaper_colorspace)
1122
1123     # *Dolby PQ* shaper name and *CTL* transforms bundled up.
1124     dolbypq_shaper_data = [
1125         dolbypq_shaper_name,
1126         os.path.join('%s',
1127                      'utilities',
1128                      'ACESlib.OCIO_shaper_dolbypq_to_lin.a1.0.0.ctl'),
1129         os.path.join('%s',
1130                      'utilities',
1131                      'ACESlib.OCIO_shaper_lin_to_dolbypq.a1.0.0.ctl'),
1132         1.0,
1133         {}]
1134
1135     shaper_data[dolbypq_shaper_name] = dolbypq_shaper_data
1136
1137     # Define the *Dolby PQ Shaper that considers a fixed linear range*
1138     #
1139     dolbypq_scaled_shaper_name = "Dolby PQ Scaled"
1140     dolbypq_scaled_shaper_name_aliases = ["crv_%s" % "dolbypq_scaled"]
1141
1142     dolbypq_scaled_shaper_colorspace = create_dolbypq_scaled(
1143         aces_ctl_directory,
1144         lut_directory,
1145         lut_resolution_1d,
1146         cleanup,
1147         name=dolbypq_scaled_shaper_name,
1148         aliases=dolbypq_scaled_shaper_name_aliases)
1149     colorspaces.append(dolbypq_scaled_shaper_colorspace)
1150
1151     # *Dolby PQ* shaper name and *CTL* transforms bundled up.
1152     dolbypq_scaled_shaper_data = [
1153         dolbypq_scaled_shaper_name,
1154         os.path.join('%s',
1155                      'utilities',
1156                      'ACESlib.OCIO_shaper_dolbypq_to_lin_param.a1.0.0.ctl'),
1157         os.path.join('%s',
1158                      'utilities',
1159                      'ACESlib.OCIO_shaper_lin_to_dolbypq_param.a1.0.0.ctl'),
1160         1.0,
1161         log2_params]
1162
1163     shaper_data[dolbypq_scaled_shaper_name] = dolbypq_scaled_shaper_data
1164
1165     #
1166     # Pick a specific shaper
1167     #
1168     rrt_shaper = log2_shaper_data
1169     # rrt_shaper = dolbypq_scaled_shaper_data
1170
1171     # *RRT + ODT* combinations.
1172     sorted_odts = sorted(odt_info.iteritems(), key=lambda x: x[1])
1173     print(sorted_odts)
1174     for odt in sorted_odts:
1175         (odt_name, odt_values) = odt
1176
1177         # Generating legal range transform for *ODTs* that can generate 
1178         # either *legal* or *full* output.
1179         if odt_values['transformHasFullLegalSwitch']:
1180             odt_name_legal = '%s - Legal' % odt_values['transformUserName']
1181         else:
1182             odt_name_legal = odt_values['transformUserName']
1183
1184         odt_legal = odt_values.copy()
1185         odt_legal['legalRange'] = 1
1186
1187         odt_aliases = ["out_%s" % compact(odt_name_legal)]
1188
1189         cs = create_ACES_RRT_plus_ODT(
1190             odt_name_legal,
1191             odt_legal,
1192             rrt_shaper,
1193             aces_ctl_directory,
1194             lut_directory,
1195             lut_resolution_1d,
1196             lut_resolution_3d,
1197             cleanup,
1198             odt_aliases)
1199         colorspaces.append(cs)
1200
1201         displays[odt_name_legal] = {
1202             'Linear': linear_display_space,
1203             'Log': log_display_space,
1204             'Output Transform': cs}
1205
1206
1207         # Generating full range transform for *ODTs* that can generate 
1208         # either *legal* or *full* output.
1209         if odt_values['transformHasFullLegalSwitch']:
1210             print('Generating full range ODT for %s' % odt_name)
1211
1212             odt_name_full = '%s - Full' % odt_values['transformUserName']
1213             odt_full = odt_values.copy()
1214             odt_full['legalRange'] = 0
1215
1216             odt_full_aliases = ["out_%s" % compact(odt_name_full)]
1217
1218             cs_full = create_ACES_RRT_plus_ODT(
1219                 odt_name_full,
1220                 odt_full,
1221                 rrt_shaper,
1222                 aces_ctl_directory,
1223                 lut_directory,
1224                 lut_resolution_1d,
1225                 lut_resolution_3d,
1226                 cleanup,
1227                 odt_full_aliases)
1228             colorspaces.append(cs_full)
1229
1230             displays[odt_name_full] = {
1231                 'Linear': linear_display_space,
1232                 'Log': log_display_space,
1233                 'Output Transform': cs_full}
1234
1235     return (colorspaces, displays)
1236
1237
1238 def get_transform_info(ctl_transform):
1239     """
1240     Object description.
1241
1242     Parameters
1243     ----------
1244     parameter : type
1245         Parameter description.
1246
1247     Returns
1248     -------
1249     type
1250          Return value description.
1251     """
1252
1253     with open(ctl_transform, 'rb') as fp:
1254         lines = fp.readlines()
1255
1256     # Retrieving the *transform ID* and *User Name*.
1257     transform_id = lines[1][3:].split('<')[1].split('>')[1].strip()
1258     transform_user_name = '-'.join(
1259         lines[2][3:].split('<')[1].split('>')[1].split('-')[1:]).strip()
1260     transform_user_name_prefix = (
1261         lines[2][3:].split('<')[1].split('>')[1].split('-')[0].strip())
1262
1263     # Figuring out if this transform has options for processing full and legal range
1264     transform_full_legal_switch = False
1265     for line in lines:
1266         if line.strip() == "input varying int legalRange = 0":
1267             # print( "%s has legal range flag" % transform_user_name)
1268             transform_full_legal_switch = True
1269             break
1270
1271     return (transform_id, transform_user_name, transform_user_name_prefix,
1272             transform_full_legal_switch)
1273
1274
1275 def get_ODTs_info(aces_ctl_directory):
1276     """
1277     Object description.
1278
1279     For versions after WGR9.
1280
1281     Parameters
1282     ----------
1283     parameter : type
1284         Parameter description.
1285
1286     Returns
1287     -------
1288     type
1289          Return value description.
1290     """
1291
1292     # TODO: Investigate usage of *files_walker* definition here.
1293     # Credit to *Alex Fry* for the original approach here.
1294     odt_dir = os.path.join(aces_ctl_directory, 'odt')
1295     all_odt = []
1296     for dir_name, subdir_list, file_list in os.walk(odt_dir):
1297         for fname in file_list:
1298             all_odt.append((os.path.join(dir_name, fname)))
1299
1300     odt_CTLs = [x for x in all_odt if
1301                 ('InvODT' not in x) and (os.path.split(x)[-1][0] != '.')]
1302
1303     odts = {}
1304
1305     for odt_CTL in odt_CTLs:
1306         odt_tokens = os.path.split(odt_CTL)
1307
1308         # Handling nested directories.
1309         odt_path_tokens = os.path.split(odt_tokens[-2])
1310         odt_dir = odt_path_tokens[-1]
1311         while odt_path_tokens[-2][-3:] != 'odt':
1312             odt_path_tokens = os.path.split(odt_path_tokens[-2])
1313             odt_dir = os.path.join(odt_path_tokens[-1], odt_dir)
1314
1315         # Building full name,
1316         transform_CTL = odt_tokens[-1]
1317         odt_name = string.join(transform_CTL.split('.')[1:-1], '.')
1318
1319         # Finding id, user name and user name prefix.
1320         (transform_ID,
1321          transform_user_name,
1322          transform_user_name_prefix,
1323          transform_full_legal_switch) = get_transform_info(
1324             os.path.join(aces_ctl_directory, 'odt', odt_dir, transform_CTL))
1325
1326         # Finding inverse.
1327         transform_CTL_inverse = 'InvODT.%s.ctl' % odt_name
1328         if not os.path.exists(
1329                 os.path.join(odt_tokens[-2], transform_CTL_inverse)):
1330             transform_CTL_inverse = None
1331
1332         # Add to list of ODTs
1333         odts[odt_name] = {}
1334         odts[odt_name]['transformCTL'] = os.path.join(odt_dir, transform_CTL)
1335         if transform_CTL_inverse is not None:
1336             odts[odt_name]['transformCTLInverse'] = os.path.join(
1337                 odt_dir, transform_CTL_inverse)
1338
1339         odts[odt_name]['transformID'] = transform_ID
1340         odts[odt_name]['transformUserNamePrefix'] = transform_user_name_prefix
1341         odts[odt_name]['transformUserName'] = transform_user_name
1342         odts[odt_name][
1343             'transformHasFullLegalSwitch'] = transform_full_legal_switch
1344
1345         forward_CTL = odts[odt_name]['transformCTL']
1346
1347         print('ODT : %s' % odt_name)
1348         print('\tTransform ID               : %s' % transform_ID)
1349         print('\tTransform User Name Prefix : %s' % transform_user_name_prefix)
1350         print('\tTransform User Name        : %s' % transform_user_name)
1351         print(
1352             '\tHas Full / Legal Switch    : %s' % transform_full_legal_switch)
1353         print('\tForward ctl                : %s' % forward_CTL)
1354         if 'transformCTLInverse' in odts[odt_name]:
1355             inverse_CTL = odts[odt_name]['transformCTLInverse']
1356             print('\tInverse ctl                : %s' % inverse_CTL)
1357         else:
1358             print('\tInverse ctl                : %s' % 'None')
1359
1360     print('\n')
1361
1362     return odts
1363
1364
1365 def get_LMTs_info(aces_ctl_directory):
1366     """
1367     Object description.
1368
1369     For versions after WGR9.
1370
1371     Parameters
1372     ----------
1373     parameter : type
1374         Parameter description.
1375
1376     Returns
1377     -------
1378     type
1379          Return value description.
1380     """
1381
1382     # TODO: Investigate refactoring with previous definition.
1383
1384     # Credit to Alex Fry for the original approach here
1385     lmt_dir = os.path.join(aces_ctl_directory, 'lmt')
1386     all_lmt = []
1387     for dir_name, subdir_list, file_list in os.walk(lmt_dir):
1388         for fname in file_list:
1389             all_lmt.append((os.path.join(dir_name, fname)))
1390
1391     lmt_CTLs = [x for x in all_lmt if
1392                 ('InvLMT' not in x) and ('README' not in x) and (
1393                     os.path.split(x)[-1][0] != '.')]
1394
1395     lmts = {}
1396
1397     for lmt_CTL in lmt_CTLs:
1398         lmt_tokens = os.path.split(lmt_CTL)
1399
1400         # Handlimg nested directories.
1401         lmt_path_tokens = os.path.split(lmt_tokens[-2])
1402         lmt_dir = lmt_path_tokens[-1]
1403         while lmt_path_tokens[-2][-3:] != 'ctl':
1404             lmt_path_tokens = os.path.split(lmt_path_tokens[-2])
1405             lmt_dir = os.path.join(lmt_path_tokens[-1], lmt_dir)
1406
1407         # Building full name.
1408         transform_CTL = lmt_tokens[-1]
1409         lmt_name = string.join(transform_CTL.split('.')[1:-1], '.')
1410
1411         # Finding id, user name and user name prefix.
1412         (transform_ID,
1413          transform_user_name,
1414          transform_user_name_prefix,
1415          transform_full_legal_switch) = get_transform_info(
1416             os.path.join(aces_ctl_directory, lmt_dir, transform_CTL))
1417
1418         # Finding inverse.
1419         transform_CTL_inverse = 'InvLMT.%s.ctl' % lmt_name
1420         if not os.path.exists(
1421                 os.path.join(lmt_tokens[-2], transform_CTL_inverse)):
1422             transform_CTL_inverse = None
1423
1424         lmts[lmt_name] = {}
1425         lmts[lmt_name]['transformCTL'] = os.path.join(lmt_dir, transform_CTL)
1426         if transform_CTL_inverse is not None:
1427             lmts[lmt_name]['transformCTLInverse'] = os.path.join(
1428                 lmt_dir, transform_CTL_inverse)
1429
1430         lmts[lmt_name]['transformID'] = transform_ID
1431         lmts[lmt_name]['transformUserNamePrefix'] = transform_user_name_prefix
1432         lmts[lmt_name]['transformUserName'] = transform_user_name
1433
1434         forward_CTL = lmts[lmt_name]['transformCTL']
1435
1436         print('LMT : %s' % lmt_name)
1437         print('\tTransform ID               : %s' % transform_ID)
1438         print('\tTransform User Name Prefix : %s' % transform_user_name_prefix)
1439         print('\tTransform User Name        : %s' % transform_user_name)
1440         print('\t Forward ctl               : %s' % forward_CTL)
1441         if 'transformCTLInverse' in lmts[lmt_name]:
1442             inverse_CTL = lmts[lmt_name]['transformCTLInverse']
1443             print('\t Inverse ctl                : %s' % inverse_CTL)
1444         else:
1445             print('\t Inverse ctl                : %s' % 'None')
1446
1447     print('\n')
1448
1449     return lmts
1450
1451
1452 def create_colorspaces(aces_ctl_directory,
1453                        lut_directory,
1454                        lut_resolution_1d,
1455                        lut_resolution_3d,
1456                        lmt_info,
1457                        odt_info,
1458                        shaper_name,
1459                        cleanup):
1460     """
1461     Generates the colorspace conversions.
1462
1463     Parameters
1464     ----------
1465     parameter : type
1466         Parameter description.
1467
1468     Returns
1469     -------
1470     type
1471          Return value description.
1472     """
1473
1474     colorspaces = []
1475
1476     ACES = create_ACES()
1477
1478     ACEScc = create_ACEScc(aces_ctl_directory, lut_directory,
1479                            lut_resolution_1d, cleanup,
1480                            min_value=-0.35840, max_value=1.468)
1481     colorspaces.append(ACEScc)
1482
1483     ACESproxy = create_ACESproxy(aces_ctl_directory, lut_directory,
1484                                  lut_resolution_1d, cleanup)
1485     colorspaces.append(ACESproxy)
1486
1487     ACEScg = create_ACEScg(aces_ctl_directory, lut_directory,
1488                            lut_resolution_1d, cleanup)
1489     colorspaces.append(ACEScg)
1490
1491     ADX10 = create_ADX(lut_directory, lut_resolution_1d, bit_depth=10)
1492     colorspaces.append(ADX10)
1493
1494     ADX16 = create_ADX(lut_directory, lut_resolution_1d, bit_depth=16)
1495     colorspaces.append(ADX16)
1496
1497     lmts = create_LMTs(aces_ctl_directory,
1498                        lut_directory,
1499                        lut_resolution_1d,
1500                        lut_resolution_3d,
1501                        lmt_info,
1502                        shaper_name,
1503                        cleanup)
1504     colorspaces.extend(lmts)
1505
1506     odts, displays = create_ODTs(aces_ctl_directory,
1507                                  lut_directory,
1508                                  lut_resolution_1d,
1509                                  lut_resolution_3d,
1510                                  odt_info,
1511                                  shaper_name,
1512                                  cleanup,
1513                                  ACES,
1514                                  ACEScc)
1515     colorspaces.extend(odts)
1516
1517     # Wish there was an automatic way to get this from the CTL
1518     defaultDisplay = "sRGB (D60 sim.)"
1519
1520     roles = {'color_picking': ACEScg.name,
1521              'color_timing': ACEScc.name,
1522              'compositing_log': ACEScc.name,
1523              'data': '',
1524              'default': ACES.name,
1525              'matte_paint': ACEScc.name,
1526              'reference': '',
1527              'scene_linear': ACEScg.name,
1528              'texture_paint': ''}
1529
1530     return ACES, colorspaces, displays, ACEScc, roles, defaultDisplay