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