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 #include "ImfNamespace.h"
45
46 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
47
48 namespace {
49
50 StringVector
parseString(string name,char c='.')51 parseString (string name, char c = '.')
52 {
53 //
54 // Turn name into a list of strings, separating
55 // on char 'c' with whitespace stripped.
56 //
57
58 StringVector r;
59
60 while (name.size() > 0)
61 {
62 size_t s = name.find (c);
63 string sec = name.substr (0, s);
64
65 //
66 // Strip spaces from beginning
67 //
68
69 while (sec.size() > 0 && sec[0] == ' ')
70 sec.erase (0, 1);
71
72 //
73 // Strip spaces from end
74 //
75
76 while (sec.size() > 0 && sec[sec.size() - 1] == ' ')
77 sec.erase (sec.size() - 1);
78
79 r.push_back (sec);
80
81 //
82 // Strip off name including ending 'c'
83 //
84
85 if (s == name.npos)
86 name = "";
87 else
88 name = name.substr (s + 1);
89 }
90
91 return r;
92 }
93
94
95 int
viewNum(const string & view,const StringVector & multiView)96 viewNum (const string &view, const StringVector &multiView)
97 {
98 //
99 // returns which view number is called 'view'
100 // returns -1 if no member of multiView is 'view'
101 // (i.e. if viewNum() returns -1, 'view' isn't a view name
102 // if viewNum() returns 0, 'view' is the default view
103 // otherwise, it's some other (valid) view
104 //
105
106 for (size_t i = 0; i < multiView.size(); ++i)
107 {
108 if (multiView[i] == view)
109 return i;
110 }
111
112 return -1;
113 }
114
115 } // namespace
116
117
118 string
defaultViewName(const StringVector & multiView)119 defaultViewName (const StringVector &multiView)
120 {
121 if (multiView.size() > 0)
122 return multiView[0];
123 else
124 return "";
125 }
126
127
128 string
viewFromChannelName(const string & channel,const StringVector & multiView)129 viewFromChannelName (const string &channel,
130 const StringVector &multiView)
131 {
132 //
133 // Given the name of a channel, return the name of the view to
134 // which it belongs.
135 //
136
137 //
138 // View name is penultimate section of name separated by periods ('.'s)
139 //
140
141 StringVector s = parseString (channel, '.');
142
143 if (s.size() == 0)
144 return ""; // nothing in, nothing out
145
146 if (s.size() == 1)
147 {
148 //
149 // Return default view name.
150 // The rules say ALL channels with no periods
151 // in the name belong to the default view.
152 //
153
154 return multiView[0];
155 }
156 else
157 {
158 //
159 // size >= 2 - the last part is the channel name,
160 // the next-to-last part is the view name.
161 // Check if that part of the name really is
162 // a valid view and, if it is, return it.
163 //
164
165 const string &viewName = s[s.size() - 2];
166
167 if (viewNum (viewName, multiView) >= 0)
168 return viewName;
169 else
170 return ""; // not associated with any particular view
171 }
172 }
173
174
175 ChannelList
channelsInView(const string & viewName,const ChannelList & channelList,const StringVector & multiView)176 channelsInView (const string & viewName,
177 const ChannelList & channelList,
178 const StringVector & multiView)
179 {
180 //
181 // Return a list of all channels belonging to view viewName.
182 //
183
184 ChannelList q;
185
186 for (ChannelList::ConstIterator i = channelList.begin();
187 i != channelList.end();
188 ++i)
189 {
190 //
191 // Get view name for this channel
192 //
193
194 string view = viewFromChannelName (i.name(), multiView);
195
196
197 //
198 // Insert channel into q if it's a member of view viewName
199 //
200
201 if (view == viewName)
202 q.insert (i.name(), i.channel());
203 }
204
205 return q;
206 }
207
208
209 ChannelList
channelsInNoView(const ChannelList & channelList,const StringVector & multiView)210 channelsInNoView (const ChannelList &channelList,
211 const StringVector &multiView)
212 {
213 //
214 // Return a list of channels not associated with any named view.
215 //
216
217 return channelsInView ("", channelList, multiView);
218 }
219
220
221
222 bool
areCounterparts(const string & channel1,const string & channel2,const StringVector & multiView)223 areCounterparts (const string &channel1,
224 const string &channel2,
225 const StringVector &multiView)
226 {
227 //
228 // Given two channels, return true if they are the same
229 // channel in two different views.
230 //
231
232 StringVector chan1 = parseString (channel1);
233 size_t size1 = chan1.size(); // number of SECTIONS in string
234 // name (not string length)
235
236 StringVector chan2 = parseString (channel2);
237 size_t size2 = chan2.size();
238
239 if (size1 == 0 || size2 == 0)
240 return false;
241
242 //
243 // channel1 and channel2 can't be counterparts
244 // if either channel is in no view.
245 //
246
247 if (size1 > 1 && viewNum (chan1[size1 - 2], multiView) == -1)
248 return false;
249
250 if (size2 > 1 && viewNum (chan2[size2 - 2], multiView) == -1)
251 return false;
252
253 if (viewFromChannelName (channel1, multiView) ==
254 viewFromChannelName (channel2, multiView))
255 {
256 //
257 // channel1 and channel2 are not counterparts
258 // if they are in the same view.
259 //
260
261 return false;
262 }
263
264 if (size1 == 1)
265 {
266 //
267 // channel1 is a default channel - the channels will only be
268 // counterparts if channel2 is of the form <view>.<channel1>
269 //
270
271 return size2 == 2 && chan1[0] == chan2[1];
272 }
273
274 if (size2 == 1)
275 {
276 //
277 // channel2 is a default channel - the channels will only be
278 // counterparts if channel1 is of the form <view>.<channel2>
279 //
280
281 return size1 == 2 && chan2[0] == chan1[1];
282 }
283
284 //
285 // Neither channel is a default channel. To be counterparts both
286 // channel names must have the same number of components, and
287 // all components except the penultimate one must be the same.
288 //
289
290 if (size1 != size2)
291 return false;
292
293 for(size_t i = 0; i < size1; ++i)
294 {
295 if (i != size1 - 2 && chan1[i] != chan2[i])
296 return false;
297 }
298
299 return true;
300 }
301
302
303 ChannelList
channelInAllViews(const string & channelName,const ChannelList & channelList,const StringVector & multiView)304 channelInAllViews (const string &channelName,
305 const ChannelList &channelList,
306 const StringVector &multiView)
307 {
308 //
309 // Given the name of a channel, return a
310 // list of the same channel in all views.
311 //
312
313 ChannelList q;
314
315 for (ChannelList::ConstIterator i=channelList.begin();
316 i != channelList.end();
317 ++i)
318 {
319 if (i.name() == channelName ||
320 areCounterparts (i.name(), channelName, multiView))
321 {
322 q.insert (i.name(), i.channel());
323 }
324 }
325
326 return q;
327 }
328
329
330 string
channelInOtherView(const string & channelName,const ChannelList & channelList,const StringVector & multiView,const string & otherViewName)331 channelInOtherView (const string &channelName,
332 const ChannelList &channelList,
333 const StringVector &multiView,
334 const string &otherViewName)
335 {
336 //
337 // Given the name of a channel in one view, return the
338 // corresponding channel name for view otherViewName.
339 //
340
341 for (ChannelList::ConstIterator i=channelList.begin();
342 i != channelList.end();
343 ++i)
344 {
345 if (viewFromChannelName (i.name(), multiView) == otherViewName &&
346 areCounterparts (i.name(), channelName, multiView))
347 {
348 return i.name();
349 }
350 }
351
352 return "";
353 }
354
355
356 string
insertViewName(const string & channel,const StringVector & multiView,int i)357 insertViewName (const string &channel,
358 const StringVector &multiView,
359 int i)
360 {
361 //
362 // Insert multiView[i] into the channel name if appropriate.
363 //
364
365 StringVector s = parseString (channel, '.');
366
367 if (s.size() == 0)
368 return ""; // nothing in, nothing out
369
370 if (s.size() == 1 && i == 0)
371 {
372 //
373 // Channel in the default view, with no periods in its name.
374 // Do not insert view name.
375 //
376
377 return channel;
378 }
379
380 //
381 // View name becomes penultimate section of new channel name.
382 //
383
384 string newName;
385
386 for (size_t j = 0; j < s.size(); ++j)
387 {
388 if (j < s.size() - 1)
389 newName += s[j] + ".";
390 else
391 newName += multiView[i] + "." + s[j];
392 }
393
394 return newName;
395 }
396
397
398 string
removeViewName(const string & channel,const string & view)399 removeViewName(const string & channel,const string & view)
400 {
401 StringVector s = parseString (channel, '.');
402
403 if (s.size() == 0)
404 return ""; // nothing in, nothing out
405
406 if (s.size() == 1)
407 {
408 //
409 // Channel in the default view, since no periods in its name.
410 // No viewname to remove
411 //
412
413 return channel;
414 }
415
416 string newName;
417 for( size_t j = 0 ; j < s.size() ; ++j)
418 {
419 // only add the penultimate string part
420 // if it doesn't match the view name
421 if(j+2!=s.size() || s[j]!=view)
422 {
423 newName += s[j];
424 if(j+1!=s.size())
425 {
426 newName += ".";
427 }
428 }
429 }
430
431 return newName;
432
433 }
434
435 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
436