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
213 static constexpr int find_closest(const int value) noexcept {
214 constexpr int levels[6] = {0, 95, 135, 175, 215, 255};
215
216 int closest_idx = 0;
217 int min_diff = 255 * 255;
218 for (int i = 0; i < 6; ++i) {
219 const int diff = value - levels[i];
220 const int dist = diff * diff;
221 if (dist < min_diff) {
222 min_diff = dist;
223 closest_idx = i;
224 }
225 }
226 return closest_idx;
227 };
228
229public:
233 constexpr color() noexcept = default;
234
235 constexpr color(const color& other) noexcept = default;
236 constexpr color& operator=(const color& other) noexcept = default;
237
242 explicit constexpr color(const int gray) noexcept :
243 r(clamp(gray)),
244 g(clamp(gray)),
245 b(clamp(gray)) {}
246
252 constexpr color(const int gray, const int alpha) noexcept :
253 r(clamp(gray)),
254 g(clamp(gray)),
255 b(clamp(gray)),
256 a(clamp(alpha)) {}
257
264 constexpr color(const int red, const int green, const int blue) noexcept :
265 r(clamp(red)),
266 g(clamp(green)),
267 b(clamp(blue)) {}
268
276 constexpr color(const int red, const int green, const int blue, const int alpha) noexcept :
277 r(clamp(red)),
278 g(clamp(green)),
279 b(clamp(blue)),
280 a(clamp(alpha)) {}
281
287 NEFORCE_CONSTEXPR20 explicit color(const string_view str) { *this = parse(str); }
288
294 NEFORCE_CONSTEXPR20 explicit color(const string& str) { *this = parse(str.view()); }
295
301 NEFORCE_CONSTEXPR20 explicit color(const char* str) { *this = parse(string_view{str}); }
302
306 constexpr color(color&& other) noexcept :
307 r(other.r),
308 g(other.g),
309 b(other.b),
310 a(other.a) {
311 other.r = 0;
312 other.g = 0;
313 other.b = 0;
314 other.a = 255;
315 }
316
320 constexpr color& operator=(color&& other) noexcept {
321 if (_NEFORCE addressof(other) == this) {
322 return *this;
323 }
324 r = other.r;
325 g = other.g;
326 b = other.b;
327 a = other.a;
328 other.r = 0;
329 other.g = 0;
330 other.b = 0;
331 other.a = 255;
332 return *this;
333 }
334
335 NEFORCE_CONSTEXPR20 ~color() = default;
336
341 NEFORCE_NODISCARD constexpr int R() const noexcept { return r; }
342
347 NEFORCE_NODISCARD constexpr int G() const noexcept { return g; }
348
353 NEFORCE_NODISCARD constexpr int B() const noexcept { return b; }
354
359 NEFORCE_NODISCARD constexpr int A() const noexcept { return a; }
360
365 constexpr void setR(const int red) noexcept { r = clamp(red); }
366
371 constexpr void setG(const int green) noexcept { g = clamp(green); }
372
377 constexpr void setB(const int blue) noexcept { b = clamp(blue); }
378
383 constexpr void setA(const int alpha) noexcept { a = clamp(alpha); }
384
391 constexpr void set_color(const int red, const int green, const int blue) noexcept {
392 r = clamp(red);
393 g = clamp(green);
394 b = clamp(blue);
395 }
396
404 constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept {
405 r = clamp(red);
406 g = clamp(green);
407 b = clamp(blue);
408 a = clamp(alpha);
409 }
410
415 constexpr void set_gray(const int gray) noexcept { r = g = b = clamp(gray); }
416
422 constexpr void set_gray(const int gray, const int alpha) noexcept {
423 set_gray(gray);
424 a = clamp(alpha);
425 }
426
431 NEFORCE_NODISCARD constexpr bool is_transparent() const noexcept { return a == 0; }
432
437 NEFORCE_NODISCARD constexpr bool is_opaque() const noexcept { return a == 255; }
438
443 NEFORCE_NODISCARD constexpr double opacity() const noexcept { return a / 255.0; }
444
449 constexpr void set_opacity(double opacity) noexcept {
450 opacity = _NEFORCE max(opacity, 0.0);
451 opacity = _NEFORCE min(opacity, 1.0);
452 a = static_cast<int>(_NEFORCE round(opacity * 255));
453 }
454
463 static constexpr color lerp(const color& from, const color& to, double t) noexcept {
464 t = clamp_double(t);
465 return {lerp_component(from.r, to.r, t), lerp_component(from.g, to.g, t), lerp_component(from.b, to.b, t),
466 lerp_component(from.a, to.a, t)};
467 }
468
474 constexpr color operator+(const color& other) const noexcept {
475 return {r + other.r, g + other.g, b + other.b, a + other.a};
476 }
477
483 constexpr color operator-(const color& other) const noexcept {
484 return {r - other.r, g - other.g, b - other.b, a - other.a};
485 }
486
492 constexpr color operator*(const double scalar) const noexcept {
493 return {static_cast<int>(_NEFORCE round(static_cast<double>(r) * scalar)),
494 static_cast<int>(_NEFORCE round(static_cast<double>(g) * scalar)),
495 static_cast<int>(_NEFORCE round(static_cast<double>(b) * scalar)),
496 static_cast<int>(_NEFORCE round(static_cast<double>(a) * scalar))};
497 }
498
504 constexpr color operator*(const int scalar) const noexcept {
505 return {r * scalar, g * scalar, b * scalar, a * scalar};
506 }
507
513 constexpr color& operator+=(const color& other) noexcept {
514 r = clamp(r + other.r);
515 g = clamp(g + other.g);
516 b = clamp(b + other.b);
517 a = clamp(a + other.a);
518 return *this;
519 }
520
526 constexpr color& operator-=(const color& other) noexcept {
527 r = clamp(r - other.r);
528 g = clamp(g - other.g);
529 b = clamp(b - other.b);
530 a = clamp(a - other.a);
531 return *this;
532 }
533
539 constexpr color& operator*=(const double scalar) noexcept {
540 r = clamp(static_cast<int>(_NEFORCE round(r * scalar)));
541 g = clamp(static_cast<int>(_NEFORCE round(g * scalar)));
542 b = clamp(static_cast<int>(_NEFORCE round(b * scalar)));
543 a = clamp(static_cast<int>(_NEFORCE round(a * scalar)));
544 return *this;
545 }
546
552 NEFORCE_NODISCARD constexpr bool equal_to(const color& other) const noexcept {
553 return r == other.r && g == other.g && b == other.b && a == other.a;
554 }
555
561 NEFORCE_NODISCARD constexpr bool less_than(const color& other) const noexcept {
562 if (r != other.r) {
563 return r < other.r;
564 }
565 if (g != other.g) {
566 return g < other.g;
567 }
568 if (b != other.b) {
569 return b < other.b;
570 }
571 return a < other.a;
572 }
573
581 NEFORCE_NODISCARD constexpr color blend(const color& background) const noexcept {
582 if (a == 255) {
583 return *this;
584 }
585 if (a == 0) {
586 return background;
587 }
588
589 const decimal_t src_a = a / 255.0;
590 const decimal_t dst_a = background.a / 255.0;
591 const decimal_t inv_src_a = 1.0 - src_a;
592
593 // Result_A = Src_A + Dst_A * (1 - Src_A)
594 const decimal_t out_a = src_a + dst_a * inv_src_a;
595
596 if (out_a <= 0.0) {
597 return transparent();
598 }
599
600 // Result_RGB = (Src_RGB * Src_A + Dst_RGB * Dst_A * (1 - Src_A)) / Result_A
601 const decimal_t inv_out_a = 1.0 / out_a;
602 const int newR = static_cast<int>(_NEFORCE round((r * src_a + background.r * dst_a * inv_src_a) * inv_out_a));
603 const int newG = static_cast<int>(_NEFORCE round((g * src_a + background.g * dst_a * inv_src_a) * inv_out_a));
604 const int newB = static_cast<int>(_NEFORCE round((b * src_a + background.b * dst_a * inv_src_a) * inv_out_a));
605 const int newA = static_cast<int>(_NEFORCE round(out_a * 255.0));
606
607 return {newR, newG, newB, newA};
608 }
609
614 NEFORCE_NODISCARD constexpr double gray_value() const noexcept { return 0.299 * r + 0.587 * g + 0.114 * b; }
615
620 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
621 return _NEFORCE format("{:02X}{:02X}{:02X}{:02X}", r, g, b, a);
622 }
623
630 static NEFORCE_CONSTEXPR20 color parse(const string_view hex) {
631 string_view clean_hex = hex;
632 if (clean_hex[0] == '#') {
633 clean_hex = clean_hex.tail(1);
634 }
635
636 if (clean_hex.length() == 6) {
637 const int64_t r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
638 const int64_t g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
639 const int64_t b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
640 return {static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)};
641 } else if (clean_hex.length() == 8) {
642 const int64_t r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
643 const int64_t g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
644 const int64_t b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
645 const int64_t a = hexadecimal::parse(clean_hex.substr(6, 2)).value();
646 return {static_cast<int>(r), static_cast<int>(g), static_cast<int>(b), static_cast<int>(a)};
647 } else {
648 NEFORCE_THROW_EXCEPTION(value_exception("Invalid hex string"));
649 }
650 unreachable();
651 }
652
660 NEFORCE_NODISCARD constexpr int to_ansi_256() const noexcept {
661 if (r == 0 && g == 0 && b == 0) {
662 return 16;
663 }
664 if (r == 255 && g == 255 && b == 255) {
665 return 231;
666 }
667
668 if (r == g && g == b) {
669 if (r < 8) {
670 return 16;
671 }
672 if (r > 248) {
673 return 231;
674 }
675 const int gray_index = (r - 8) / 10;
676 return 232 + (gray_index > 23 ? 23 : gray_index);
677 }
678
679 const int r_idx = find_closest(r);
680 const int g_idx = find_closest(g);
681 const int b_idx = find_closest(b);
682
683 // 16 + 36 * R + 6 * G + B
684 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
685 }
686
692 NEFORCE_NODISCARD constexpr int to_ansi_basic(const bool is_background = false) const noexcept {
693 const int base = is_background ? 40 : 30;
694
695 if (r > g && r > b) {
696 if (g > 128 && b > 128) {
697 return base + 7;
698 }
699 return base + 1;
700 } else if (g > r && g > b) {
701 if (r > 128 && b > 128) {
702 return base + 7;
703 }
704 return base + 2;
705 } else if (b > r && b > g) {
706 if (r > 128 && g > 128) {
707 return base + 7;
708 }
709 return base + 4;
710 } else if (r == g && g == b) {
711 if (r < 64) {
712 return base + 0;
713 }
714 if (r < 192) {
715 return base + 7;
716 }
717 return base + 7;
718 } else if (r == g && r > b) {
719 return base + 3;
720 } else if (r == b && r > g) {
721 return base + 5;
722 } else if (g == b && g > r) {
723 return base + 6;
724 }
725
726 return base + 7;
727 }
728
734 NEFORCE_NODISCARD constexpr integer32 to_ansi_foreground(const bool use_256_color = true) const noexcept {
735 if (use_256_color) {
736 return integer32{38 * 100 + 5 * 10 + to_ansi_256()};
737 }
738 return integer32{to_ansi_basic(false)};
739 }
740
746 NEFORCE_NODISCARD constexpr integer32 to_ansi_background(const bool use_256_color = true) const noexcept {
747 if (use_256_color) {
748 return integer32{48 * 100 + 5 * 10 + to_ansi_256()};
749 }
750 return integer32{to_ansi_basic(true)};
751 }
752
758 NEFORCE_NODISCARD constexpr color to_premultiplied() const noexcept {
759 const decimal_t alpha = a / 255.0;
760 return {static_cast<int>(_NEFORCE round(r * alpha)), static_cast<int>(_NEFORCE round(g * alpha)),
761 static_cast<int>(_NEFORCE round(b * alpha)), a};
762 }
763
769 NEFORCE_NODISCARD constexpr color from_premultiplied() const noexcept {
770 if (a == 0) {
771 return transparent();
772 }
773 const decimal_t inv_alpha = 255.0 / a;
774 return {static_cast<int>(_NEFORCE round(r * inv_alpha)), static_cast<int>(_NEFORCE round(g * inv_alpha)),
775 static_cast<int>(_NEFORCE round(b * inv_alpha)), a};
776 }
777
783 NEFORCE_NODISCARD constexpr integer32 to_integer32(const bool use_256_color = true) const noexcept {
784 if (use_256_color) {
785 return integer32{to_ansi_256()};
786 }
787 return integer32{to_ansi_basic(false)};
788 }
789
794 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
795 constexpr hash<int> hasher;
796 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
797 }
798
803 constexpr void swap(color& other) noexcept {
804 color tmp = _NEFORCE move(other);
805 other = _NEFORCE move(*this);
806 *this = _NEFORCE move(tmp);
807 }
808
810 static constexpr color black() noexcept { return {0, 0, 0, 255}; }
811
813 static constexpr color white() noexcept { return {255, 255, 255, 255}; }
814
816 static constexpr color gray() noexcept { return {128, 128, 128, 255}; }
817
819 static constexpr color red() noexcept { return {255, 0, 0, 255}; }
820
822 static constexpr color green() noexcept { return {0, 255, 0, 255}; }
823
825 static constexpr color blue() noexcept { return {0, 0, 255, 255}; }
826
828 static constexpr color yellow() noexcept { return {255, 255, 0, 255}; }
829
831 static constexpr color magenta() noexcept { return {255, 0, 255, 255}; }
832
834 static constexpr color cyan() noexcept { return {0, 255, 255, 255}; }
835
837 static constexpr color transparent() noexcept { return {0, 0, 0, 0}; }
838};
839
846constexpr color operator*(const double scalar, const color& color) noexcept { return color * scalar; }
847
854constexpr color operator*(const int scalar, const color& color) noexcept { return color * scalar; }
855 // Color
857
858NEFORCE_END_NAMESPACE__
859#endif // NEFORCE_CORE_UTILITY_COLOR_HPP__
constexpr size_type length() const noexcept
获取字符串长度
constexpr basic_string_view tail(const size_type off=0) const
获取尾部子串
constexpr basic_string_view substr(const size_type off=0, const size_type count=npos) const
获取子视图
constexpr view_type view() const noexcept
获取字符串视图
RGB颜色类
constexpr integer32 to_integer32(const bool use_256_color=true) const noexcept
转换为整数表示
constexpr color(const string &str)
从字符串对象构造
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
设置不透明度
constexpr void set_gray(const int gray, const int alpha) noexcept
设置灰度值和透明度
constexpr color & operator+=(const color &other) noexcept
颜色加等赋值
constexpr double gray_value() const noexcept
计算灰度值
static constexpr color parse(const string_view hex)
从十六进制字符串解析颜色
constexpr color(const int gray, const int alpha) noexcept
从灰度值和透明度构造
constexpr color from_premultiplied() const noexcept
从预乘 Alpha 转换回直通 Alpha(Straight Alpha)
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
蓝色
constexpr void swap(color &other) noexcept
交换两个颜色对象
constexpr int to_ansi_basic(const bool is_background=false) const noexcept
转换为基本ANSI颜色代码
static constexpr color transparent() noexcept
完全透明
constexpr color(const string_view str)
从十六进制字符串构造
constexpr void setB(const int blue) noexcept
设置蓝色分量
constexpr double opacity() const noexcept
获取不透明度(0.0-1.0)
constexpr size_t to_hash() const noexcept
计算哈希值
constexpr color(const char *str)
从C风格字符串构造
constexpr int B() const noexcept
获取蓝色分量
constexpr color & operator*=(const double scalar) noexcept
颜色乘等赋值
static constexpr color red() noexcept
红色
constexpr color & operator-=(const color &other) noexcept
颜色减等赋值
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
颜色乘以整数标量
constexpr bool less_than(const color &other) const noexcept
小于比较
static constexpr color cyan() noexcept
青色
constexpr int to_ansi_256() const noexcept
转换为256色ANSI颜色索引
static constexpr color white() noexcept
白色
constexpr integer32 to_ansi_foreground(const bool use_256_color=true) const noexcept
转换为ANSI前景色代码
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颜色
constexpr integer32 to_ansi_background(const bool use_256_color=true) const noexcept
转换为ANSI背景色代码
static constexpr color yellow() noexcept
黄色
static constexpr color gray() noexcept
灰色
constexpr color & operator=(color &&other) noexcept
移动赋值运算符
constexpr string to_string() const
转换为十六进制字符串
constexpr color blend(const color &background) const noexcept
将当前颜色与背景色混合
constexpr color to_premultiplied() const noexcept
转换为标准预乘 Alpha 表示
constexpr int R() const noexcept
获取红色分量
static constexpr color magenta() noexcept
品红
constexpr void setA(const int alpha) noexcept
设置透明度
constexpr bool equal_to(const color &other) const noexcept
相等比较
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr color operator*(const double scalar, const color &color) noexcept
标量乘以颜色
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
long double decimal_t
扩展精度浮点数类型
long long int64_t
64位有符号整数类型
NEFORCE_NORETURN void unreachable() noexcept
标记不可达代码路径
constexpr string format(const string_view fmt, Args &&... args)
格式化字符串
constexpr 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
字符字符串视图
十六进制数值包装类
数值类型包装类
哈希函数的主模板
static constexpr hexadecimal parse(const string_view str)
从字符串解析十六进制值
通用接口,同时具备可比较和可哈希功能
32位整数包装类
可解析对象接口
constexpr package_type value() const noexcept
获取数值
变量处理异常