Skip to content

Commit f071e02

Browse files
committed
Marker RGB colors
Signed-off-by: Spencer Magnusson <spencer.magnusson@dreamworks.com>
1 parent aa34e9a commit f071e02

16 files changed

Lines changed: 346 additions & 139 deletions

File tree

docs/tutorials/otio-serialized-schema-only-fields.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,6 @@ parameters:
3131

3232
## Module: opentimelineio.core
3333

34-
### Color.1
35-
36-
parameters:
37-
- *a*
38-
- *b*
39-
- *g*
40-
- *name*
41-
- *r*
42-
4334
### Composable.1
4435

4536
parameters:
@@ -152,6 +143,15 @@ parameters:
152143
- *name*
153144
- *source_range*
154145

146+
### Color.1
147+
148+
parameters:
149+
- *a*
150+
- *b*
151+
- *g*
152+
- *name*
153+
- *r*
154+
155155
### Effect.1
156156

157157
parameters:
@@ -224,7 +224,7 @@ parameters:
224224
- *name*
225225
- *time_scalar*
226226

227-
### Marker.2
227+
### Marker.3
228228

229229
parameters:
230230
- *color*

docs/tutorials/otio-serialized-schema.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,27 +55,6 @@ parameters:
5555

5656
## Module: opentimelineio.core
5757

58-
### Color.1
59-
60-
*full module path*: `opentimelineio.core.Color`
61-
62-
*documentation*:
63-
64-
```
65-
:class:`Color` is a definition of red, green, blue, and alpha double floating point values, allowing
66-
conversion between different formats. To be considered interoperable, the sRGB transfer function
67-
encoded values, ranging between zero and one, are expected to be accurate to within 1/255 of the
68-
intended value. Round-trip conversions may not be guaranteed outside that. This Color class is meant
69-
for use in user interface elements, like marker or clip coloring, NOT for image pixel content.
70-
```
71-
72-
parameters:
73-
- *a*:
74-
- *b*:
75-
- *g*:
76-
- *name*:
77-
- *r*:
78-
7958
### Composable.1
8059

8160
*full module path*: `opentimelineio.core.Composable`
@@ -309,6 +288,27 @@ parameters:
309288
- *name*:
310289
- *source_range*:
311290

291+
### Color.1
292+
293+
*full module path*: `opentimelineio.schema.Color`
294+
295+
*documentation*:
296+
297+
```
298+
:class:`Color` is a definition of red, green, blue, and alpha double floating point values, allowing
299+
conversion between different formats. To be considered interoperable, the sRGB transfer function
300+
encoded values, ranging between zero and one, are expected to be accurate to within 1/255 of the
301+
intended value. Round-trip conversions may not be guaranteed outside that. This Color class is meant
302+
for use in user interface elements, like marker or clip coloring, NOT for image pixel content.
303+
```
304+
305+
parameters:
306+
- *a*:
307+
- *b*:
308+
- *g*:
309+
- *name*:
310+
- *r*:
311+
312312
### Effect.1
313313

314314
*full module path*: `opentimelineio.schema.Effect`
@@ -519,7 +519,7 @@ parameters:
519519
Note that adjusting the time_scalar of a :class:`~LinearTimeWarp` does not affect the duration of the item this effect is attached to.
520520
Instead it affects the speed of the media displayed within that item.
521521

522-
### Marker.2
522+
### Marker.3
523523

524524
*full module path*: `opentimelineio.schema.Marker`
525525

