1 /////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2007, Weta Digital Ltd 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are 9 // met: 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Weta Digital nor the names of 17 // its contributors may be used to endorse or promote products derived 18 // from this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 // 32 /////////////////////////////////////////////////////////////////////////// 33 34 //----------------------------------------------------------------------------- 35 // 36 // Functions related to accessing channels 37 // and views in multi-view OpenEXR files. 38 // 39 //----------------------------------------------------------------------------- 40 41 #include <ImfMultiView.h> 42 43 using namespace std; 44 45 namespace Imf { 46 namespace { 47 48 StringVector 49 parseString (string name, char c = '.') 50 { 51 // 52 // Turn name into a list of strings, separating 53 // on char 'c' with whitespace stripped. 54 // 55 56 StringVector r; 57 58 while (name.size() > 0) 59 { 60 size_t s = name.find (c); 61 string sec = name.substr (0, s); 62 63 // 64 // Strip spaces from beginning 65 // 66 67 while (sec.size() > 0 && sec[0] == ' ') 68 sec.erase (0, 1); 69 70 // 71 // Strip spaces from end 72 // 73 74 while (sec.size() > 0 && sec[sec.size() - 1] == ' ') 75 sec.erase (sec.size() - 1); 76 77 r.push_back (sec); 78 79 // 80 // Strip off name including ending 'c' 81 // 82 83 if (s == name.npos) 84 name = ""; 85 else 86 name = name.substr (s + 1); 87 } 88 89 return r; 90 } 91 92 93 int 94 viewNum (const string &view, const StringVector &multiView) 95 { 96 // 97 // returns which view number is called 'view' 98 // returns -1 if no member of multiView is 'view' 99 // (i.e. if viewNum() returns -1, 'view' isn't a view name 100 // if viewNum() returns 0, 'view' is the default view 101 // otherwise, it's some other (valid) view 102 // 103 104 for (int i = 0; i < multiView.size(); ++i) 105 { 106 if (multiView[i] == view) 107 return i; 108 } 109 110 return -1; 111 } 112 113 } // namespace 114 115 116 string 117 defaultViewName (const StringVector &multiView) 118 { 119 if (multiView.size() > 0) 120 return multiView[0]; 121 else 122 return ""; 123 } 124 125 126 string 127 viewFromChannelName (const string &channel, 128 const StringVector &multiView) 129 { 130 // 131 // Given the name of a channel, return the name of the view to 132 // which it belongs. 133 // 134 135 // 136 // View name is penultimate section of name separated by periods ('.'s) 137 // 138 139 StringVector s = parseString (channel, '.'); 140 141 if (s.size() == 0) 142 return ""; // nothing in, nothing out 143 144 if (s.size() == 1) 145 { 146 // 147 // Return default view name. 148 // The rules say ALL channels with no periods 149 // in the name belong to the default view. 150 // 151 152 return multiView[0]; 153 } 154 else 155 { 156 // 157 // size >= 2 - the last part is the channel name, 158 // the next-to-last part is the view name. 159 // Check if that part of the name really is 160 // a valid view and, if it is, return it. 161 // 162 163 const string &viewName = s[s.size() - 2]; 164 165 if (viewNum (viewName, multiView) >= 0) 166 return viewName; 167 else 168 return ""; // not associated with any particular view 169 } 170 } 171 172 173 ChannelList 174 channelsInView (const string & viewName, 175 const ChannelList & channelList, 176 const StringVector & multiView) 177 { 178 // 179 // Return a list of all channels belonging to view viewName. 180 // 181 182 ChannelList q; 183 184 for (ChannelList::ConstIterator i = channelList.begin(); 185 i != channelList.end(); 186 ++i) 187 { 188 // 189 // Get view name for this channel 190 // 191 192 string view = viewFromChannelName (i.name(), multiView); 193 194 195 // 196 // Insert channel into q if it's a member of view viewName 197 // 198 199 if (view == viewName) 200 q.insert (i.name(), i.channel()); 201 } 202 203 return q; 204 } 205 206 207 ChannelList 208 channelsInNoView (const ChannelList &channelList, 209 const StringVector &multiView) 210 { 211 // 212 // Return a list of channels not associated with any named view. 213 // 214 215 return channelsInView ("", channelList, multiView); 216 } 217 218 219 220 bool 221 areCounterparts (const string &channel1, 222 const string &channel2, 223 const StringVector &multiView) 224 { 225 // 226 // Given two channels, return true if they are the same 227 // channel in two different views. 228 // 229 230 StringVector chan1 = parseString (channel1); 231 unsigned int size1 = chan1.size(); // number of SECTIONS in string 232 // name (not string length) 233 234 StringVector chan2 = parseString (channel2); 235 unsigned int size2 = chan2.size(); 236 237 if (size1 == 0 || size2 == 0) 238 return false; 239 240 // 241 // channel1 and channel2 can't be counterparts 242 // if either channel is in no view. 243 // 244 245 if (size1 > 1 && viewNum (chan1[size1 - 2], multiView) == -1) 246 return false; 247 248 if (size2 > 1 && viewNum (chan2[size2 - 2], multiView) == -1) 249 return false; 250 251 if (viewFromChannelName (channel1, multiView) == 252 viewFromChannelName (channel2, multiView)) 253 { 254 // 255 // channel1 and channel2 are not counterparts 256 // if they are in the same view. 257 // 258 259 return false; 260 } 261 262 if (size1 == 1) 263 { 264 // 265 // channel1 is a default channel - the channels will only be 266 // counterparts if channel2 is of the form <view>.<channel1> 267 // 268 269 return size2 == 2 && chan1[0] == chan2[1]; 270 } 271 272 if (size2 == 1) 273 { 274 // 275 // channel2 is a default channel - the channels will only be 276 // counterparts if channel1 is of the form <view>.<channel2> 277 // 278 279 return size1 == 2 && chan2[0] == chan1[1]; 280 } 281 282 // 283 // Neither channel is a default channel. To be counterparts both 284 // channel names must have the same number of components, and 285 // all components except the penultimate one must be the same. 286 // 287 288 if (size1 != size2) 289 return false; 290 291 for(int i = 0; i < size1; ++i) 292 { 293 if (i != size1 - 2 && chan1[i] != chan2[i]) 294 return false; 295 } 296 297 return true; 298 } 299 300 301 ChannelList 302 channelInAllViews (const string &channelName, 303 const ChannelList &channelList, 304 const StringVector &multiView) 305 { 306 // 307 // Given the name of a channel, return a 308 // list of the same channel in all views. 309 // 310 311 ChannelList q; 312 313 for (ChannelList::ConstIterator i=channelList.begin(); 314 i != channelList.end(); 315 ++i) 316 { 317 if (i.name() == channelName || 318 areCounterparts (i.name(), channelName, multiView)) 319 { 320 q.insert (i.name(), i.channel()); 321 } 322 } 323 324 return q; 325 } 326 327 328 string 329 channelInOtherView (const string &channelName, 330 const ChannelList &channelList, 331 const StringVector &multiView, 332 const string &otherViewName) 333 { 334 // 335 // Given the name of a channel in one view, return the 336 // corresponding channel name for view otherViewName. 337 // 338 339 for (ChannelList::ConstIterator i=channelList.begin(); 340 i != channelList.end(); 341 ++i) 342 { 343 if (viewFromChannelName (i.name(), multiView) == otherViewName && 344 areCounterparts (i.name(), channelName, multiView)) 345 { 346 return i.name(); 347 } 348 } 349 350 return ""; 351 } 352 353 354 string 355 insertViewName (const string &channel, 356 const StringVector &multiView, 357 int i) 358 { 359 // 360 // Insert multiView[i] into the channel name if appropriate. 361 // 362 363 StringVector s = parseString (channel, '.'); 364 365 if (s.size() == 0) 366 return ""; // nothing in, nothing out 367 368 if (s.size() == 1 && i == 0) 369 { 370 // 371 // Channel in the default view, with no periods in its name. 372 // Do not insert view name. 373 // 374 375 return channel; 376 } 377 378 // 379 // View name becomes penultimate section of new channel name. 380 // 381 382 string newName; 383 384 for (int j = 0; j < s.size(); ++j) 385 { 386 if (j < s.size() - 1) 387 newName += s[j] + "."; 388 else 389 newName += multiView[i] + "." + s[j]; 390 } 391 392 return newName; 393 } 394 395 396 } // namespace Imf 397