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
3539namespace 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