@@ -534,7 +534,7 @@ system.
534534
```
535535

536536
parameters:
537-
- *color*: Color string for this marker (for example: 'RED'), based on the :class:`~Color` enum.
537+
- *color*: Color object assigned to this marker
538538
- *comment*: Optional comment for this marker.
539539
- *marked_range*: Range this marker applies to, relative to the :class:`.Item` this marker is attached to (e.g. the :class:`.Clip` or :class:`.Track` that owns this marker).
540540
- *metadata*:

src/opentimelineio/CORE_VERSION_MAP.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ const label_to_schema_version_map CORE_VERSION_MAP{
221221
{ "ImageSequenceReference", 1 },
222222
{ "Item", 1 },
223223
{ "LinearTimeWarp", 1 },
224-
{ "Marker", 2 },
224+
{ "Marker", 3 },
225225
{ "MediaLinker", 1 },
226226
{ "MediaReference", 1 },
227227
{ "MissingReference", 1 },

src/opentimelineio/marker.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {
88

99
Marker::Marker(
10-
std::string const& name,
11-
TimeRange const& marked_range,
12-
std::string const& color,
13-
AnyDictionary const& metadata,
14-
std::string const& comment)
10+
std::string const& name,
11+
TimeRange const& marked_range,
12+
std::optional<Color> const& color,
13+
AnyDictionary const& metadata,
14+
std::string const& comment)
1515
: Parent(name, metadata)
1616
, _color(color)
1717
, _marked_range(marked_range)

src/opentimelineio/marker.h

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "opentimelineio/serializableObjectWithMetadata.h"
77
#include "opentimelineio/version.h"
8+
#include "opentimelineio/color.h"
89

910
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {
1011

@@ -16,27 +17,12 @@ namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {
1617
class OTIO_API_TYPE Marker : public SerializableObjectWithMetadata
1718
{
1819
public:
19-
/// @brief This struct provides the base set of colors.
20-
struct Color
21-
{
22-
static auto constexpr pink = "PINK";
23-
static auto constexpr red = "RED";
24-
static auto constexpr orange = "ORANGE";
25-
static auto constexpr yellow = "YELLOW";
26-
static auto constexpr green = "GREEN";
27-
static auto constexpr cyan = "CYAN";
28-
static auto constexpr blue = "BLUE";
29-
static auto constexpr purple = "PURPLE";
30-
static auto constexpr magenta = "MAGENTA";
31-
static auto constexpr black = "BLACK";
32-
static auto constexpr white = "WHITE";
33-
};
3420

3521
/// @brief This struct provides the Marker schema.
3622
struct Schema
3723
{
3824
static auto constexpr name = "Marker";
39-
static int constexpr version = 2;
25+
static int constexpr version = 3;
4026
};
4127

4228
using Parent = SerializableObjectWithMetadata;
@@ -51,15 +37,15 @@ class OTIO_API_TYPE Marker : public SerializableObjectWithMetadata
5137
OTIO_API Marker(
5238
std::string const& name = std::string(),
5339
TimeRange const& marked_range = TimeRange(),
54-
std::string const& color = Color::green,
40+
std::optional<Color> const& color = Color::green,
5541
AnyDictionary const& metadata = AnyDictionary(),
5642
std::string const& comment = std::string());
5743

5844
/// @brief Return the marker color.
59-
std::string color() const noexcept { return _color; }
45+
std::optional<Color> color() const noexcept { return _color; }
6046

6147
/// @brief Set the marker color.
62-
void set_color(std::string const& color) { _color = color; }
48+
void set_color(std::optional<Color> const& color) { _color = color; }
6349

6450
/// @brief Return the marker time range.
6551
TimeRange marked_range() const noexcept { return _marked_range; }
@@ -83,7 +69,7 @@ class OTIO_API_TYPE Marker : public SerializableObjectWithMetadata
8369
void write_to(Writer&) const override;
8470

8571
private:
86-
std::string _color;
72+
std::optional<Color> _color;
8773
TimeRange _marked_range;
8874
std::string _comment;
8975
};

src/opentimelineio/typeRegistry.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@
2929
#include "opentimelineio/unknownSchema.h"
3030
#include "stringUtils.h"
3131

32+
#include <algorithm>
3233
#include <assert.h>
34+
#include <cctype>
35+
#include <map>
36+
#include <set>
3337
#include <vector>
3438

3539
namespace opentimelineio { namespace OPENTIMELINEIO_VERSION_NS {
@@ -96,6 +100,62 @@ TypeRegistry::TypeRegistry()
96100
d->erase("range");
97101
});
98102

103+
// 2 - 3
104+
register_upgrade_function(Marker::Schema::name, 3, [](AnyDictionary* d) {
105+
// get color name
106+
std::string color_name_v2;
107+
if (d->get_if_set("color", &color_name_v2))
108+
{
109+
static const std::map<std::string, Color> color_map = {
110+
{ "PINK", Color::pink },
111+
{ "RED", Color::red },
112+
{ "ORANGE", Color::orange },
113+
{ "YELLOW", Color::yellow },
114+
{ "GREEN", Color::green },
115+
{ "CYAN", Color::cyan },
116+
{ "BLUE", Color::blue },
117+
{ "MAGENTA", Color::magenta },
118+
{ "PURPLE", Color::purple },
119+
{ "BLACK", Color::black },
120+
{ "WHITE", Color::white },
121+
{ "TRANSPARENT", Color::transparent }
122+
};
123+
124+
// make copy of color_name_v2, for uppercase change to be separate
125+
std::string color_name_v2_upper = color_name_v2;
126+
127+
// force color name to uppercase for lookup
128+
// since v2 color names were case-insensitive
129+
std::transform(
130+
color_name_v2_upper.begin(),
131+
color_name_v2_upper.end(),
132+
color_name_v2_upper.begin(),
133+
[](unsigned char c) { return std::toupper(c); }
134+
);
135+
136+
// if all-caps name matches a known color, convert to color with r,g,b,a, and name fields
137+
auto it = color_map.find(color_name_v2_upper);
138+
Color color_match = Color::white;
139+
std::string color_match_name = "";
140+
if (it != color_map.end()) { // match found
141+
color_match = it->second;
142+
color_match_name = color_match.name();
143+
}
144+
else { // no match, default to white but keep original name
145+
color_match = Color::white;
146+
color_match_name = color_name_v2;
147+
}
148+
149+
(*d)["color"] = Color(
150+
color_match.r(),
151+
color_match.g(),
152+
color_match.b(),
153+
color_match.a(),
154+
color_match_name
155+
);
156+
}
157+
});
158+
99159
register_upgrade_function(Clip::Schema::name, 2, [](AnyDictionary* d) {
100160
auto media_ref = (*d)["media_reference"];
101161

@@ -116,6 +176,46 @@ TypeRegistry::TypeRegistry()
116176
d->erase("media_reference");
117177
});
118178

179+
// 3->2
180+
register_downgrade_function(Marker::Schema::name, 3, [](AnyDictionary* d) {
181+
AnyDictionary color_dict;
182+
183+
if (d->get_if_set("color", &color_dict))
184+
{
185+
std::string color_name = "";
186+
color_dict.get_if_set("name", &color_name);
187+
188+
// if the name matches case-insensitive to a known color,
189+
// set the color an all-caps version of that name
190+
if (!color_name.empty())
191+
{
192+
// Convert to uppercase for comparison and storage
193+
std::string upper_name = color_name;
194+
std::transform(
195+
upper_name.begin(),
196+
upper_name.end(),
197+
upper_name.begin(),
198+
[](unsigned char c) { return std::toupper(c); }
199+
);
200+
201+
// Known color names - these are the valid color enum values
202+
static const std::set<std::string> known_colors = {
203+
"RED", "GREEN", "BLUE", "YELLOW", "CYAN", "MAGENTA",
204+
"PINK", "ORANGE", "PURPLE", "BLACK", "WHITE", "TRANSPARENT"
205+
};
206+
207+
if (known_colors.find(upper_name) != known_colors.end())
208+
{
209+
// remove color object and replace with color name string
210+
(*d)["color"] = upper_name;
211+
}
212+
else { // otherwise, keep name as-is
213+
(*d)["color"] = color_name;
214+
}
215+
}
216+
}
217+
});
218+
119219
// 2->1
120220
register_downgrade_function(Clip::Schema::name, 2, [](AnyDictionary* d) {
121221
AnyDictionary mrefs;

0 commit comments

Comments
 (0)