Coverage for notation/hexadecimal.py: 52%

1"""

2 Hexadecimal Notation

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

4

5 Define objects for converting between RGB colour values and hexadecimal

6 notation.

7

8- :func:`colour.notation.RGB_to_HEX`

9- :func:`colour.notation.HEX_to_RGB`

10"""

11

12 from __future__ import annotations

13

14 import typing

15

16 import numpy as np

17

18 from colour.algebra import normalise_maximum

19

20 if typing.TYPE_CHECKING:

21 from colour.hints import NDArrayStr

22

23 from colour.hints import ( # noqa: TC001

24 ArrayLike,

25 Domain1,

26 Range1,

27)

28 from colour.models import eotf_inverse_sRGB, eotf_sRGB

29 from colour.utilities import (

30 as_float_array,

31 as_int_array,

32 from_range_1,

33 to_domain_1,

34 usage_warning,

35)

36

37 __author__ = "Colour Developers"

38 __copyright__ = "Copyright 2013 Colour Developers"

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

40 __maintainer__ = "Colour Developers"

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

42 __status__ = "Production"

43

44 __all__ = [

45 "RGB_to_HEX",

46 "HEX_to_RGB",

47]

48

49

50 def RGB_to_HEX(RGB: Domain1) -> NDArrayStr:

51 """

52 Convert from *RGB* colourspace to hexadecimal representation.

53

54 Parameters

55 ----------

56 RGB

57 *RGB* colourspace array with values typically normalised to [0, 1].

58

59 Returns

60 -------

61 :class:`str` or :class:`numpy.array`

62 Hexadecimal representation as a string in the format '#RRGGBB'.

63

64 Notes

65 -----

66 +------------+-----------------------+---------------+

67 | **Domain** | **Scale - Reference** | **Scale - 1** |

68 +============+=======================+===============+

69 | ``RGB`` | 1 | 1 |

70 +------------+-----------------------+---------------+

71

72 Examples

73 --------

74 >>> RGB = np.array([0.66666667, 0.86666667, 1.00000000])

75 >>> RGB_to_HEX(RGB)

76 '#aaddff'

77 """

78

79 RGB = to_domain_1(RGB)

80

81 if np.any(RGB < 0):

82 usage_warning(

83 '"RGB" array contains negative values, those will be clipped, '

84 "unpredictable results may occur!"

85 )

86

87 RGB = as_float_array(np.clip(RGB, 0, np.inf))

88

89 if np.any(RGB > 1):

90 usage_warning(

91 '"RGB" array contains values over 1 and will be normalised, '

92 "unpredictable results may occur!"

93 )

94

95 RGB = eotf_inverse_sRGB(normalise_maximum(eotf_sRGB(RGB)))

96

97 to_HEX = np.vectorize("{:02x}".format)

98

99 HEX = to_HEX(as_int_array(RGB * 255, dtype=np.uint8)).astype(object)

100

101 return np.asarray("#") + HEX[..., 0] + HEX[..., 1] + HEX[..., 2]

102

103

104 def HEX_to_RGB(HEX: ArrayLike) -> Range1:

105 """

106 Convert from hexadecimal representation to *RGB* colourspace.

107

108 Parameters

109 ----------

110 HEX

111 Hexadecimal representation as a string in the format '#RRGGBB'.

112

113 Returns

114 -------

115 :class:`numpy.array`

116 *RGB* colourspace array with values typically normalised to [0, 1].

117

118 Notes

119 -----

120 +-----------+-----------------------+---------------+

121 | **Range** | **Scale - Reference** | **Scale - 1** |

122 +===========+=======================+===============+

123 | ``RGB`` | 1 | 1 |

124 +-----------+-----------------------+---------------+

125

126 Examples

127 --------

128 >>> HEX = "#aaddff"

129 >>> HEX_to_RGB(HEX) # doctest: +ELLIPSIS

130 array([ 0.6666666..., 0.8666666..., 1. ])

131 """

132

133 HEX = np.char.lstrip(HEX, "#") # pyright: ignore

134

135 def to_RGB(x: list) -> list:

136 """Convert specified hexadecimal representation to *RGB*."""

137

138 l_x = len(x)

139

140 return [

141 int(x[i : i + l_x // 3], 16) # pyright: ignore

142 for i in range(0, l_x, l_x // 3)

143 ]

144

145 to_RGB_v = np.vectorize(to_RGB, otypes=[np.ndarray])

146

147 RGB = as_float_array(to_RGB_v(HEX).tolist()) / 255

148

149 return from_range_1(RGB)