Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/webcolors/_conversion.py: 42%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

36 statements  

1""" 

2Functions which convert between various types of color values. 

3 

4""" 

5 

6# SPDX-License-Identifier: BSD-3-Clause 

7 

8from ._definitions import CSS3, _get_hex_to_name_map, _get_name_to_hex_map 

9from ._normalization import ( 

10 _percent_to_integer, 

11 normalize_hex, 

12 normalize_integer_triplet, 

13 normalize_percent_triplet, 

14) 

15from ._types import IntegerRGB, IntTuple, PercentRGB, PercentTuple 

16 

17# Conversions from color names to other formats. 

18# -------------------------------------------------------------------------------- 

19 

20 

21def name_to_hex(name: str, spec: str = CSS3) -> str: 

22 """ 

23 Convert a color name to a normalized hexadecimal color value. 

24 

25 The color name will be normalized to lower-case before being looked up. 

26 

27 Examples: 

28 

29 .. doctest:: 

30 

31 >>> name_to_hex("white") 

32 '#ffffff' 

33 >>> name_to_hex("navy") 

34 '#000080' 

35 >>> name_to_hex("goldenrod") 

36 '#daa520' 

37 >>> name_to_hex("goldenrod", spec=HTML4) 

38 Traceback (most recent call last): 

39 ... 

40 ValueError: "goldenrod" is not defined as a named color in html4. 

41 

42 :param name: The color name to convert. 

43 :param spec: The specification from which to draw the list of color names. Default 

44 is :data:`CSS3`. 

45 :raises ValueError: when the given name has no definition in the given spec. 

46 

47 """ 

48 color_map = _get_name_to_hex_map(spec) 

49 if hex_value := color_map.get(name.lower()): 

50 return hex_value 

51 raise ValueError(f'"{name}" is not defined as a named color in {spec}') 

52 

53 

54def name_to_rgb(name: str, spec: str = CSS3) -> IntegerRGB: 

55 """ 

56 Convert a color name to a 3-:class:`tuple` of :class:`int` suitable for use in 

57 an ``rgb()`` triplet specifying that color. 

58 

59 The color name will be normalized to lower-case before being looked up. 

60 

61 Examples: 

62 

63 .. doctest:: 

64 

65 >>> name_to_rgb("white") 

66 IntegerRGB(red=255, green=255, blue=255) 

67 >>> name_to_rgb("navy") 

68 IntegerRGB(red=0, green=0, blue=128) 

69 >>> name_to_rgb("goldenrod") 

70 IntegerRGB(red=218, green=165, blue=32) 

71 

72 :param name: The color name to convert. 

73 :param spec: The specification from which to draw the list of color names. Default 

74 is :data:`CSS3.` 

75 :raises ValueError: when the given name has no definition in the given spec. 

76 

77 """ 

78 return hex_to_rgb(name_to_hex(name, spec=spec)) 

79 

80 

81def name_to_rgb_percent(name: str, spec: str = CSS3) -> PercentRGB: 

82 """ 

83 Convert a color name to a 3-:class:`tuple` of percentages suitable for use in an 

84 ``rgb()`` triplet specifying that color. 

85 

86 The color name will be normalized to lower-case before being looked up. 

87 

88 Examples: 

89 

90 .. doctest:: 

91 

92 >>> name_to_rgb_percent("white") 

93 PercentRGB(red='100%', green='100%', blue='100%') 

94 >>> name_to_rgb_percent("navy") 

95 PercentRGB(red='0%', green='0%', blue='50%') 

96 >>> name_to_rgb_percent("goldenrod") 

97 PercentRGB(red='85.49%', green='64.71%', blue='12.5%') 

98 

99 :param name: The color name to convert. 

100 :param spec: The specification from which to draw the list of color names. Default 

101 is :data:`CSS3`. 

102 :raises ValueError: when the given name has no definition in the given spec. 

103 

104 """ 

105 return rgb_to_rgb_percent(name_to_rgb(name, spec=spec)) 

106 

107 

108# Conversions from hexadecimal color values to other formats. 

109# -------------------------------------------------------------------------------- 

110 

111 

112def hex_to_name(hex_value: str, spec: str = CSS3) -> str: 

113 """ 

114 Convert a hexadecimal color value to its corresponding normalized color name, if 

115 any such name exists. 

116 

117 The hexadecimal value will be normalized before being looked up. 

118 

119 .. note:: **Spelling variants** 

120 

121 Some values representing named gray colors can map to either of two names in 

122 CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for 

123 those colors. This function will always return the variant spelled ``"gray"`` 

124 (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation 

125 on name conventions <color-name-conventions>` for details. 

126 

127 Examples: 

128 

129 .. doctest:: 

130 

131 >>> hex_to_name("#ffffff") 

132 'white' 

133 >>> hex_to_name("#fff") 

134 'white' 

135 >>> hex_to_name("#000080") 

136 'navy' 

137 >>> hex_to_name("#daa520") 

138 'goldenrod' 

139 >>> hex_to_name("#daa520", spec=HTML4) 

140 Traceback (most recent call last): 

141 ... 

142 ValueError: "#daa520" has no defined color name in html4. 

143 

144 :param hex_value: The hexadecimal color value to convert. 

145 :param spec: The specification from which to draw the list of color names. Default 

146 is :data:`CSS3`. 

147 :raises ValueError: when the given color has no name in the given spec, or when the 

148 supplied hex value is invalid. 

149 

150 """ 

