1+ // SPDX-License-Identifier: Apache-2.0
2+ // Copyright Contributors to the OpenTimelineIO project
3+
4+ #pragma once
5+
6+ #include < cmath>
7+
8+ #include " opentimelineio/serializableObjectWithMetadata.h"
9+ #include " opentimelineio/version.h"
10+
11+ namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {
12+
13+
14+
15+ class Color : public SerializableObjectWithMetadata
16+ {
17+ public:
18+ struct Schema
19+ {
20+ static auto constexpr name = " Color" ;
21+ static int constexpr version = 1 ;
22+ };
23+
24+ using Parent = SerializableObjectWithMetadata;
25+
26+ Color (double const r = 1 .f,
27+ double const g = 1 .f,
28+ double const b = 1 .f,
29+ double const a = 1 .f);
30+
31+ Color (Color const & other);
32+
33+ static const Color pink;
34+ static const Color red;
35+ static const Color orange;
36+ static const Color yellow;
37+ static const Color green;
38+ static const Color cyan;
39+ static const Color blue;
40+ static const Color purple;
41+ static const Color magenta;
42+ static const Color black;
43+ static const Color white;
44+ static const Color transparent;
45+
46+ static Color*
47+ from_hex (std::string const & color) noexcept
48+ {
49+ std::string temp = color;
50+ if (temp[0 ] == ' #' )
51+ {
52+ temp = temp.substr (1 );
53+ }
54+ else if (temp[0 ] == ' 0' and (temp[1 ] == ' x' or temp[1 ] == ' X' ))
55+ {
56+ temp = temp.substr (2 );
57+ }
58+
59+ double _r, _g, _b, _a;
60+ // 0xFFFFFFFF (rgba, 255)
61+ int BASE_16 = 16 ;
62+ double BASE_16_DIV = 255.0 ;
63+ double BASE_8_DIV = 15.0 ;
64+ if (temp.length () == 8 )
65+ {
66+ _r = std::stoi (temp.substr (0 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
67+ _g = std::stoi (temp.substr (2 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
68+ _b = std::stoi (temp.substr (4 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
69+ _a = std::stoi (temp.substr (6 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
70+ }
71+ // 0xFFFFFF (rgb, 255)
72+ else if (temp.length () == 6 )
73+ {
74+ _r = std::stoi (temp.substr (0 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
75+ _g = std::stoi (temp.substr (2 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
76+ _b = std::stoi (temp.substr (4 , 2 ), nullptr , BASE_16 ) / BASE_16_DIV ;
77+ _a = 1.0 ;
78+ }
79+ // 0xFFF (rgb, 16)
80+ else if (temp.length () == 3 )
81+ {
82+ _r = std::stoi (temp.substr (0 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
83+ _g = std::stoi (temp.substr (1 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
84+ _b = std::stoi (temp.substr (2 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
85+ _a = 1.0 ;
86+ }
87+ // 0xFFFF (rgba, 16)
88+ else if (temp.length () == 4 )
89+ {
90+ _r = std::stoi (temp.substr (0 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
91+ _g = std::stoi (temp.substr (1 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
92+ _b = std::stoi (temp.substr (2 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
93+ _a = std::stoi (temp.substr (3 , 1 ), nullptr , BASE_16 ) / BASE_8_DIV ;
94+ }
95+ else {
96+ throw std::invalid_argument (" Invalid hex format" );
97+ }
98+ return new Color (_r, _g, _b, _a);
99+ }
100+
101+ static Color*
102+ from_int_list (const std::vector<int >& color, int bit_depth) noexcept
103+ {
104+ double depth = pow (2 , bit_depth) - 1.0 ; // e.g. 8 = 255.0
105+ if (color.size () == 3 )
106+ return new Color (color[0 ] / depth, color[1 ] / depth, color[2 ] / depth, 1.0 );
107+ else if (color.size () == 4 )
108+ return new Color (color[0 ] / depth, color[1 ] / depth, color[2 ] / depth, color[3 ] / depth);
109+
110+ throw std::invalid_argument (" List must have exactly 3 or 4 elements" );
111+ }
112+
113+ static Color*
114+ from_agbr_int (unsigned int agbr) noexcept
115+ {
116+ auto conv_r = (agbr & 0xFF ) / 255.0 ;
117+ auto conv_g = ((agbr >> 16 ) & 0xFF ) / 255.0 ;
118+ auto conv_b = ((agbr >> 8 ) & 0xFF ) / 255.0 ;
119+ auto conv_a = ((agbr >> 24 ) & 0xFF ) / 255.0 ;
120+ return new Color (conv_r, conv_g, conv_b, conv_a);
121+ }
122+
123+ static Color*
124+ from_float_list (const std::vector<double >& color) noexcept
125+ {
126+ if (color.size () == 3 )
127+ return new Color (color[0 ], color[1 ], color[2 ], 1.0 );
128+ else if (color.size () == 4 )
129+ return new Color (color[0 ], color[1 ], color[2 ], color[3 ]);
130+
131+ throw std::invalid_argument (" List must have exactly 3 or 4 elements" );
132+ }
133+
134+ friend bool
135+ operator ==(Color lhs, Color rhs) noexcept
136+ {
137+ return lhs.to_hex () == rhs.to_hex () && lhs.to_agbr_integer () == rhs.to_agbr_integer ();
138+ }
139+
140+ std::string to_hex ();
141+ std::array<int , 4 > to_rgba_int_list (int base);
142+ unsigned int to_agbr_integer ();
143+ std::array<double , 4 > to_rgba_float_list ();
144+
145+ double r () const { return _r; }
146+ double g () const { return _g; }
147+ double b () const { return _b; }
148+ double a () const { return _a; }
149+
150+ void set_r (double r) { _r = r; }
151+ void set_g (double g) { _g = g; }
152+ void set_b (double b) { _b = b; }
153+ void set_a (double a) { _a = a; }
154+
155+ protected:
156+ virtual ~Color ();
157+
158+ bool read_from (Reader&) override ;
159+ void write_to (Writer&) const override ;
160+
161+ private:
162+ double _r;
163+ double _g;
164+ double _b;
165+ double _a;
166+ };
167+
168+ }} // namespace opentimelineio::OPENTIMELINEIO_VERSION
0 commit comments