Skip to content

Commit efb57dc

Browse files
committed
Item-based Color
Signed-off-by: Spencer Magnusson <[email protected]>
1 parent 21bd2c9 commit efb57dc

25 files changed

+609
-20
lines changed

src/opentimelineio/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
set(OPENTIMELINEIO_HEADER_FILES
55
anyDictionary.h
66
anyVector.h
7+
color.h
78
clip.h
89
composable.h
910
composition.h
@@ -38,7 +39,8 @@ set(OPENTIMELINEIO_HEADER_FILES
3839
vectorIndexing.h
3940
version.h)
4041

41-
add_library(opentimelineio ${OTIO_SHARED_OR_STATIC_LIB}
42+
add_library(opentimelineio ${OTIO_SHARED_OR_STATIC_LIB}
43+
color.cpp
4244
clip.cpp
4345
composable.cpp
4446
composition.cpp

src/opentimelineio/clip.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ Clip::Clip(
1515
AnyDictionary const& metadata,
1616
std::vector<Effect*> const& effects,
1717
std::vector<Marker*> const& markers,
18-
std::string const& active_media_reference_key)
19-
: Parent{ name, source_range, metadata, effects, markers }
18+
std::string const& active_media_reference_key,
19+
std::optional<Color> const& color)
20+
: Parent{ name, source_range, metadata, effects, markers, /*enabled*/ true, color }
2021
, _active_media_reference_key(active_media_reference_key)
2122
{
2223
set_media_reference(media_reference);

src/opentimelineio/clip.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class Clip : public Item
4646
AnyDictionary const& metadata = AnyDictionary(),
4747
std::vector<Effect*> const& effects = std::vector<Effect*>(),
4848
std::vector<Marker*> const& markers = std::vector<Marker*>(),
49-
std::string const& active_media_reference_key = default_media_key);
49+
std::string const& active_media_reference_key = default_media_key,
50+
std::optional<Color> const& color = std::nullopt);
5051

5152
/// @name Media References
5253
///@{

src/opentimelineio/color.cpp

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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

src/opentimelineio/color.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright Contributors to the OpenTimelineIO project
3+
4+
#pragma once
5+
6+
#include <cmath>
7+
#include <vector>
8+
9+
#include "opentimelineio/version.h"
10+
11+
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {
12+
13+
14+
15+
class Color
16+
{
17+
public:
18+
struct Schema
19+
{
20+
static auto constexpr name = "Color";
21+
static int constexpr version = 1;
22+
};
23+
24+
Color(
25+
double const r = 1.f,
26+
double const g = 1.f,
27+
double const b = 1.f,
28+
double const a = 1.f,
29+
std::string const& name = "");
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+
45+
static Color* from_hex(std::string const& color);
46+
static Color* from_int_list(std::vector<int> const& color, int bit_depth);
47+
static Color* from_agbr_int(unsigned int agbr) noexcept;
48+
static Color* from_float_list(std::vector<double> const& color);
49+
50+
friend bool
51+
operator==(Color lhs, Color rhs) noexcept
52+
{
53+
return lhs.to_hex() == rhs.to_hex() && lhs.to_agbr_integer() == rhs.to_agbr_integer();
54+
}
55+
56+
std::string to_hex();
57+
std::vector<int> to_rgba_int_list(int base);
58+
unsigned int to_agbr_integer();
59+
std::vector<double> to_rgba_float_list();
60+
61+
double r() const { return _r; }
62+
double g() const { return _g; }
63+
double b() const { return _b; }
64+
double a() const { return _a; }
65+
std::string name() const { return _name; }
66+
67+
void set_r(double r) { _r = r; }
68+
void set_g(double g) { _g = g; }
69+
void set_b(double b) { _b = b; }
70+
void set_a(double a) { _a = a; }
71+
void set_name(std::string const& name) { _name = name; }
72+
73+
private:
74+
double _r;
75+
double _g;
76+
double _b;
77+
double _a;
78+
std::string _name;
79+
};
80+
81+
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

src/opentimelineio/composition.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ Composition::Composition(
1515
std::optional<TimeRange> const& source_range,
1616
AnyDictionary const& metadata,
1717
std::vector<Effect*> const& effects,
18-
std::vector<Marker*> const& markers)
19-
: Parent(name, source_range, metadata, effects, markers)
18+
std::vector<Marker*> const& markers,
19+
std::optional<Color> const& color)
20+
: Parent(name, source_range, metadata, effects, markers, /*enabled*/ true, color)
2021
{}
2122

2223
Composition::~Composition()

src/opentimelineio/composition.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class Composition : public Item
3838
std::optional<TimeRange> const& source_range = std::nullopt,
3939
AnyDictionary const& metadata = AnyDictionary(),
4040
std::vector<Effect*> const& effects = std::vector<Effect*>(),
41-
std::vector<Marker*> const& markers = std::vector<Marker*>());
41+
std::vector<Marker*> const& markers = std::vector<Marker*>(),
42+
std::optional<Color> const& color = std::nullopt);
4243

