Updated __init__.py to reflect version no. and new LUT defaults
[OpenColorIO-Configs.git] / nuke-default / make.py
1 #!/usr/bin/env python
2
3 """
4 env
5 PYTHONPATH=/net/soft_scratch/users/jeremys/git/ocio.js/build/src/pyglue/
6 LD_LIBRARY_PATH=/net/soft_scratch/users/jeremys/git/ocio.js/build/src/core/
7 """
8
9 import math, os, sys
10 import PyOpenColorIO as OCIO
11
12 print "OCIO",OCIO.version
13
14 outputfilename = "config.ocio"
15
16 def WriteSPI1D(filename, fromMin, fromMax, data):
17     f = file(filename,'w')
18     f.write("Version 1\n")
19     f.write("From %s %s\n" % (fromMin, fromMax))
20     f.write("Length %d\n" % len(data))
21     f.write("Components 1\n")
22     f.write("{\n")
23     for value in data:
24         f.write("        %s\n" % value)
25     f.write("}\n")
26     f.close()
27
28 def Fit(value, fromMin, fromMax, toMin, toMax):
29     if fromMin == fromMax:
30         raise ValueError("fromMin == fromMax")
31     return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin
32
33
34 ###############################################################################
35
36
37 config = OCIO.Config()
38 config.setSearchPath('luts')
39
40 config.setRole(OCIO.Constants.ROLE_SCENE_LINEAR, "linear")
41 config.setRole(OCIO.Constants.ROLE_REFERENCE, "linear")
42 config.setRole(OCIO.Constants.ROLE_COLOR_TIMING, "Cineon")
43 config.setRole(OCIO.Constants.ROLE_COMPOSITING_LOG, "Cineon")
44 config.setRole(OCIO.Constants.ROLE_DATA,"raw")
45 config.setRole(OCIO.Constants.ROLE_DEFAULT,"raw")
46 config.setRole(OCIO.Constants.ROLE_COLOR_PICKING,"sRGB")
47 config.setRole(OCIO.Constants.ROLE_MATTE_PAINT,"sRGB")
48 config.setRole(OCIO.Constants.ROLE_TEXTURE_PAINT,"sRGB")
49
50
51 ###############################################################################
52
53 cs = OCIO.ColorSpace(name='linear')
54 cs.setDescription("Scene-linear, high dynamic range. Used for rendering and compositing.")
55 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
56 cs.setAllocation(OCIO.Constants.ALLOCATION_LG2)
57 cs.setAllocationVars([-15.0, 6.0])
58 config.addColorSpace(cs)
59
60
61 ###############################################################################
62
63 def toSRGB(v):
64     if v<0.04045/12.92:
65         return v*12.92
66     return 1.055 * v**(1.0/2.4) - 0.055
67
68 def fromSRGB(v):
69     if v<0.04045:
70         return v/12.92
71     return ((v + .055) / 1.055) ** 2.4
72
73 # These samples and range have been chosen to write out this colorspace with
74 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
75 # crossings
76
77 NUM_SAMPLES = 2**12+5
78 RANGE = (-0.125, 1.125)
79 data = []
80 for i in xrange(NUM_SAMPLES):
81     x = i/(NUM_SAMPLES-1.0)
82     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
83     data.append(fromSRGB(x))
84
85 # Data is srgb->linear
86 WriteSPI1D('luts/srgb.spi1d', RANGE[0], RANGE[1], data)
87
88 cs = OCIO.ColorSpace(name='sRGB')
89 cs.setDescription("Standard RGB Display Space")
90 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
91 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
92 cs.setAllocationVars([RANGE[0], RANGE[1]])
93
94 t = OCIO.FileTransform('srgb.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
95 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
96 config.addColorSpace(cs)
97
98
99 NUM_SAMPLES = 2**16+25
100 RANGE = (-0.125, 4.875)
101 data = []
102 for i in xrange(NUM_SAMPLES):
103     x = i/(NUM_SAMPLES-1.0)
104     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
105     data.append(fromSRGB(x))
106
107 # Data is srgb->linear
108 WriteSPI1D('luts/srgbf.spi1d', RANGE[0], RANGE[1], data)
109
110 cs = OCIO.ColorSpace(name='sRGBf')
111 cs.setDescription("Standard RGB Display Space, but with additional range to preserve float highlights.")
112 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
113 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
114 cs.setAllocationVars([RANGE[0], RANGE[1]])
115
116 t = OCIO.FileTransform('srgbf.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
117 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
118 config.addColorSpace(cs)
119
120
121 ###############################################################################
122
123 def toRec709(v):
124     if v<0.018:
125         return v*4.5
126     return 1.099 * v**0.45 - 0.099
127
128 def fromRec709(v):
129     if v<0.018*4.5:
130         return v/4.5
131     return ((v + .099) / 1.099) ** (1.0/0.45)
132
133 # These samples and range have been chosen to write out this colorspace with
134 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
135 # crossings
136
137 NUM_SAMPLES = 2**12+5
138 RANGE = (-0.125, 1.125)
139 data = []
140 for i in xrange(NUM_SAMPLES):
141     x = i/(NUM_SAMPLES-1.0)
142     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
143     data.append(fromRec709(x))
144
145 # Data is srgb->linear
146 WriteSPI1D('luts/rec709.spi1d', RANGE[0], RANGE[1], data)
147
148 cs = OCIO.ColorSpace(name='rec709')
149 cs.setDescription("Rec. 709 (Full Range) Display Space")
150 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
151 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
152 cs.setAllocationVars([RANGE[0], RANGE[1]])
153
154 t = OCIO.FileTransform('rec709.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
155 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
156 config.addColorSpace(cs)
157
158
159 ###############################################################################
160
161 cineonBlackOffset = 10.0 ** ((95.0 - 685.0)/300.0)
162
163 def fromCineon(x):
164     return (10.0**((1023.0 * x - 685.0) / 300.0) - cineonBlackOffset) / (1.0 - cineonBlackOffset)
165
166 # These samples and range have been chosen to write out this colorspace with
167 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
168 # crossings
169
170 NUM_SAMPLES = 2**12+5
171 RANGE = (-0.125, 1.125)
172 data = []
173 for i in xrange(NUM_SAMPLES):
174     x = i/(NUM_SAMPLES-1.0)
175     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
176     data.append(fromCineon(x))
177
178 # Data is srgb->linear
179 WriteSPI1D('luts/cineon.spi1d', RANGE[0], RANGE[1], data)
180
181 cs = OCIO.ColorSpace(name='Cineon')
182 cs.setDescription("Cineon (Log Film Scan)")
183 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
184 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
185 cs.setAllocationVars([RANGE[0], RANGE[1]])
186
187 t = OCIO.FileTransform('cineon.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
188 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
189 config.addColorSpace(cs)
190
191
192
193 ###############################################################################
194
195 cs = OCIO.ColorSpace(name='Gamma1.8')
196 cs.setDescription("Emulates a idealized Gamma 1.8 display device.")
197 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
198 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
199 cs.setAllocationVars([0.0, 1.0])
200
201 t = OCIO.ExponentTransform(value=(1.8,1.8,1.8,1.0))
202 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
203 config.addColorSpace(cs)
204
205 cs = OCIO.ColorSpace(name='Gamma2.2')
206 cs.setDescription("Emulates a idealized Gamma 2.2 display device.")
207 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
208 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
209 cs.setAllocationVars([0.0, 1.0])
210
211 t = OCIO.ExponentTransform(value=(2.2,2.2,2.2,1.0))
212 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
213 config.addColorSpace(cs)
214
215
216 ###############################################################################
217
218
219 # Log to Linear light conversions for Panalog
220 # WARNING: these are estimations known to be close enough.
221 # The actual transfer functions are not published
222
223 panalogBlackOffset = 10.0 ** ((64.0 - 681.0) / 444.0)
224
225 def fromPanalog(x):
226     return (10.0**((1023 * x - 681.0) / 444.0) - panalogBlackOffset) / (1.0 - panalogBlackOffset)
227
228 # These samples and range have been chosen to write out this colorspace with
229 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
230 # crossings
231
232 NUM_SAMPLES = 2**12+5
233 RANGE = (-0.125, 1.125)
234 data = []
235 for i in xrange(NUM_SAMPLES):
236     x = i/(NUM_SAMPLES-1.0)
237     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
238     data.append(fromPanalog(x))
239
240 # Data is srgb->linear
241 WriteSPI1D('luts/panalog.spi1d', RANGE[0], RANGE[1], data)
242
243 cs = OCIO.ColorSpace(name='Panalog')
244 cs.setDescription("Sony/Panavision Genesis Log Space")
245 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
246 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
247 cs.setAllocationVars([RANGE[0], RANGE[1]])
248
249 t = OCIO.FileTransform('panalog.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
250 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
251 config.addColorSpace(cs)
252
253
254
255 ###############################################################################
256
257
258
259 redBlackOffset = 10.0 ** ((0.0 - 1023.0) / 511.0)
260
261 def fromREDLog(x):
262     return ((10.0 ** ((1023.0 * x - 1023.0) / 511.0)) - redBlackOffset) / (1.0 - redBlackOffset)
263
264 # These samples and range have been chosen to write out this colorspace with
265 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
266 # crossings
267
268
269 NUM_SAMPLES = 2**12+5
270 RANGE = (-0.125, 1.125)
271 data = []
272 for i in xrange(NUM_SAMPLES):
273     x = i/(NUM_SAMPLES-1.0)
274     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
275     data.append(fromREDLog(x))
276
277 # Data is srgb->linear
278 WriteSPI1D('luts/redlog.spi1d', RANGE[0], RANGE[1], data)
279
280 cs = OCIO.ColorSpace(name='REDLog')
281 cs.setDescription("RED Log Space")
282 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
283 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
284 cs.setAllocationVars([RANGE[0], RANGE[1]])
285
286 t = OCIO.FileTransform('redlog.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
287 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
288 config.addColorSpace(cs)
289
290
291
292 ###############################################################################
293
294 def fromViperLog(x):
295     return 10.0**((1023.0 * x - 1023.0) / 500.0)
296
297 # These samples and range have been chosen to write out this colorspace with
298 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
299 # crossings
300
301
302 NUM_SAMPLES = 2**12+5
303 RANGE = (-0.125, 1.125)
304 data = []
305 for i in xrange(NUM_SAMPLES):
306     x = i/(NUM_SAMPLES-1.0)
307     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
308     data.append(fromViperLog(x))
309
310 # Data is srgb->linear
311 WriteSPI1D('luts/viperlog.spi1d', RANGE[0], RANGE[1], data)
312
313 cs = OCIO.ColorSpace(name='ViperLog')
314 cs.setDescription("Viper Log Space")
315 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
316 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
317 cs.setAllocationVars([RANGE[0], RANGE[1]])
318
319 t = OCIO.FileTransform('viperlog.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
320 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
321 config.addColorSpace(cs)
322
323
324
325 ###############################################################################
326
327
328 alexav3logc_a = 5.555556
329 alexav3logc_b = 0.052272
330 alexav3logc_c = 0.247190
331 alexav3logc_d = 0.385537
332 alexav3logc_e = 5.367655
333 alexav3logc_f = 0.092809
334 alexav3logc_cut = 0.010591
335 alexav3logc_eCutF = alexav3logc_e*alexav3logc_cut + alexav3logc_f
336
337 # This corresponds to EI800 per Arri Doc
338 # http://www.arridigital.com/forum/index.php?topic=6372.0
339 # http://www.arri.com/?eID=registration&file_uid=7775
340 def fromAlexaV3LogC(x):
341     if x > alexav3logc_eCutF:
342         return (10.0 **((x - alexav3logc_d) / alexav3logc_c) - alexav3logc_b) / alexav3logc_a
343     else:
344         return (x - alexav3logc_f) / alexav3logc_e
345
346
347 # These samples and range have been chosen to write out this colorspace with
348 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
349 # crossings
350
351
352 NUM_SAMPLES = 2**12+5
353 RANGE = (-0.125, 1.125)
354 data = []
355 for i in xrange(NUM_SAMPLES):
356     x = i/(NUM_SAMPLES-1.0)
357     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
358     data.append(fromAlexaV3LogC(x))
359
360 # Data is srgb->linear
361 WriteSPI1D('luts/alexalogc.spi1d', RANGE[0], RANGE[1], data)
362
363 cs = OCIO.ColorSpace(name='AlexaV3LogC')
364 cs.setDescription("Alexa Log C")
365 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
366 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
367 cs.setAllocationVars([RANGE[0], RANGE[1]])
368
369 t = OCIO.FileTransform('alexalogc.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
370 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
371 config.addColorSpace(cs)
372
373
374 ###############################################################################
375
376 'PLogLin'
377
378 # Josh Pines style pivoted log/lin conversion
379 minLinValue = 1e-10
380 linReference = 0.18
381 logReference = 445.0
382 negativeGamma = 0.6
383 densityPerCodeValue = 0.002
384 ngOverDpcv = negativeGamma/densityPerCodeValue
385 dpcvOverNg = densityPerCodeValue/negativeGamma
386
387 def fromPLogLin(x):
388     return (10.0**((x*1023.0 - logReference)*dpcvOverNg ) * linReference)
389
390
391 # These samples and range have been chosen to write out this colorspace with
392 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
393 # crossings
394
395 NUM_SAMPLES = 2**12+5
396 RANGE = (-0.125, 1.125)
397 data = []
398 for i in xrange(NUM_SAMPLES):
399     x = i/(NUM_SAMPLES-1.0)
400     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
401     data.append(fromPLogLin(x))
402
403 # Data is srgb->linear
404 WriteSPI1D('luts/ploglin.spi1d', RANGE[0], RANGE[1], data)
405
406 cs = OCIO.ColorSpace(name='PLogLin')
407 cs.setDescription("Josh Pines style pivoted log/lin conversion. 445->0.18")
408 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
409 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
410 cs.setAllocationVars([RANGE[0], RANGE[1]])
411
412 t = OCIO.FileTransform('ploglin.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
413 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
414 config.addColorSpace(cs)
415
416
417 ###############################################################################
418
419 def fromSLog(x):
420     return (10.0 ** (((x - 0.616596 - 0.03) / 0.432699)) - 0.037584)
421
422 # These samples and range have been chosen to write out this colorspace with
423 # a limited over/undershoot range, which also exactly samples the 0.0,1.0
424 # crossings
425
426 NUM_SAMPLES = 2**12+5
427 RANGE = (-0.125, 1.125)
428 data = []
429 for i in xrange(NUM_SAMPLES):
430     x = i/(NUM_SAMPLES-1.0)
431     x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
432     data.append(fromSLog(x))
433
434 # Data is srgb->linear
435 WriteSPI1D('luts/slog.spi1d', RANGE[0], RANGE[1], data)
436
437 cs = OCIO.ColorSpace(name='SLog')
438 cs.setDescription("Sony SLog")
439 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
440 cs.setAllocation(OCIO.Constants.ALLOCATION_UNIFORM)
441 cs.setAllocationVars([RANGE[0], RANGE[1]])
442
443 t = OCIO.FileTransform('slog.spi1d', interpolation=OCIO.Constants.INTERP_LINEAR)
444 cs.setTransform(t, OCIO.Constants.COLORSPACE_DIR_TO_REFERENCE)
445 config.addColorSpace(cs)
446
447
448 ###############################################################################
449
450 'REDSpace'
451
452
453
454 ###############################################################################
455
456 cs = OCIO.ColorSpace(name='raw')
457 cs.setDescription("Raw Data. Used for normals, points, etc.")
458 cs.setBitDepth(OCIO.Constants.BIT_DEPTH_F32)
459 cs.setIsData(True)
460 config.addColorSpace(cs)
461
462
463 ###############################################################################
464
465 display = 'default'
466 config.addDisplay(display, 'None', 'raw')
467 config.addDisplay(display, 'sRGB', 'sRGB')
468 config.addDisplay(display, 'rec709', 'rec709')
469
470 config.setActiveDisplays('default')
471 config.setActiveViews('sRGB')
472
473
474 ###############################################################################
475
476
477
478 try:
479     config.sanityCheck()
480 except Exception,e:
481     print e
482
483 f = file(outputfilename,"w")
484 f.write(config.serialize())
485 f.close()
486 print "Wrote",outputfilename
487
488 # Core/LUT/include/LUT/fnLUTConversions.h
489