ImfPartHelper.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright (c) Weta Digital, Ltd and Contributors to the OpenEXR Project.
  4. //
  5. #ifndef INCLUDED_IMF_PARTHELPER_H
  6. #define INCLUDED_IMF_PARTHELPER_H
  7. //-----------------------------------------------------------------------------
  8. //
  9. // Functions to help split channels into separate parts: provide a list of
  10. // channels, with desired views. call SplitChannels to assign a part to each
  11. // layer, or correct the name of the channel.
  12. // Also can enumerate the parts in a file and list which parts channels are in
  13. //
  14. // This is a good way to offer a 'create Multipart file' checkbox to the user in a
  15. // write dialog box: Populate a list of MultiViewChannelName objects,
  16. // call SplitChannels with whether single or multipart files are required.
  17. // Then write the number of parts it specifies, using internal_name for the channel
  18. // names in the ChannelList and FrameBuffer objects. There should be no need
  19. // for different codepaths for single part and multipart files
  20. //
  21. // Similarly, on reading a file as a MultiPartInputFile, use GetChannelsInMultiPartFile to
  22. // enumerate all channels in the file, using internal_name in FrameBuffer objects
  23. // to read the channel
  24. //
  25. //
  26. //-----------------------------------------------------------------------------
  27. #include "ImfForward.h"
  28. #include "ImfNamespace.h"
  29. #include "ImfExport.h"
  30. #include "ImfMultiPartInputFile.h"
  31. #include "ImfChannelList.h"
  32. #include "ImfStringVectorAttribute.h"
  33. #include "ImfStandardAttributes.h"
  34. #include "ImfMultiView.h"
  35. #include <string>
  36. #include <map>
  37. #include <set>
  38. OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
  39. struct MultiViewChannelName{
  40. public:
  41. std::string name; ///< name of channel
  42. std::string view; ///< view for channel
  43. int part_number; ///< part number: updated by SplitChannels
  44. std::string internal_name;///< name used in headers: in singlepart mode, may contain viewname
  45. //return layer for this channel, or "" if no layer
  46. std::string getLayer() const
  47. {
  48. std::size_t q=name.rfind('.');
  49. if( q==name.npos )
  50. {
  51. return "";
  52. }
  53. return name.substr(0,q);
  54. }
  55. std::string getSuffix() const
  56. {
  57. std::size_t q=name.rfind('.');
  58. if( q==name.npos )
  59. {
  60. return name;
  61. }
  62. return name.substr(q+1);
  63. }
  64. };
  65. //
  66. ///\brief assigns individual channels to different parts based on their layer and view name
  67. /// input is an array, list, vector etc of MultiViewChannelName objects
  68. /// on entry, each MultiViewChannelName name/view must be set (view can be empty if not multiview)
  69. ///
  70. /// if singlepart set, then on exit part_number will be zero, and internal_name will have view name inserted
  71. /// otherwise, each channel will be assigned to a different part based on its layer name and view name
  72. ///
  73. /// @param begin pointer to first MultiViewChannelName item
  74. /// @param end pointer to end of MultiViewChannelName item array
  75. /// @return total number of parts required
  76. //
  77. template<typename T> inline int
  78. SplitChannels(const T & begin,const T & end,bool multipart=true,const std::string & heroView=std::string())
  79. {
  80. if(!multipart)
  81. {
  82. for(T i=begin;i!=end;i++)
  83. {
  84. i->part_number=0;
  85. //does this have a view name set?
  86. if(i->view=="")
  87. {
  88. i->internal_name=i->name;
  89. }else{
  90. std::string lname = i->getLayer();
  91. // no layer, only non-hero views get view name in layer name
  92. if(lname=="")
  93. {
  94. if(i->view==heroView)
  95. {
  96. i->internal_name = i->name;
  97. }else{
  98. i->internal_name = i->view+"."+i->name;
  99. }
  100. }else{
  101. i->internal_name = lname+"."+i->view+"."+i->getSuffix();
  102. }
  103. }
  104. }
  105. // single part created
  106. return 1;
  107. }else{
  108. // step 1: extract individual layers and parts
  109. // for each layer, enumerate which views are active
  110. std::map< std::string , std::set< std::string > > viewsInLayers;
  111. for(T i=begin;i!=end;i++)
  112. {
  113. viewsInLayers[i->getLayer()].insert(i->view);
  114. }
  115. // step 2: assign a part number to each layer/view
  116. std::map< std::pair<std::string,std::string> , int > layerToPart;
  117. int partCount=0;
  118. for(std::map< std::string , std::set< std::string > >::const_iterator layer=viewsInLayers.begin();
  119. layer!=viewsInLayers.end();layer++)
  120. {
  121. // if this layer has a heroView, insert that first
  122. bool layer_has_hero = layer->second.find(heroView)!=layer->second.end();
  123. if( layer_has_hero )
  124. {
  125. layerToPart[ std::make_pair(layer->first,heroView) ] = partCount++;
  126. }
  127. // insert other layers which aren't the hero view
  128. for(std::set< std::string >::const_iterator view=layer->second.begin();
  129. view!=layer->second.end();view++)
  130. {
  131. if(*view!=heroView)
  132. {
  133. layerToPart[ std::make_pair(layer->first,*view) ] = partCount++;
  134. }
  135. }
  136. }
  137. // step 3: update part number of each provided channel
  138. for( T i=begin;i!=end;i++)
  139. {
  140. i->internal_name=i->name;
  141. i->part_number = layerToPart[ std::make_pair(i->getLayer(),i->view) ];
  142. }
  143. // return number of parts created
  144. return partCount;
  145. }
  146. }
  147. //
  148. // populate the chans vector<MultiViewChannelName> with a list of channels in the file
  149. // and their corresponding part number
  150. //
  151. template<class T> inline void
  152. GetChannelsInMultiPartFile(const MultiPartInputFile & file,T & chans)
  153. {
  154. bool has_multiview=false;
  155. StringVector mview;
  156. if(file.parts()==1)
  157. {
  158. if(hasMultiView(file.header(0)))
  159. {
  160. mview=multiView(file.header(0));
  161. has_multiview=true;
  162. }
  163. }
  164. for(int p=0;p<file.parts();p++)
  165. {
  166. const ChannelList & c=file.header(p).channels();
  167. std::string view="";
  168. if(file.header(p).hasView())
  169. {
  170. view=file.header(p).view();
  171. }
  172. for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
  173. {
  174. MultiViewChannelName m;
  175. m.name=std::string(i.name());
  176. m.internal_name=m.name;
  177. if(has_multiview)
  178. {
  179. m.view=viewFromChannelName(m.name,mview);
  180. m.name=removeViewName(m.internal_name,m.view);
  181. }else{
  182. m.view=view;
  183. }
  184. m.part_number=p;
  185. chans.push_back(m);
  186. }
  187. }
  188. }
  189. OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
  190. #endif