NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
color.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_UTILITY_COLOR_HPP__
2#define NEFORCE_CORE_UTILITY_COLOR_HPP__
3
11
14NEFORCE_BEGIN_NAMESPACE__
15
155
164class color : public iobject<color>, public icommon<color> {
165private:
166 int r = 0;
167 int g = 0;
168 int b = 0;
169 int a = 255;
170
176 static constexpr int clamp(const int value) noexcept {
177 if (value < 0) {
178 return 0;
179 }
180 if (value > 255) {
181 return 255;
182 }
183 return value;
184 }
185
191 static constexpr double clamp_double(const double value) noexcept {
192 if (value < 0.0) {
193 return 0.0;
194 }
195 if (value > 1.0) {
196 return 1.0;
197 }
198 return value;
199 }
200
208 static constexpr int lerp_component(const int from, const int to, const double t) noexcept {
209 const double result = from + (to - from) * clamp_double(t);
210 return static_cast<int>(_NEFORCE round(result));
211 }
212
213public:
217 constexpr color() noexcept = default;
218
219 constexpr color(const color& other) noexcept = default;
220 constexpr color& operator=(const color& other) noexcept = default;
221
226 explicit constexpr color(const int gray) noexcept :
227 r(clamp(gray)),
228 g(clamp(gray)),
229 b(clamp(gray)) {}
230
236 constexpr color(const int gray, const int alpha) noexcept :
237 r(clamp(gray)),
238 g(clamp(gray)),
239 b(clamp(gray)),
240 a(clamp(alpha)) {}
241
248 constexpr color(const int red, const int green, const int blue) noexcept :
249 r(clamp(red)),
250 g(clamp(green)),
251 b(clamp(blue)) {}
252
260 constexpr color(const int red, const int green, const int blue, const int alpha) noexcept :
261 r(clamp(red)),
262 g(clamp(green)),
263 b(clamp(blue)),
264 a(clamp(alpha)) {}
265
270 NEFORCE_CONSTEXPR20 explicit color(const string_view str) { try_parse(str); }
271
276 NEFORCE_CONSTEXPR20 explicit color(const string& str) { try_parse(str.view()); }
277
282 NEFORCE_CONSTEXPR20 explicit color(const char* str) { try_parse(string_view{str}); }
283
287 constexpr color(color&& other) noexcept :
288 r(other.r),
289 g(other.g),
290 b(other.b),
291 a(other.a) {
292 other.r = 0;
293 other.g = 0;
294 other.b = 0;
295 other.a = 255;
296 }
297
301 constexpr color& operator=(color&& other) noexcept {
302 if (_NEFORCE addressof(other) == this) {
303 return *this;
304 }
305 this->swap(other);
306 return *this;
307 }
308
309 NEFORCE_CONSTEXPR20 ~color() = default;
310
315 constexpr int R() const noexcept { return r; }
316
321 constexpr int G() const noexcept { return g; }
322
327 constexpr int B() const noexcept { return b; }
328
333 constexpr int A() const noexcept { return a; }
334
339 constexpr void setR(const int red) noexcept { r = clamp(red); }
340
345 constexpr void setG(const int green) noexcept { g = clamp(green); }
346
351 constexpr void setB(const int blue) noexcept { b = clamp(blue); }
352
357 constexpr void setA(const int alpha) noexcept { a = clamp(alpha); }
358
365 constexpr void set_color(const int red, const int green, const int blue) noexcept {
366 r = clamp(red);
367 g = clamp(green);
368 b = clamp(blue);
369 }
370
378 constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept {
379 r = clamp(red);
380 g = clamp(green);
381 b = clamp(blue);
382 a = clamp(alpha);
383 }
384
389 constexpr void set_gray(const int gray) noexcept { r = g = b = clamp(gray); }
390
396 constexpr void set_gray(const int gray, const int alpha) noexcept {
397 set_gray(gray);
398 a = clamp(alpha);
399 }
400
405 constexpr bool is_transparent() const noexcept { return a == 0; }
406
411 constexpr bool is_opaque() const noexcept { return a == 255; }
412
417 constexpr double opacity() const noexcept { return a / 255.0; }
418
423 constexpr void set_opacity(double opacity) noexcept {
424 if (opacity < 0.0) {
425 opacity = 0.0;
426 }
427 if (opacity > 1.0) {
428 opacity = 1.0;
429 }
430 a = static_cast<int>(_NEFORCE round(opacity * 255));
431 }
432
441 static constexpr color lerp(const color& from, const color& to, double t) noexcept {
442 t = clamp_double(t);
443 return color(lerp_component(from.r, to.r, t), lerp_component(from.g, to.g, t), lerp_component(from.b, to.b, t),
444 lerp_component(from.a, to.a, t));
445 }
446
452 constexpr color operator+(const color& other) const noexcept {
453 return color(r + other.r, g + other.g, b + other.b, a + other.a);
454 }
455
461 constexpr color operator-(const color& other) const noexcept {
462 return color(r - other.r, g - other.g, b - other.b, a - other.a);
463 }
464
470 constexpr color operator*(const double scalar) const noexcept {
471 return color(static_cast<int>(_NEFORCE round(r * scalar)), static_cast<int>(_NEFORCE round(g * scalar)),
472 static_cast<int>(_NEFORCE round(b * scalar)), static_cast<int>(_NEFORCE round(a * scalar)));
473 }
474
480 constexpr color operator*(const int scalar) const noexcept {
481 return {r * scalar, g * scalar, b * scalar, a * scalar};
482 }
483
489 constexpr color& operator+=(const color& other) noexcept {
490 r = clamp(r + other.r);
491 g = clamp(g + other.g);
492 b = clamp(b + other.b);
493 a = clamp(a + other.a);
494 return *this;
495 }
496
502 constexpr color& operator-=(const color& other) noexcept {
503 r = clamp(r - other.r);
504 g = clamp(g - other.g);
505 b = clamp(b - other.b);
506 a = clamp(a - other.a);
507 return *this;
508 }
509
515 constexpr color& operator*=(const double scalar) noexcept {
516 r = clamp(static_cast<int>(_NEFORCE round(r * scalar)));
517 g = clamp(static_cast<int>(_NEFORCE round(g * scalar)));
518 b = clamp(static_cast<int>(_NEFORCE round(b * scalar)));
519 a = clamp(static_cast<int>(_NEFORCE round(a * scalar)));
520 return *this;
521 }
522
528 constexpr bool operator==(const color& other) const noexcept {
529 return r == other.r && g == other.g && b == other.b && a == other.a;
530 }
531
537 constexpr bool operator<(const color& other) const noexcept {
538 if (r != other.r) {
539 return r < other.r;
540 }
541 if (g != other.g) {
542 return g < other.g;
543 }
544 if (b != other.b) {
545 return b < other.b;
546 }
547 return a < other.a;
548 }
549
557 NEFORCE_NODISCARD constexpr color blend(const color& background) const noexcept {
558 if (a == 255) {
559 return *this;
560 }
561 if (a == 0) {
562 return background;
563 }
564
565 const decimal_t src_a = a / 255.0;
566 const decimal_t dst_a = background.a / 255.0;
567 const decimal_t inv_src_a = 1.0 - src_a;
568
569 // Result_A = Src_A + Dst_A * (1 - Src_A)
570 const decimal_t out_a = src_a + dst_a * inv_src_a;
571
572 if (out_a <= 0.0) {
573 return transparent();
574 }
575
576 // Result_RGB = (Src_RGB * Src_A + Dst_RGB * Dst_A * (1 - Src_A)) / Result_A
577 const decimal_t inv_out_a = 1.0 / out_a;
578 const int newR = static_cast<int>(_NEFORCE round((r * src_a + background.r * dst_a * inv_src_a) * inv_out_a));
579 const int newG = static_cast<int>(_NEFORCE round((g * src_a + background.g * dst_a * inv_src_a) * inv_out_a));
580 const int newB = static_cast<int>(_NEFORCE round((b * src_a + background.b * dst_a * inv_src_a) * inv_out_a));
581 const int newA = static_cast<int>(_NEFORCE round(out_a * 255.0));
582
583 return color(newR, newG, newB, newA);
584 }
585
590 NEFORCE_NODISCARD constexpr double gray_value() const noexcept { return 0.299 * r + 0.587 * g + 0.114 * b; }
591
596 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
597 return _NEFORCE format("{:02X}{:02X}{:02X}{:02X}", r, g, b, a);
598 }
599
606 static NEFORCE_CONSTEXPR20 color parse(const string_view hex) {
607 string_view clean_hex = hex;
608 if (clean_hex[0] == '#') {
609 clean_hex = clean_hex.substr(1);
610 }
611
612 if (clean_hex.length() == 6) {
613 const int r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
614 const int g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
615 const int b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
616 return {r, g, b};
617 } else if (clean_hex.length() == 8) {
618 const int r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
619 const int g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
620 const int b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
621 const int a = hexadecimal::parse(clean_hex.substr(6, 2)).value();
622 return {r, g, b, a};
623 } else {
624 NEFORCE_THROW_EXCEPTION(value_exception("Invalid hex string"));
625 }
626 unreachable();
627 }
628
636 NEFORCE_NODISCARD constexpr int to_ansi_256() const noexcept {
637 if (r == 0 && g == 0 && b == 0) {
638 return 16;
639 }
640 if (r == 255 && g == 255 && b == 255) {
641 return 231;
642 }
643
644 if (r == g && g == b) {
645 if (r < 8) {
646 return 16;
647 }
648 if (r > 248) {
649 return 231;
650 }
651 const int gray_index = (r - 8) / 10;
652 return 232 + (gray_index > 23 ? 23 : gray_index);
653 }
654
655 constexpr auto find_closest = [](const int value) -> int {
656 constexpr int levels[6] = {0, 95, 135, 175, 215, 255};
657
658 int closest_idx = 0;
659 int min_diff = 255 * 255;
660 for (int i = 0; i < 6; ++i) {
661 const int diff = value - levels[i];
662 const int dist = diff * diff;
663 if (dist < min_diff) {
664 min_diff = dist;
665 closest_idx = i;
666 }
667 }
668 return closest_idx;
669 };
670
671 const int r_idx = find_closest(r);
672 const int g_idx = find_closest(g);
673 const int b_idx = find_closest(b);
674
675 // 16 + 36 * R + 6 * G + B
676 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
677 }
678
684 NEFORCE_NODISCARD constexpr int to_ansi_basic(const bool is_background = false) const noexcept {
685 const int base = is_background ? 40 : 30;
686
687 if (r > g && r > b) {
688 if (g > 128 && b > 128) {
689 return base + 7;
690 }
691 return base + 1;
692 } else if (g > r && g > b) {
693 if (r > 128 && b > 128) {
694 return base + 7;
695 }
696 return base + 2;
697 } else if (b > r && b > g) {
698 if (r > 128 && g > 128) {
699 return base + 7;
700 }
701 return base + 4;
702 } else if (r == g && g == b) {
703 if (r < 64) {
704 return base + 0;
705 }
706 if (r < 192) {
707 return base + 7;
708 }
709 return base + 7;
710 } else if (r == g && r > b) {
711 return base + 3;
712 } else if (r == b && r > g) {
713 return base + 5;
714 } else if (g == b && g > r) {
715 return base + 6;
716 }
717
718 return base + 7;
719 }
720
726 NEFORCE_NODISCARD constexpr integer32 to_ansi_foreground(const bool use_256_color = true) const noexcept {
727 if (use_256_color) {
728 return integer32{38 * 100 + 5 * 10 + to_ansi_256()};
729 }
730 return integer32{to_ansi_basic(false)};
731 }
732
738 NEFORCE_NODISCARD constexpr integer32 to_ansi_background(const bool use_256_color = true) const noexcept {
739 if (use_256_color) {
740 return integer32{48 * 100 + 5 * 10 + to_ansi_256()};
741 }
742 return integer32{to_ansi_basic(true)};
743 }
744
750 NEFORCE_NODISCARD constexpr color to_premultiplied() const noexcept {
751 const decimal_t alpha = a / 255.0;
752 return color(static_cast<int>(_NEFORCE round(r * alpha)), static_cast<int>(_NEFORCE round(g * alpha)),
753 static_cast<int>(_NEFORCE round(b * alpha)), a);
754 }
755
761 NEFORCE_NODISCARD constexpr color from_premultiplied() const noexcept {
762 if (a == 0) {
763 return transparent();
764 }
765 const decimal_t inv_alpha = 255.0 / a;
766 return color(static_cast<int>(_NEFORCE round(r * inv_alpha)), static_cast<int>(_NEFORCE round(g * inv_alpha)),
767 static_cast<int>(_NEFORCE round(b * inv_alpha)), a);
768 }
769
775 NEFORCE_NODISCARD constexpr integer32 to_integer32(const bool use_256_color = true) const noexcept {
776 if (use_256_color) {
777 return integer32{to_ansi_256()};
778 }
779 return integer32{to_ansi_basic(false)};
780 }
781
786 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
787 constexpr hash<int> hasher;
788 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
789 }
790
795 constexpr void swap(color& other) noexcept {
796 color tmp = _NEFORCE move(other);
797 other = _NEFORCE move(*this);
798 *this = _NEFORCE move(tmp);
799 }
800
802 static constexpr color black() noexcept { return color(0, 0, 0, 255); }
803
805 static constexpr color white() noexcept { return color(255, 255, 255, 255); }
806
808 static constexpr color gray() noexcept { return color(128, 128, 128, 255); }
809
811 static constexpr color red() noexcept { return color(255, 0, 0, 255); }
812
814 static constexpr color green() noexcept { return color(0, 255, 0, 255); }
815
817 static constexpr color blue() noexcept { return color(0, 0, 255, 255); }
818
820 static constexpr color yellow() noexcept { return color(255, 255, 0, 255); }
821
823 static constexpr color magenta() noexcept { return color(255, 0, 255, 255); }
824
826 static constexpr color cyan() noexcept { return color(0, 255, 255, 255); }
827
829 static constexpr color transparent() noexcept { return color(0, 0, 0, 0); }
830};
831
838constexpr color operator*(const double scalar, const color& color) noexcept { return color * scalar; }
839
846constexpr color operator*(const int scalar, const color& color) noexcept { return color * scalar; }
847 // Color
849
850NEFORCE_END_NAMESPACE__
851#endif // NEFORCE_CORE_UTILITY_COLOR_HPP__
NEFORCE_NODISCARD constexpr size_type length() const noexcept
获取字符串长度
NEFORCE_NODISCARD constexpr basic_string_view substr(const size_type off=0, size_type count=npos) const
获取子视图
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view() const noexcept
获取字符串视图
RGB颜色类
constexpr void setG(const int green) noexcept
设置绿色分量
static constexpr color lerp(const color &from, const color &to, double t) noexcept
线性插值两个颜色
constexpr void set_gray(const int gray) noexcept
设置灰度值
constexpr color(color &&other) noexcept
移动构造函数
constexpr color(const int red, const int green, const int blue, const int alpha) noexcept
从RGBA分量构造
constexpr void set_opacity(double opacity) noexcept
设置不透明度
NEFORCE_NODISCARD constexpr color from_premultiplied() const noexcept
从预乘 Alpha 转换回直通 Alpha(Straight Alpha)
constexpr void set_gray(const int gray, const int alpha) noexcept
设置灰度值和透明度
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为十六进制字符串
constexpr bool operator<(const color &other) const noexcept
小于比较
constexpr color & operator+=(const color &other) noexcept
颜色加等赋值
NEFORCE_NODISCARD constexpr color to_premultiplied() const noexcept
转换为标准预乘 Alpha 表示
constexpr bool operator==(const color &other) const noexcept
相等比较
constexpr color(const int gray, const int alpha) noexcept
从灰度值和透明度构造
NEFORCE_NODISCARD constexpr integer32 to_ansi_foreground(const bool use_256_color=true) const noexcept
转换为ANSI前景色代码
NEFORCE_NODISCARD constexpr int to_ansi_256() const noexcept
转换为256色ANSI颜色索引
constexpr void set_color(const int red, const int green, const int blue) noexcept
设置RGB颜色
constexpr int A() const noexcept
获取透明度
constexpr void setR(const int red) noexcept
设置红色分量
constexpr int G() const noexcept
获取绿色分量
constexpr bool is_opaque() const noexcept
检查是否完全不透明
constexpr color(const int red, const int green, const int blue) noexcept
从RGB分量构造
constexpr color() noexcept=default
默认构造函数,创建黑色(0,0,0,255)
constexpr color operator-(const color &other) const noexcept
颜色减法
static constexpr color blue() noexcept
蓝色
NEFORCE_CONSTEXPR20 color(const string_view str)
从十六进制字符串构造
constexpr void swap(color &other) noexcept
交换两个颜色对象
static constexpr color transparent() noexcept
完全透明
constexpr void setB(const int blue) noexcept
设置蓝色分量
constexpr double opacity() const noexcept
获取不透明度(0.0-1.0)
constexpr int B() const noexcept
获取蓝色分量
constexpr color & operator*=(const double scalar) noexcept
颜色乘等赋值
static constexpr color red() noexcept
红色
constexpr color & operator-=(const color &other) noexcept
颜色减等赋值
NEFORCE_NODISCARD constexpr int to_ansi_basic(const bool is_background=false) const noexcept
转换为基本ANSI颜色代码
static constexpr color black() noexcept
黑色
static constexpr color green() noexcept
绿色
constexpr color operator*(const double scalar) const noexcept
颜色乘以标量
constexpr bool is_transparent() const noexcept
检查是否完全透明
constexpr color operator*(const int scalar) const noexcept
颜色乘以整数标量
NEFORCE_NODISCARD constexpr double gray_value() const noexcept
计算灰度值
static NEFORCE_CONSTEXPR20 color parse(const string_view hex)
从十六进制字符串解析颜色
NEFORCE_NODISCARD constexpr integer32 to_ansi_background(const bool use_256_color=true) const noexcept
转换为ANSI背景色代码
static constexpr color cyan() noexcept
青色
NEFORCE_NODISCARD constexpr color blend(const color &background) const noexcept
将当前颜色与背景色混合
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
static constexpr color white() noexcept
白色
constexpr color operator+(const color &other) const noexcept
颜色加法
constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept
设置RGBA颜色
static constexpr color yellow() noexcept
黄色
static constexpr color gray() noexcept
灰色
constexpr color & operator=(color &&other) noexcept
移动赋值运算符
NEFORCE_NODISCARD constexpr integer32 to_integer32(const bool use_256_color=true) const noexcept
转换为整数表示
constexpr int R() const noexcept
获取红色分量
static constexpr color magenta() noexcept
品红
constexpr void setA(const int alpha) noexcept
设置透明度
NEFORCE_CONSTEXPR20 color(const string &str)
从字符串对象构造
NEFORCE_CONSTEXPR20 color(const char *str)
从C风格字符串构造
NEFORCE_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr color operator*(const double scalar, const color &color) noexcept
标量乘以颜色
long double decimal_t
扩展精度浮点数类型
NEFORCE_NORETURN NEFORCE_ALWAYS_INLINE_INLINE void unreachable() noexcept
标记不可达代码路径
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string format(const string_view fmt, Args &&... args)
格式化字符串
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 decimal_t round(const decimal_t x) noexcept
四舍五入
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
basic_string_view< char > string_view
字符字符串视图
void swap()=delete
删除无参数的swap重载
十六进制数值包装类
数值类型包装类
哈希函数的主模板
static NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 hexadecimal parse(const string_view str)
从字符串解析十六进制值
通用接口,同时具备可比较和可哈希功能
32位整数包装类
可解析对象接口
NEFORCE_CONSTEXPR20 bool try_parse(const string_view str) noexcept
NEFORCE_NODISCARD constexpr package_type value() const noexcept
获取数值
变量处理异常