Coverage for models/rgb/transfer_functions/common.py: 62%

37 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1""" 

2Common Transfer Functions Utilities 

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

4 

5Define various transfer functions common utilities. 

6""" 

7 

8from __future__ import annotations 

9 

10import typing 

11 

12import numpy as np 

13 

14if typing.TYPE_CHECKING: 

15 from colour.hints import ArrayLike, NDArrayReal 

16 

17from colour.utilities import as_float, as_float_array, as_int, as_int_array 

18 

19__author__ = "Colour Developers" 

20__copyright__ = "Copyright 2013 Colour Developers" 

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

22__maintainer__ = "Colour Developers" 

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

24__status__ = "Production" 

25 

26__all__ = [ 

27 "CV_range", 

28 "legal_to_full", 

29 "full_to_legal", 

30] 

31 

32 

33def CV_range( 

34 bit_depth: int = 10, is_legal: bool = False, is_int: bool = False 

35) -> NDArrayReal: 

36 """ 

37 Return the code value :math:`CV` range for the specified bit-depth, 

38 range legality and representation. 

39 

40 Parameters 

41 ---------- 

42 bit_depth 

43 Bit-depth of the code value :math:`CV` range. 

44 is_legal 

45 Whether the code value :math:`CV` range represents legal code values. 

46 is_int 

47 Whether the code value :math:`CV` range represents int code 

48 values. 

49 

50 Returns 

51 ------- 

52 :class:`numpy.ndarray` 

53 Code value :math:`CV` range. 

54 

55 Examples 

56 -------- 

57 >>> CV_range(8, True, True) 

58 array([ 16, 235]) 

59 >>> CV_range(8, True, False) # doctest: +ELLIPSIS 

60 array([ 0.0627451..., 0.9215686...]) 

61 >>> CV_range(10, False, False) 

62 array([ 0., 1.]) 

63 """ 

64 

65 if is_legal: 

66 ranges = np.array([16, 235]) 

67 ranges *= 2 ** (bit_depth - 8) 

68 else: 

69 ranges = np.array([0, 2**bit_depth - 1]) 

70 

71 if not is_int: 

72 ranges = as_float_array(ranges) / (2**bit_depth - 1) 

73 

74 return ranges 

75 

76 

77def legal_to_full( 

78 CV: ArrayLike, 

79 bit_depth: int = 10, 

80 in_int: bool = False, 

81 out_int: bool = False, 

82) -> NDArrayReal: 

83 """ 

84 Convert the specified code value :math:`CV` or float equivalent of a code 

85 value at a specified bit-depth from *legal range* (studio swing) to 

86 *full range* (full swing). 

87 

88 Parameters 

89 ---------- 

90 CV 

91 Legal range code value :math:`CV` or float equivalent of a code value 

92 at a specified bit-depth. 

93 bit_depth 

94 Bit-depth used for conversion. 

95 in_int 

96 Whether to treat the input value as integer code value or floating 

97 point equivalent of a code value at a specified bit-depth. 

98 out_int 

99 Whether to return value as integer code value or floating point 

100 equivalent of a code value at a specified bit-depth. 

101 

102 Returns 

103 ------- 

104 :class:`numpy.ndarray` 

105 Full range code value :math:`CV` or float equivalent of a code value 

106 at a specified bit-depth. 

107 

108 Examples 

109 -------- 

110 >>> legal_to_full(64 / 1023) 

111 0.0 

112 >>> legal_to_full(940 / 1023) 

113 1.0 

114 >>> legal_to_full(64 / 1023, out_int=True) 

115 0 

116 >>> legal_to_full(940 / 1023, out_int=True) 

117 1023 

118 >>> legal_to_full(64, in_int=True) 

119 0.0 

120 >>> legal_to_full(940, in_int=True) 

121 1.0 

122 >>> legal_to_full(64, in_int=True, out_int=True) 

123 0 

124 >>> legal_to_full(940, in_int=True, out_int=True) 

125 1023 

126 """ 

127 

128 CV = as_float_array(CV) 

129 

130 MV = 2**bit_depth - 1 

131 

132 CV_full = as_int_array(np.round(CV)) if in_int else CV * MV 

133 

134 B, W = CV_range(bit_depth, True, True) 

135 

136 CV_full = (CV_full - B) / (W - B) 

137 

138 if out_int: 

139 return as_int(np.round(CV_full * MV)) 

140 

141 return as_float(CV_full) 

142 

143 

144def full_to_legal( 

145 CV: ArrayLike, 

146 bit_depth: int = 10, 

147 in_int: bool = False, 

148 out_int: bool = False, 

149) -> NDArrayReal: 

150 """ 

151 Convert the specified code value :math:`CV` or float equivalent of a 

152 code value at a specified bit-depth from full range (full swing) to 

153 legal range (studio swing). 

154 

155 Parameters 

156 ---------- 

157 CV 

158 Full range code value :math:`CV` or float equivalent of a code value 

159 at a specified bit-depth. 

160 bit_depth 

161 Bit-depth used for conversion. 

162 in_int 

163 Whether to treat the input value as integer code value or floating 

164 point equivalent of a code value at a specified bit-depth. 

165 out_int 

166 Whether to return value as integer code value or floating point 

167 equivalent of a code value at a specified bit-depth. 

168 

169 Returns 

170 ------- 

171 :class:`numpy.ndarray` 

172 Legal range code value :math:`CV` or float equivalent of a code value 

173 at a specified bit-depth. 

174 

175 Examples 

176 -------- 

177 >>> full_to_legal(0.0) # doctest: +ELLIPSIS 

178 0.0625610... 

179 >>> full_to_legal(1.0) # doctest: +ELLIPSIS 

180 0.9188660... 

181 >>> full_to_legal(0.0, out_int=True) 

182 64 

183 >>> full_to_legal(1.0, out_int=True) 

184 940 

185 >>> full_to_legal(0, in_int=True) # doctest: +ELLIPSIS 

186 0.0625610... 

187 >>> full_to_legal(1023, in_int=True) # doctest: +ELLIPSIS 

188 0.9188660... 

189 >>> full_to_legal(0, in_int=True, out_int=True) 

190 64 

191 >>> full_to_legal(1023, in_int=True, out_int=True) 

192 940 

193 """ 

194 

195 CV = as_float_array(CV) 

196 

197 MV = 2**bit_depth - 1 

198 

199 CV_legal = as_int_array(np.round(CV / MV)) if in_int else CV 

200 

201 B, W = CV_range(bit_depth, True, True) 

202 

203 CV_legal = (W - B) * CV_legal + B 

204 

205 if out_int: 

206 return as_int(np.round(CV_legal)) 

207 

208 return as_float(CV_legal / MV)