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+
41+ Color*
42+ Color::from_hex (std::string const & color)
43+ {
44+ std::string temp = color;
45+ if (temp[0 ] == ' #' )
46+ {
47+ temp = temp.substr (1 );
48+ }
49+ else if (temp[0 ] == ' 0' && (temp[1 ] == ' x' || temp[1 ] == ' X' ))
50+ {
51+ temp = temp.substr (2 );
52+ }
53+
54+ double _r, _g, _b, _a;
55+ // 0xFFFFFFFF (rgba, 255)
56+ int BASE_16 = 16 ;
57+ double BASE_16_DIV = 255.0 ;
58+ double BASE_8_DIV = 15.0 ;
59+ if (temp.length () == 8 )
60+ {
61+ _r = std::stoi (temp.substr (0 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
62+ _g = std::stoi (temp.substr (2 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
63+ _b = std::stoi (temp.substr (4 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
64+ _a = std::stoi (temp.substr (6 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
65+ }
66+ // 0xFFFFFF (rgb, 255)
67+ else if (temp.length () == 6 )
68+ {
69+ _r = std::stoi (temp.substr (0 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
70+ _g = std::stoi (temp.substr (2 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
71+ _b = std::stoi (temp.substr (4 , 2 ), nullptr , BASE_16) / BASE_16_DIV;
72+ _a = 1.0 ;
73+ }
74+ // 0xFFF (rgb, 16)
75+ else if (temp.length () == 3 )
76+ {
77+ _r = std::stoi (temp.substr (0 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
78+ _g = std::stoi (temp.substr (1 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
79+ _b = std::stoi (temp.substr (2 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
80+ _a = 1.0 ;
81+ }
82+ // 0xFFFF (rgba, 16)
83+ else if (temp.length () == 4 )
84+ {
85+ _r = std::stoi (temp.substr (0 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
86+ _g = std::stoi (temp.substr (1 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
87+ _b = std::stoi (temp.substr (2 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
88+ _a = std::stoi (temp.substr (3 , 1 ), nullptr , BASE_16) / BASE_8_DIV;
89+ }
90+ else {
91+ throw std::invalid_argument (" Invalid hex format" );
92+ }
93+ return new Color (_r, _g, _b, _a);
94+ }
95+
96+ Color*
97+ Color::from_int_list (std::vector<int > const & color, int bit_depth)
98+ {
99+ double depth = pow (2 , bit_depth) - 1.0 ; // e.g. 8 = 255.0
100+ if (color.size () == 3 )
101+ return new Color (color[0 ] / depth, color[1 ] / depth, color[2 ] / depth, 1.0 );
102+ else if (color.size () == 4 )
103+ return new Color (color[0 ] / depth, color[1 ] / depth, color[2 ] / depth, color[3 ] / depth);
104+
105+ throw std::invalid_argument (" List must have exactly 3 or 4 elements" );
106+ }
107+
108+ Color*
109+ Color::from_agbr_int (unsigned int agbr) noexcept
110+ {
111+ auto conv_r = (agbr & 0xFF ) / 255.0 ;
112+ auto conv_g = ((agbr >> 16 ) & 0xFF ) / 255.0 ;
113+ auto conv_b = ((agbr >> 8 ) & 0xFF ) / 255.0 ;
114+ auto conv_a = ((agbr >> 24 ) & 0xFF ) / 255.0 ;
115+ return new Color (conv_r, conv_g, conv_b, conv_a);
116+ }
117+
118+ Color*
119+ Color::from_float_list (std::vector<double > const & color)
120+ {
121+ if (color.size () == 3 )
122+ return new Color (color[0 ], color[1 ], color[2 ], 1.0 );
123+ else if (color.size () == 4 )
124+ return new Color (color[0 ], color[1 ], color[2 ], color[3 ]);
125+
126+ throw std::invalid_argument (" List must have exactly 3 or 4 elements" );
127+ }
128+
129+ std::string
130+ Color::to_hex ()
131+ {
132+ auto rgba = to_rgba_int_list (8 );
133+ std::stringstream ss;
134+ ss << " #" ;
135+
136+ ss << std::hex << std::setfill (' 0' );
137+ ss << std::setw (2 ) << rgba[0 ];
138+ ss << std::setw (2 ) << rgba[1 ];
139+ ss << std::setw (2 ) << rgba[2 ];
140+ ss << std::setw (2 ) << rgba[3 ];
141+ return ss.str ();
142+ }
143+
144+ std::vector<int >
145+ Color::to_rgba_int_list (int base)
146+ {
147+ double math_base = pow (2 , base) - 1.0 ;
148+ return {int (_r * math_base), int (_g * math_base), int (_b * math_base), int (_a * math_base)};
149+ }
150+
151+ unsigned int
152+ Color::to_agbr_integer ()
153+ {
154+ auto rgba = to_rgba_int_list (8 );
155+ return (rgba[3 ] << 24 ) + (rgba[2 ] << 16 ) + (rgba[1 ] << 8 ) + rgba[0 ];
156+ }
157+
158+ std::vector<double >
159+ Color::to_rgba_float_list ()
160+ {
161+ return {_r, _g, _b, _a};
162+ }
163+
164+ }} // namespace opentimelineio::OPENTIMELINEIO_VERSION
0 commit comments