4344
/// @brief Return the kind of composition.
4445
virtual std::string composition_kind() const;

src/opentimelineio/deserialization.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "opentime/rationalTime.h"
55
#include "opentime/timeRange.h"
66
#include "opentime/timeTransform.h"
7+
#include "opentimelineio/color.h"
78
#include "opentimelineio/serializableObject.h"
89
#include "opentimelineio/serializableObjectWithMetadata.h"
910
#include "stringUtils.h"
@@ -587,6 +588,18 @@ SerializableObject::Reader::_decode(_Resolver& resolver)
587588
? std::any(TimeRange(start_time, duration))
588589
: std::any();
589590
}
591+
else if (schema_name_and_version == "Color.1")
592+
{
593+
float r, g, b, a;
594+
std::string name;
595+
return _fetch("r", &r)
596+
&& _fetch("g", &g)
597+
&& _fetch("b", &b)
598+
&& _fetch("a", &a)
599+
&& _fetch("name", &name)
600+
? std::any(Color(r, g, b, a, name))
601+
: std::any();
602+
}
590603
else if (schema_name_and_version == "TimeTransform.1")
591604
{
592605
RationalTime offset;
@@ -726,6 +739,12 @@ SerializableObject::Reader::read(std::string const& key, TimeRange* value)
726739
return _fetch(key, value);
727740
}
728741

742+
bool
743+
SerializableObject::Reader::read(std::string const& key, Color* value)
744+
{
745+
return _fetch(key, value);
746+
}
747+
729748
bool
730749
SerializableObject::Reader::read(std::string const& key, TimeTransform* value)
731750
{
@@ -816,6 +835,14 @@ SerializableObject::Reader::read(
816835
return _read_optional(key, value);
817836
}
818837

838+
bool
839+
SerializableObject::Reader::read(
840+
std::string const& key,
841+
std::optional<Color>* value)
842+
{
843+
return _read_optional(key, value);
844+
}
845+
819846
bool
820847
SerializableObject::Reader::read(
821848
std::string const& key,

src/opentimelineio/item.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ Item::Item(
1616
AnyDictionary const& metadata,
1717
std::vector<Effect*> const& effects,
1818
std::vector<Marker*> const& markers,
19-
bool enabled)
19+
bool enabled,
20+
std::optional<Color> const& color)
2021
: Parent(name, metadata)
2122
, _source_range(source_range)
2223
, _effects(effects.begin(), effects.end())
2324
, _markers(markers.begin(), markers.end())
2425
, _enabled(enabled)
26+
, _color(color)
2527
{}
2628

2729
Item::~Item()
@@ -176,6 +178,7 @@ Item::read_from(Reader& reader)
176178
&& reader.read_if_present("effects", &_effects)
177179
&& reader.read_if_present("markers", &_markers)
178180
&& reader.read_if_present("enabled", &_enabled)
181+
&& reader.read_if_present("color", &_color)
179182
&& Parent::read_from(reader);
180183
}
181184

@@ -187,6 +190,7 @@ Item::write_to(Writer& writer) const
187190
writer.write("effects", _effects);
188191
writer.write("markers", _markers);
189192
writer.write("enabled", _enabled);
193+
writer.write("color", _color);
190194
}
191195

192196
}} // namespace opentimelineio::OPENTIMELINEIO_VERSION

0 commit comments

Comments
 (0)