Coverage for colour/models/rgb/transfer_functions/gamma.py: 100%

23 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-15 19:01 +1300

1""" 

2Gamma Colour Component Transfer Function 

3======================================== 

4 

5Define the gamma encoding / decoding colour component transfer function 

6related objects. 

7 

8- :func:`colour.gamma_function` 

9""" 

10 

11from __future__ import annotations 

12 

13import typing 

14 

15import numpy as np 

16 

17from colour.algebra import spow 

18 

19if typing.TYPE_CHECKING: 

20 from colour.hints import ArrayLike, Literal, NDArrayFloat 

21 

22from colour.utilities import as_float, as_float_array, validate_method 

23 

24__author__ = "Colour Developers" 

25__copyright__ = "Copyright 2013 Colour Developers" 

26__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" 

27__maintainer__ = "Colour Developers" 

28__email__ = "colour-developers@colour-science.org" 

29__status__ = "Production" 

30 

31__all__ = [ 

32 "gamma_function", 

33] 

34 

35 

36def gamma_function( 

37 a: ArrayLike, 

38 exponent: ArrayLike = 1, 

39 negative_number_handling: ( 

40 Literal["Clamp", "Indeterminate", "Mirror", "Preserve"] | str 

41 ) = "Indeterminate", 

42) -> NDArrayFloat: 

43 """ 

44 Apply a gamma encoding or decoding transformation to the specified array. 

45 

46 Parameters 

47 ---------- 

48 a 

49 Array to encode or decode. 

50 exponent 

51 Encoding or decoding exponent. 

52 negative_number_handling 

53 Behaviour for ``a`` negative numbers and the definition return 

54 value: 

55 

56 - *Indeterminate*: The behaviour will be indeterminate and the 

57 definition return value might contain *nans*. 

58 - *Mirror*: The definition return value will be mirrored around 

59 the abscissa and ordinate axes, i.e., Blackmagic Design: 

60 Davinci Resolve behaviour. 

61 - *Preserve*: The definition will preserve any negative number 

62 in ``a``, i.e., The Foundry Nuke behaviour. 

63 - *Clamp*: The definition will clamp any negative number in 

64 ``a`` to 0. 

65 

66 Returns 

67 ------- 

68 :class:`numpy.ndarray` 

69 Encoded or decoded array. 

70 

71 Examples 

72 -------- 

73 >>> gamma_function(0.18, 2.2) # doctest: +ELLIPSIS 

74 0.0229932... 

75 >>> gamma_function(-0.18, 2.0) # doctest: +ELLIPSIS 

76 0.0323999... 

77 >>> gamma_function(-0.18, 2.2) 

78 nan 

79 >>> gamma_function(-0.18, 2.2, "Mirror") # doctest: +ELLIPSIS 

80 -0.0229932... 

81 >>> gamma_function(-0.18, 2.2, "Preserve") # doctest: +ELLIPSIS 

82 -0.1... 

83 >>> gamma_function(-0.18, 2.2, "Clamp") # doctest: +ELLIPSIS 

84 0.0 

85 """ 

86 

87 a = as_float_array(a) 

88 exponent = as_float_array(exponent) 

89 negative_number_handling = validate_method( 

90 negative_number_handling, 

91 ("Indeterminate", "Mirror", "Preserve", "Clamp"), 

92 '"{0}" negative number handling is invalid, it must be one of {1}!', 

93 ) 

94 

95 if negative_number_handling == "indeterminate": 

96 return as_float(a**exponent) 

97 

98 if negative_number_handling == "mirror": 

99 return spow(a, exponent) 

100 

101 if negative_number_handling == "preserve": 

102 return as_float(np.where(a <= 0, a, a**exponent)) 

103 

104 # negative_number_handling == 'clamp': 

105 return as_float(np.where(a <= 0, 0, a**exponent))