151 color_map = _get_hex_to_name_map(spec) 

152 if name := color_map.get(normalize_hex(hex_value)): 

153 return name 

154 raise ValueError(f'"{hex_value}" has no defined color name in {spec}.') 

155 

156 

157def hex_to_rgb(hex_value: str) -> IntegerRGB: 

158 """ 

159 Convert a hexadecimal color value to a 3-:class:`tuple` of :class:`int` suitable 

160 for use in an ``rgb()`` triplet specifying that color. 

161 

162 The hexadecimal value will be normalized before being converted. 

163 

164 Examples: 

165 

166 .. doctest:: 

167 

168 >>> hex_to_rgb("#fff") 

169 IntegerRGB(red=255, green=255, blue=255) 

170 >>> hex_to_rgb("#000080") 

171 IntegerRGB(red=0, green=0, blue=128) 

172 

173 :param hex_value: The hexadecimal color value to convert. 

174 :raises ValueError: when the supplied hex value is invalid. 

175 

176 """ 

177 int_value = int(normalize_hex(hex_value)[1:], 16) 

178 return IntegerRGB(int_value >> 16, int_value >> 8 & 0xFF, int_value & 0xFF) 

179 

180 

181def hex_to_rgb_percent(hex_value: str) -> PercentRGB: 

182 """ 

183 Convert a hexadecimal color value to a 3-:class:`tuple` of percentages suitable 

184 for use in an ``rgb()`` triplet representing that color. 

185 

186 The hexadecimal value will be normalized before being converted. 

187 

188 Examples: 

189 

190 .. doctest:: 

191 

192 >>> hex_to_rgb_percent("#ffffff") 

193 PercentRGB(red='100%', green='100%', blue='100%') 

194 >>> hex_to_rgb_percent("#000080") 

195 PercentRGB(red='0%', green='0%', blue='50%') 

196 

197 :param hex_value: The hexadecimal color value to convert. 

198 :raises ValueError: when the supplied hex value is invalid. 

199 

200 """ 

201 return rgb_to_rgb_percent(hex_to_rgb(hex_value)) 

202 

203 

204# Conversions from integer rgb() triplets to other formats. 

205# -------------------------------------------------------------------------------- 

206 

207 

208def rgb_to_name(rgb_triplet: IntTuple, spec: str = CSS3) -> str: 

209 """ 

210 Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` 

211 color triplet, to its corresponding normalized color name, if any such name exists. 

212 

213 To determine the name, the triplet will be converted to a normalized hexadecimal 

214 value. 

215 

216 .. note:: **Spelling variants** 

217 

218 Some values representing named gray colors can map to either of two names in 

219 CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for 

220 those colors. This function will always return the variant spelled ``"gray"`` 

221 (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation 

222 on name conventions <color-name-conventions>` for details. 

223 

224 Examples: 

225 

226 .. doctest:: 

227 

228 >>> rgb_to_name((255, 255, 255)) 

229 'white' 

230 >>> rgb_to_name((0, 0, 128)) 

231 'navy' 

232 

233 :param rgb_triplet: The ``rgb()`` triplet. 

234 :param spec: The specification from which to draw the list of color names. Default 

235 is :data:`CSS3`. 

236 :raises ValueError: when the given color has no name in the given spec. 

237 

238 """ 

239 return hex_to_name(rgb_to_hex(normalize_integer_triplet(rgb_triplet)), spec=spec) 

240 

241 

242def rgb_to_hex(rgb_triplet: IntTuple) -> str: 

243 """ 

244 Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` 

245 color triplet, to a normalized hexadecimal value for that color. 

246 

247 Examples: 

248 

249 .. doctest:: 

250 

251 >>> rgb_to_hex((255, 255, 255)) 

252 '#ffffff' 

253 >>> rgb_to_hex((0, 0, 128)) 

254 '#000080' 

255 

256 :param rgb_triplet: The ``rgb()`` triplet. 

257 

258 """ 

259 red, green, blue = normalize_integer_triplet(rgb_triplet) 

260 return f"#{red:02x}{green:02x}{blue:02x}" 

261 

262 

263def rgb_to_rgb_percent(rgb_triplet: IntTuple) -> PercentRGB: 

