NovaSVG 0.10.0
A header-only SVG library
Loading...
Searching...
No Matches
color.h
Go to the documentation of this file.
1#ifndef NOVASVG_COLOR_H
2#define NOVASVG_COLOR_H
3
4// Self-contained on purpose (see NOVASVG_MAX() usage below): this header
5// is included standalone by tests/cpp/test_novacolor.cpp, not just via
6// the novasvg.h umbrella. novasvg.h defines these same two macros before
7// it includes this file, so the guards below are a no-op in that path;
8// here they're what makes plain `#include "novasvg/detail/color.h"` work
9// on its own too.
10#ifndef NOVASVG_MAX
11#define NOVASVG_MAX(a, b) ((a) > (b) ? (a) : (b))
12#endif
13#ifndef NOVASVG_MIN
14#define NOVASVG_MIN(a, b) ((a) < (b) ? (a) : (b))
15#endif
16
17#include <stdexcept>
18#include <string>
19#include <cstdint>
20#include <math.h>
21#include <sstream>
22#include <iomanip>
23#include <algorithm>
24#include <cctype>
25#include <ostream>
26#include <utility>
27#include <type_traits>
28
33namespace novasvg {
34struct ColorBlend;
35
85class Color {
86private:
87 uint8_t r;
88 uint8_t g;
89 uint8_t b;
90 uint8_t a;
91
92public:
93 // ==================== Constructors ====================
94
114 explicit Color(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255)
115 : r(r), g(g), b(b), a(a) {}
116
141 Color(const std::string& str) : Color(fromString(str)) {}
142
143 // ==================== Interop with Other Color Types ====================
144
170 template <typename OtherColor,
171 typename = decltype(std::declval<const OtherColor&>().red()),
172 typename = decltype(std::declval<const OtherColor&>().green()),
173 typename = decltype(std::declval<const OtherColor&>().blue()),
174 typename = decltype(std::declval<const OtherColor&>().alpha())>
175 constexpr Color(const OtherColor& other)
176 : r(static_cast<uint8_t>(other.red())),
177 g(static_cast<uint8_t>(other.green())),
178 b(static_cast<uint8_t>(other.blue())),
179 a(static_cast<uint8_t>(other.alpha())) {}
180
202 template <typename OtherColor>
203 constexpr OtherColor as() const {
204 return OtherColor(r, g, b, a);
205 }
206
207 // ==================== Getters & Setters ====================
208
213 uint8_t getR() const { return r; }
214
219 uint8_t getG() const { return g; }
220
225 uint8_t getB() const { return b; }
226
232 uint8_t getA() const { return a; }
233
238 void setR(uint8_t value) { r = value; }
239
244 void setG(uint8_t value) { g = value; }
245
250 void setB(uint8_t value) { b = value; }
251
256 void setA(uint8_t value) { a = value; }
257
258 // ==================== Engine-Facing Additions ====================
259 // The methods below are additions for the SVG rendering engine's
260 // internal use (float 0..1 channel access, opacity checks, deriving
261 // a new color with a different alpha) -- your original getters/
262 // setters/static factories above are untouched.
263
265 float getRF() const { return r / 255.f; }
267 float getGF() const { return g / 255.f; }
269 float getBF() const { return b / 255.f; }
271 float getAF() const { return a / 255.f; }
272
274 bool isOpaque() const { return a == 255; }
276 bool isVisible() const { return a > 0; }
277
279 Color opaqueColor() const { return Color(r, g, b, 255); }
280
282 Color colorWithAlpha(float opacity) const {
283 return Color(r, g, b, static_cast<uint8_t>(a * opacity));
284 }
285
286 // ==================== Value Conversion ====================
287
308 uint32_t value() const {
309 return (static_cast<uint32_t>(r) << 24) |
310 (static_cast<uint32_t>(g) << 16) |
311 (static_cast<uint32_t>(b) << 8) |
312 static_cast<uint32_t>(a);
313 }
314
335 friend bool operator==(const Color& lhs, const Color& rhs) {
336 return lhs.r == rhs.r &&
337 lhs.g == rhs.g &&
338 lhs.b == rhs.b &&
339 lhs.a == rhs.a;
340 }
341
362 friend bool operator!=(const Color& lhs, const Color& rhs) {
363 return !(lhs == rhs);
364 }
365
366 // ==================== String Conversion ====================
367
384 operator std::string() const { return toString(); }
385
400 std::string toString() const {
401 std::ostringstream oss;
402 oss << "Color(r=" << static_cast<int>(r)
403 << ", g=" << static_cast<int>(g)
404 << ", b=" << static_cast<int>(b)
405 << ", a=" << static_cast<int>(a) << ")";
406 return oss.str();
407 }
408
409 // ==================== Blend Operators ====================
410
433 ColorBlend operator|(int percentage) const;
434
449 Color operator|(const Color& other) const {
450 return blend(other, 50);
451 }
452
470 Color blend(const Color& other, int percentage) const {
471 int pct = NOVASVG_MAX(0, NOVASVG_MIN(100, percentage));
472 double p = pct / 100.0;
473 double q = 1.0 - p;
474
475 return Color(
476 static_cast<uint8_t>(std::ceil(r * q + other.r * p)),
477 static_cast<uint8_t>(std::ceil(g * q + other.g * p)),
478 static_cast<uint8_t>(std::ceil(b * q + other.b * p)),
479 static_cast<uint8_t>(std::ceil(a * q + other.a * p))
480 );
481 }
482
483 // ==================== Static Factory Methods ====================
484
519 static Color fromString(const std::string& str) {
520 if (str.empty()) {
521 throw std::invalid_argument("Empty string provided");
522 }
523 bool is_hex = std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isxdigit(c); });
524 return (str[0] == '#') ? fromHash(str) : ( is_hex ? fromHash("#" + str) : fromName(str));
525 }
526
545 static Color rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) {
546 return Color(r, g, b, a);
547 }
548
575 static Color fromHash(const std::string& hex_code) {
576 if (hex_code.empty() || hex_code[0] != '#') {
577 throw std::invalid_argument("Hex color string must start with '#'");
578 }
579
580 std::string hex_body = hex_code.substr(1);
581
582 if (hex_body.length() != 3 && hex_body.length() != 4 &&
583 hex_body.length() != 6 && hex_body.length() != 8) {
584 throw std::invalid_argument("Invalid hex color format");
585 }
586
587 // Expand shorthand: #RGB -> #RRGGBB
588 if (hex_body.length() == 3) {
589 hex_body = std::string() + hex_body[0] + hex_body[0]
590 + hex_body[1] + hex_body[1]
591 + hex_body[2] + hex_body[2];
592 }
593 // Expand shorthand with alpha: #RGBA -> #RRGGBBAA
594 else if (hex_body.length() == 4) {
595 hex_body = std::string() + hex_body[0] + hex_body[0]
596 + hex_body[1] + hex_body[1]
597 + hex_body[2] + hex_body[2]
598 + hex_body[3] + hex_body[3];
599 }
600
601 uint8_t r = static_cast<uint8_t>(std::stoi(hex_body.substr(0, 2), nullptr, 16));
602 uint8_t g = static_cast<uint8_t>(std::stoi(hex_body.substr(2, 2), nullptr, 16));
603 uint8_t b = static_cast<uint8_t>(std::stoi(hex_body.substr(4, 2), nullptr, 16));
604 uint8_t a = (hex_body.length() == 8)
605 ? static_cast<uint8_t>(std::stoi(hex_body.substr(6, 2), nullptr, 16))
606 : 255;
607
608 return Color(r, g, b, a);
609 }
610
636 static Color fromName(const std::string& name) {
637 std::string name_lower = name;
638 for (char& c : name_lower) c = static_cast<char>(std::tolower(c));
639
640 if (name_lower == "black") return black();
641 if (name_lower == "white") return white();
642 if (name_lower == "red") return red();
643 if (name_lower == "green") return green();
644 if (name_lower == "lime") return lime();
645 if (name_lower == "blue") return blue();
646 if (name_lower == "yellow") return yellow();
647 if (name_lower == "cyan") return cyan();
648 if (name_lower == "magenta") return magenta();
649 if (name_lower == "silver") return silver();
650 if (name_lower == "gray" || name_lower == "grey") return gray();
651 if (name_lower == "maroon") return maroon();
652 if (name_lower == "olive") return olive();
653 if (name_lower == "purple") return purple();
654 if (name_lower == "teal") return teal();
655 if (name_lower == "navy") return navy();
656 if (name_lower == "orange") return orange();
657 if (name_lower == "pink") return pink();
658 if (name_lower == "brown") return brown();
659 if (name_lower == "transparent") return transparent();
660
661 throw std::invalid_argument("Unknown color name: '" + name + "'");
662 }
663
692 static Color fromValue(uint32_t value) {
693 uint8_t r = static_cast<uint8_t>((value >> 24) & 0xFF);
694 uint8_t g = static_cast<uint8_t>((value >> 16) & 0xFF);
695 uint8_t b = static_cast<uint8_t>((value >> 8) & 0xFF);
696 uint8_t a = static_cast<uint8_t>(value & 0xFF);
697 return Color(r, g, b, a);
698 }
699
700 // ==================== Predefined Colors ====================
701
706 static Color black() { return Color(0, 0, 0); }
707
712 static Color white() { return Color(255, 255, 255); }
713
718 static Color red() { return Color(255, 0, 0); }
719
724 static Color green() { return Color(0, 128, 0); }
725
730 static Color lime() { return Color(0, 255, 0); }
731
736 static Color blue() { return Color(0, 0, 255); }
737
742 static Color yellow() { return Color(255, 255, 0); }
743
748 static Color cyan() { return Color(0, 255, 255); }
749
754 static Color magenta() { return Color(255, 0, 255); }
755
760 static Color silver() { return Color(192, 192, 192); }
761
766 static Color gray() { return Color(128, 128, 128); }
767
772 static Color maroon() { return Color(128, 0, 0); }
773
778 static Color olive() { return Color(128, 128, 0); }
779
784 static Color purple() { return Color(128, 0, 128); }
785
790 static Color teal() { return Color(0, 128, 128); }
791
796 static Color navy() { return Color(0, 0, 128); }
797
802 static Color orange() { return Color(255, 165, 0); }
803
808 static Color pink() { return Color(255, 192, 203); }
809
814 static Color brown() { return Color(165, 42, 42); }
815
820 static Color transparent() { return Color(0, 0, 0, 0); }
821
822 // Static member-variable form, distinct from the black()/white()/
823 // transparent() factory functions above (used pervasively as
824 // default values through the SVG engine, e.g. `Color::Transparent`).
825 static const Color Black;
826 static const Color White;
827 static const Color Transparent;
828};
829
830inline const Color Color::Black(0, 0, 0, 255);
831inline const Color Color::White(255, 255, 255, 255);
832inline const Color Color::Transparent(0, 0, 0, 0);
833
834// ==================== ColorBlend ====================
835
859
866 ColorBlend(const Color& base, int percent)
867 : baseColor(base), percentage(percent) {}
868
883 Color operator|(const Color& other) const {
884 return baseColor.blend(other, percentage);
885 }
886
895 ColorBlend operator|(const ColorBlend& other) const {
896 // First blend: baseColor | percentage → transparent
898 // Second blend: intermediate | other.percentage → other.baseColor
899 return ColorBlend(intermediate, other.percentage);
900 }
901
909 operator Color() const {
911 }
912};
913
923inline ColorBlend Color::operator|(int percentage) const {
924 return ColorBlend(*this, percentage);
925}
926
927// ==================== Non-Member Operators ====================
928
944inline std::ostream& operator<<(std::ostream& os, const Color& color) {
945 os << color.toString();
946 return os;
947}
948
959inline std::ostream& operator<<(std::ostream& os, const ColorBlend& blend) {
960 os << static_cast<Color>(blend);
961 return os;
962}
963
964} // namespace novasvg
965
966// ==================== Color Literals Namespace ====================
967
988namespace novasvg::color_literals {
989
1018inline novasvg::Color operator""_c(const char* str, std::size_t len) {
1019 return novasvg::Color::fromString(std::string(str, len));
1020}
1021
1022} // namespace novasvg::color_literals
1023
1024#endif // NOVASVG_COLOR_H
Represents a color in RGBA format (0xRRGGBBAA).
Definition color.h:85
float getGF() const
Green component as a 0..1 float.
Definition color.h:267
static Color purple()
Returns the color purple (128, 0, 128, 255).
Definition color.h:784
static Color rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Create a color from RGBA components.
Definition color.h:545
static Color brown()
Returns the color brown (165, 42, 42, 255).
Definition color.h:814
void setB(uint8_t value)
Set the blue component of the color.
Definition color.h:250
static Color magenta()
Returns the color magenta (255, 0, 255, 255).
Definition color.h:754
Color(uint8_t r=0, uint8_t g=0, uint8_t b=0, uint8_t a=255)
Construct a new Color object from RGBA components.
Definition color.h:114
static Color transparent()
Returns the color transparent (0, 0, 0, 0).
Definition color.h:820
void setA(uint8_t value)
Set the alpha component of the color.
Definition color.h:256
float getBF() const
Blue component as a 0..1 float.
Definition color.h:269
static Color olive()
Returns the color olive (128, 128, 0, 255).
Definition color.h:778
static Color yellow()
Returns the color yellow (255, 255, 0, 255).
Definition color.h:742
static Color maroon()
Returns the color maroon (128, 0, 0, 255).
Definition color.h:772
static Color pink()
Returns the color pink (255, 192, 203, 255).
Definition color.h:808
uint8_t getB() const
Get the blue component of the color.
Definition color.h:225
friend bool operator!=(const Color &lhs, const Color &rhs)
Inequality comparison operator.
Definition color.h:362
static Color navy()
Returns the color navy (0, 0, 128, 255).
Definition color.h:796
static Color orange()
Returns the color orange (255, 165, 0, 255).
Definition color.h:802
static Color black()
Returns the color black (0, 0, 0, 255).
Definition color.h:706
Color colorWithAlpha(float opacity) const
This color with its alpha scaled by opacity (0..1).
Definition color.h:282
static Color cyan()
Returns the color cyan (0, 255, 255, 255).
Definition color.h:748
static Color fromName(const std::string &name)
Create a color from a standard CSS color name.
Definition color.h:636
Color blend(const Color &other, int percentage) const
Blend this color with another color by a specific percentage.
Definition color.h:470
static Color blue()
Returns the color blue (0, 0, 255, 255).
Definition color.h:736
constexpr OtherColor as() const
Convert this Color to any "color-like" type constructible from four (r, g, b, a) components.
Definition color.h:203
uint8_t getR() const
Get the red component of the color.
Definition color.h:213
static Color fromHash(const std::string &hex_code)
Create a color from a hexadecimal string.
Definition color.h:575
static Color lime()
Returns the color lime (0, 255, 0, 255).
Definition color.h:730
bool isOpaque() const
True if fully opaque (alpha == 255).
Definition color.h:274
void setR(uint8_t value)
Set the red component of the color.
Definition color.h:238
static Color red()
Returns the color red (255, 0, 0, 255).
Definition color.h:718
friend bool operator==(const Color &lhs, const Color &rhs)
Equality comparison operator.
Definition color.h:335
static Color fromValue(uint32_t value)
Create a color from a 32-bit integer value.
Definition color.h:692
uint32_t value() const
Convert the color to a 32-bit unsigned integer.
Definition color.h:308
static Color gray()
Returns the color gray (128, 128, 128, 255).
Definition color.h:766
bool isVisible() const
True if not fully transparent (alpha > 0).
Definition color.h:276
static const Color Transparent
Definition color.h:827
float getRF() const
Red component as a 0..1 float.
Definition color.h:265
Color(const std::string &str)
Construct a new Color object from a string.
Definition color.h:141
std::string toString() const
Convert the color to a human-readable string.
Definition color.h:400
Color operator|(const Color &other) const
Blend this color with another color (50% each).
Definition color.h:449
static Color green()
Returns the color green (0, 128, 0, 255).
Definition color.h:724
uint8_t getA() const
Get the alpha component of the color.
Definition color.h:232
static Color fromString(const std::string &str)
Create a color from a string (auto-detects hex or name).
Definition color.h:519
Color opaqueColor() const
This color with alpha forced to fully opaque (255).
Definition color.h:279
float getAF() const
Alpha component as a 0..1 float.
Definition color.h:271
void setG(uint8_t value)
Set the green component of the color.
Definition color.h:244
static const Color Black
Definition color.h:825
static const Color White
Definition color.h:826
constexpr Color(const OtherColor &other)
Construct a Color from any "color-like" type.
Definition color.h:175
static Color teal()
Returns the color teal (0, 128, 128, 255).
Definition color.h:790
static Color silver()
Returns the color silver (192, 192, 192, 255).
Definition color.h:760
ColorBlend operator|(int percentage) const
Blend this color with transparent by a percentage.
Definition color.h:923
uint8_t getG() const
Get the green component of the color.
Definition color.h:219
static Color white()
Returns the color white (255, 255, 255, 255).
Definition color.h:712
#define NOVASVG_MAX(a, b)
Definition color.h:11
#define NOVASVG_MIN(a, b)
Definition color.h:14
String literal operators for creating Color instances.
NOVASVG_INLINE void blend(canvas_t *canvas, const span_buffer_t *span_buffer)
Definition blend.h:1215
Main namespace for the NovaSVG library.
Definition bitmap.h:23
std::ostream & operator<<(std::ostream &os, const Color &color)
Stream output operator for Color.
Definition color.h:944
Lightweight helper class for color blending operations.
Definition color.h:856
ColorBlend(const Color &base, int percent)
Construct a ColorBlend from a base color and percentage.
Definition color.h:866
ColorBlend operator|(const ColorBlend &other) const
Chain multiple blend operations.
Definition color.h:895
int percentage
Percentage for the blend operation (0-100)
Definition color.h:858
Color baseColor
The base color being blended.
Definition color.h:857
Color operator|(const Color &other) const
Finalize the blend with a specific color.
Definition color.h:883
Represents a color with red, green, blue, and alpha components.
Definition render.h:1019