1#ifndef MSTL_CORE_UTILITY_COLOR_HPP__
2#define MSTL_CORE_UTILITY_COLOR_HPP__
3#include "hexadecimal.hpp"
7class color :
public iobject<color>,
public icommon<color> {
9 int r = 0, g = 0, b = 0, a = 255;
11 static constexpr int clamp(
const int value)
noexcept {
12 if (value < 0)
return 0;
13 if (value > 255)
return 255;
17 static constexpr double clamp_double(
const double value)
noexcept {
18 if (value < 0.0)
return 0.0;
19 if (value > 1.0)
return 1.0;
23 static constexpr int lerp_component(
const int from,
const int to,
const double t)
noexcept {
24 const double result = from + (to - from) * clamp_double(t);
29 constexpr color() noexcept = default;
31 explicit constexpr color(const
int gray) noexcept
34 constexpr color(
const int gray,
const int alpha) noexcept
37 constexpr color(
const int red,
const int green,
const int blue) noexcept
40 constexpr color(
const int red,
const int green,
const int blue,
const int alpha) noexcept
43 MSTL_CONSTEXPR20
explicit color(
const string_view str) { try_parse(str); }
44 MSTL_CONSTEXPR20
explicit color(
const string& str) { try_parse(str.view()); }
45 MSTL_CONSTEXPR20
explicit color(
const char* str) { try_parse(str); }
47 constexpr color(
const color& other)
noexcept =
default;
48 constexpr color& operator =(
const color& other)
noexcept =
default;
49 constexpr color(color&& other) noexcept : r(other.r), g(other.g), b(other.b), a(other.a) {
55 constexpr color& operator =(color&& other)
noexcept {
61 MSTL_CONSTEXPR20 ~color() =
default;
63 constexpr int R() const noexcept {
return r; }
64 constexpr int G() const noexcept {
return g; }
65 constexpr int B() const noexcept {
return b; }
66 constexpr int A() const noexcept {
return a; }
68 constexpr void setR(
const int red)
noexcept { r =
clamp(red); }
69 constexpr void setG(
const int green)
noexcept { g =
clamp(green); }
70 constexpr void setB(
const int blue)
noexcept { b =
clamp(blue); }
71 constexpr void setA(
const int alpha)
noexcept { a =
clamp(alpha); }
73 constexpr void set_color(
const int red,
const int green,
const int blue)
noexcept {
79 constexpr void set_color(
const int red,
const int green,
const int blue,
const int alpha)
noexcept {
86 constexpr void set_gray(
const int gray)
noexcept {
87 r = g = b =
clamp(gray);
90 constexpr void set_gray(
const int gray,
const int alpha)
noexcept {
95 constexpr bool is_transparent() const noexcept {
return a == 0; }
96 constexpr bool is_opaque() const noexcept {
return a == 255; }
98 constexpr double opacity() const noexcept {
return a / 255.0; }
100 constexpr void set_opacity(
double opacity)
noexcept {
101 if (opacity < 0.0) opacity = 0.0;
102 if (opacity > 1.0) opacity = 1.0;
103 a =
static_cast<int>(
_MSTL round(opacity * 255));
106 static constexpr color lerp(
const color& from,
const color& to,
double t)
noexcept {
109 lerp_component(from.r, to.r, t),
110 lerp_component(from.g, to.g, t),
111 lerp_component(from.b, to.b, t),
112 lerp_component(from.a, to.a, t)
116 constexpr color
operator +(
const color& other)
const noexcept {
117 return color(r + other.r, g + other.g, b + other.b, a + other.a);
120 constexpr color
operator -(
const color& other)
const noexcept {
121 return color(r - other.r, g - other.g, b - other.b, a - other.a);
124 constexpr color
operator *(
const double scalar)
const noexcept {
133 constexpr color
operator *(
const int scalar)
const noexcept {
134 return {r * scalar, g * scalar, b * scalar, a * scalar};
137 constexpr color& operator +=(
const color& other)
noexcept {
138 r =
clamp(r + other.r);
139 g =
clamp(g + other.g);
140 b =
clamp(b + other.b);
141 a =
clamp(a + other.a);
145 constexpr color& operator -=(
const color& other)
noexcept {
146 r =
clamp(r - other.r);
147 g =
clamp(g - other.g);
148 b =
clamp(b - other.b);
149 a =
clamp(a - other.a);
153 constexpr color& operator *=(
const double scalar)
noexcept {
161 constexpr bool operator ==(
const color& other)
const noexcept {
162 return r == other.r && g == other.g && b == other.b && a == other.a;
165 constexpr bool operator <(
const color& other)
const noexcept {
166 if (r != other.r)
return r < other.r;
167 if (g != other.g)
return g < other.g;
168 if (b != other.b)
return b < other.b;
172 MSTL_NODISCARD
constexpr color blend(
const color& background)
const noexcept {
173 if (a == 255)
return *
this;
174 if (a == 0)
return background;
176 const double alpha = a / 255.0;
177 const double inv_alpha = 1.0 - alpha;
179 const int newR =
static_cast<int>(
_MSTL round(r * alpha + background.r * inv_alpha));
180 const int newG =
static_cast<int>(
_MSTL round(g * alpha + background.g * inv_alpha));
181 const int newB =
static_cast<int>(
_MSTL round(b * alpha + background.b * inv_alpha));
182 return color(newR, newG, newB, 255);
185 MSTL_NODISCARD
constexpr color premultiply_alpha() const noexcept {
186 const double alpha = a / 255.0;
195 MSTL_NODISCARD
constexpr double gray_value() const noexcept {
196 return 0.299 * r + 0.587 * g + 0.114 * b;
199 MSTL_NODISCARD MSTL_CONSTEXPR20
string to_string()
const {
200 return _MSTL format(
"{02X}{02X}{02X}{02X}", r, g, b, a);
203 static MSTL_CONSTEXPR20 color parse(
const string_view hex) {
204 string_view clean_hex = hex;
205 if (clean_hex[0] ==
'#') clean_hex = clean_hex.substr(1);
207 if (clean_hex.length() == 6) {
208 const int r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
209 const int g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
210 const int b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
212 }
else if (clean_hex.length() == 8) {
213 const int r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
214 const int g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
215 const int b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
216 const int a = hexadecimal::parse(clean_hex.substr(6, 2)).value();
219 throw_exception(value_exception(
"Invalid hex string"));
224 MSTL_NODISCARD
constexpr int to_ansi_256() const noexcept {
225 if (r < 8 && g < 8 && b < 8)
return 16;
226 if (r > 248 && g > 248 && b > 248)
return 231;
228 if (r == g && g == b) {
229 const int gray_index =
static_cast<int>((r - 8) / 247.0 * 24.0 + 0.5);
230 return 232 + gray_index;
233 const int r_idx =
static_cast<int>((r / 255.0) * 5.0 + 0.5);
234 const int g_idx =
static_cast<int>((g / 255.0) * 5.0 + 0.5);
235 const int b_idx =
static_cast<int>((b / 255.0) * 5.0 + 0.5);
237 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
240 MSTL_NODISCARD
constexpr int to_ansi_basic(
const bool is_background =
false) const noexcept {
241 const int base = is_background ? 40 : 30;
243 if (r > g && r > b) {
244 if (g > 128 && b > 128)
return base + 7;
246 }
else if (g > r && g > b) {
247 if (r > 128 && b > 128)
return base + 7;
249 }
else if (b > r && b > g) {
250 if (r > 128 && g > 128)
return base + 7;
252 }
else if (r == g && g == b) {
253 if (r < 64)
return base + 0;
254 if (r < 192)
return base + 7;
256 }
else if (r == g && r > b) {
258 }
else if (r == b && r > g) {
260 }
else if (g == b && g > r) {
267 MSTL_NODISCARD
constexpr integer32 to_ansi_foreground(
const bool use_256_color =
true) const noexcept {
269 return {38 * 100 + 5 * 10 + to_ansi_256()};
271 return {to_ansi_basic(
false)};
274 MSTL_NODISCARD
constexpr integer32 to_ansi_background(
const bool use_256_color =
true) const noexcept {
276 return {48 * 100 + 5 * 10 + to_ansi_256()};
278 return {to_ansi_basic(
true)};
281 MSTL_NODISCARD
constexpr integer32 to_integer32(
const bool use_256_color =
true) const noexcept {
283 return {to_ansi_256()};
285 return {to_ansi_basic(
false)};
288 MSTL_NODISCARD
constexpr size_t to_hash() const noexcept {
289 constexpr hash<int> hasher;
290 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
293 constexpr void swap(color& other)
noexcept {
299 static constexpr color black() noexcept {
return color(0, 0, 0, 255); }
300 static constexpr color white() noexcept {
return color(255, 255, 255, 255); }
301 static constexpr color red() noexcept {
return color(255, 0, 0, 255); }
302 static constexpr color green() noexcept {
return color(0, 255, 0, 255); }
303 static constexpr color blue() noexcept {
return color(0, 0, 255, 255); }
304 static constexpr color yellow() noexcept {
return color(255, 255, 0, 255); }
305 static constexpr color magenta() noexcept {
return color(255, 0, 255, 255); }
306 static constexpr color cyan() noexcept {
return color(0, 255, 255, 255); }
307 static constexpr color transparent() noexcept {
return color(0, 0, 0, 0); }
310constexpr color
operator *(
const double scalar,
const color& color)
noexcept {
311 return color * scalar;
313constexpr color
operator *(
const int scalar,
const color& color)
noexcept {
314 return color * scalar;
MSTL_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr const T & clamp(const T &value, const T &lower, const T &upper, Compare comp) noexcept(noexcept(comp(value, lower)))
将值限制在指定范围内
constexpr duration< _INNER __common_rep_t< Rep1, Rep2 >, Period > operator*(const duration< Rep1, Period > &value, const Rep2 &scalar)
乘法运算符(持续时间 * 标量)
bool operator==(const function< Res(Args...)> &f, nullptr_t null) noexcept
等于空指针比较
MSTL_CONST_FUNCTION MSTL_CONSTEXPR14 decimal_t round(const decimal_t x) noexcept
四舍五入
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
MSTL_NODISCARD constexpr normal_iterator< Iterator > operator+(iter_difference_t< normal_iterator< Iterator > > n, const normal_iterator< Iterator > &iter) noexcept
加法运算符
MSTL_NODISCARD constexpr auto operator-(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept -> decltype(lhs.base() - rhs.base())
减法运算符
MSTL_NODISCARD constexpr bool operator<(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept
小于比较运算符
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result)
移动范围元素
void swap()=delete
删除无参数的swap重载