264 """ 

265 Convert a 3-:class:`tuple` of :class:`int`, suitable for use in an ``rgb()`` 

266 color triplet, to a 3-:class:`tuple` of percentages suitable for use in representing 

267 that color. 

268 

269 .. note:: **Floating-point precision** 

270 

271 This function makes some trade-offs in terms of the accuracy of the final 

272 representation. For some common integer values, special-case logic is used to 

273 ensure a precise result (e.g., integer 128 will always convert to ``"50%"``, 

274 integer 32 will always convert to ``"12.5%"``), but for all other values a 

275 standard Python :class:`float` is used and rounded to two decimal places, which 

276 may result in a loss of precision for some values due to the inherent imprecision 

277 of `IEEE floating-point numbers <https://en.wikipedia.org/wiki/IEEE_754>`_. 

278 

279 Examples: 

280 

281 .. doctest:: 

282 

283 >>> rgb_to_rgb_percent((255, 255, 255)) 

284 PercentRGB(red='100%', green='100%', blue='100%') 

285 >>> rgb_to_rgb_percent((0, 0, 128)) 

286 PercentRGB(red='0%', green='0%', blue='50%') 

287 >>> rgb_to_rgb_percent((218, 165, 32)) 

288 PercentRGB(red='85.49%', green='64.71%', blue='12.5%') 

289 

290 :param rgb_triplet: The ``rgb()`` triplet. 

291 

292 """ 

293 # In order to maintain precision for common values, 

294 # special-case them. 

295 specials = { 

296 255: "100%", 

297 128: "50%", 

298 64: "25%", 

299 32: "12.5%", 

300 16: "6.25%", 

301 0: "0%", 

302 } 

303 return PercentRGB._make( 

304 specials.get(d, f"{d / 255.0 * 100:.02f}%") 

305 for d in normalize_integer_triplet(rgb_triplet) 

306 ) 

307 

308 

309# Conversions from percentage rgb() triplets to other formats. 

310# -------------------------------------------------------------------------------- 

311 

312 

313def rgb_percent_to_name(rgb_percent_triplet: PercentTuple, spec: str = CSS3) -> str: 

314 """ 

315 Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` 

316 color triplet, to its corresponding normalized color name, if any such name exists. 

317 

318 To determine the name, the triplet will be converted to a normalized hexadecimal 

319 value. 

320 

321 .. note:: **Spelling variants** 

322 

323 Some values representing named gray colors can map to either of two names in 

324 CSS3, because it supports both ``"gray"`` and ``"grey"`` spelling variants for 

325 those colors. This function will always return the variant spelled ``"gray"`` 

326 (such as ``"lightgray"`` instead of ``"lightgrey"``). See :ref:`the documentation 

327 on name conventions <color-name-conventions>` for details. 

328 

329 Examples: 

330 

331 .. doctest:: 

332 

333 >>> rgb_percent_to_name(("100%", "100%", "100%")) 

334 'white' 

335 >>> rgb_percent_to_name(("0%", "0%", "50%")) 

336 'navy' 

337 >>> rgb_percent_to_name(("85.49%", "64.71%", "12.5%")) 

338 'goldenrod' 

339 

340 :param rgb_percent_triplet: The ``rgb()`` triplet. 

341 :param spec: The specification from which to draw the list of color names. Default 

342 is :data:`CSS3`. 

343 :raises ValueError: when the given color has no name in the given spec. 

344 

345 """ 

346 return rgb_to_name( 

347 rgb_percent_to_rgb(normalize_percent_triplet(rgb_percent_triplet)), 

348 spec=spec, 

349 ) 

350 

351 

352def rgb_percent_to_hex(rgb_percent_triplet: PercentTuple) -> str: 

353 """ 

354 Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` 

355 color triplet, to a normalized hexadecimal color value for that color. 

356 

357 Examples: 

358 

359 .. doctest:: 

360 

361 >>> rgb_percent_to_hex(("100%", "100%", "0%")) 

362 '#ffff00' 

363 >>> rgb_percent_to_hex(("0%", "0%", "50%")) 

364 '#000080' 

365 >>> rgb_percent_to_hex(("85.49%", "64.71%", "12.5%")) 

366 '#daa520' 

367 

368 :param rgb_percent_triplet: The ``rgb()`` triplet. 

369 

370 """ 

371 return rgb_to_hex( 

372 rgb_percent_to_rgb(normalize_percent_triplet(rgb_percent_triplet)) 

373 ) 

374 

375 

376def rgb_percent_to_rgb(rgb_percent_triplet: PercentTuple) -> IntegerRGB: 

377 """ 

378 Convert a 3-:class:`tuple` of percentages, suitable for use in an ``rgb()`` 

379 color triplet, to a 3-:class:`tuple` of :class:`int` suitable for use in 

380 representing that color. 

381 

382 Some precision may be lost in this conversion. See the note regarding precision for 

383 :func:`~webcolors.rgb_to_rgb_percent` for details. 

384 

385 Examples: 

386 

387 .. doctest:: 

388 

389 >>> rgb_percent_to_rgb(("100%", "100%", "100%")) 

390 IntegerRGB(red=255, green=255, blue=255) 

391 >>> rgb_percent_to_rgb(("0%", "0%", "50%")) 

392 IntegerRGB(red=0, green=0, blue=128) 

393 >>> rgb_percent_to_rgb(("85.49%", "64.71%", "12.5%")) 

394 IntegerRGB(red=218, green=165, blue=32) 

395 

396 :param rgb_percent_triplet: The ``rgb()`` triplet. 

397 

398 """ 

399 return IntegerRGB._make( 

400 map( 

401 _percent_to_integer, # pylint: disable=protected-access 

402 normalize_percent_triplet(rgb_percent_triplet), 

403 ) 

404 )