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