Blame IlmImf/ImfPartHelper.h

Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
//
Packit 0d464f
// Copyright (c) 2012, Weta Digital Ltd
Packit 0d464f
// 
Packit 0d464f
// All rights reserved.
Packit 0d464f
// 
Packit 0d464f
// Redistribution and use in source and binary forms, with or without
Packit 0d464f
// modification, are permitted provided that the following conditions are
Packit 0d464f
// met:
Packit 0d464f
// *       Redistributions of source code must retain the above copyright
Packit 0d464f
// notice, this list of conditions and the following disclaimer.
Packit 0d464f
// *       Redistributions in binary form must reproduce the above
Packit 0d464f
// copyright notice, this list of conditions and the following disclaimer
Packit 0d464f
// in the documentation and/or other materials provided with the
Packit 0d464f
// distribution.
Packit 0d464f
// *       Neither the name of Weta Digital nor the names of
Packit 0d464f
// its contributors may be used to endorse or promote products derived
Packit 0d464f
// from this software without specific prior written permission. 
Packit 0d464f
// 
Packit 0d464f
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 0d464f
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 0d464f
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 0d464f
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 0d464f
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 0d464f
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 0d464f
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 0d464f
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 0d464f
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 0d464f
//
Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
Packit 0d464f
Packit 0d464f
#ifndef INCLUDED_IMF_PARTHELPER_H
Packit 0d464f
#define INCLUDED_IMF_PARTHELPER_H
Packit 0d464f
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
//
Packit 0d464f
//	Functions to help split channels into separate parts: provide a list of
Packit 0d464f
//      channels, with desired views. call SplitChannels to assign a part to each
Packit 0d464f
//      layer, or correct the name of the channel.
Packit 0d464f
//      Also can enumerate the parts in a file and list which parts channels are in
Packit 0d464f
//
Packit 0d464f
//      This is a good way to offer a 'create Multipart file' checkbox to the user in a
Packit 0d464f
//      write dialog box: Populate a list of MultiViewChannelName objects,
Packit 0d464f
//      call SplitChannels with whether single or multipart files are required.
Packit 0d464f
//      Then write the number of parts it specifies, using internal_name for the channel
Packit 0d464f
//      names in the ChannelList and FrameBuffer objects. There should be no need
Packit 0d464f
//      for different codepaths for single part and multipart files
Packit 0d464f
//
Packit 0d464f
//      Similarly, on reading a file as a MultiPartInputFile, use GetChannelsInMultiPartFile to
Packit 0d464f
//      enumerate all channels in the file, using internal_name in FrameBuffer objects
Packit 0d464f
//      to read the channel
Packit 0d464f
//   
Packit 0d464f
//
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
Packit 0d464f
#include "ImfForward.h"
Packit 0d464f
#include "ImfNamespace.h"
Packit 0d464f
#include "ImfExport.h"
Packit 0d464f
#include "ImfMultiPartInputFile.h"
Packit 0d464f
#include "ImfChannelList.h"
Packit 0d464f
#include "ImfStringVectorAttribute.h"
Packit 0d464f
#include "ImfStandardAttributes.h"
Packit 0d464f
#include "ImfMultiView.h"
Packit 0d464f
Packit 0d464f
#include <string>
Packit 0d464f
#include <map>
Packit 0d464f
#include <set>
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
Packit 0d464f
Packit 0d464f
struct MultiViewChannelName{
Packit 0d464f
  
Packit 0d464f
public:
Packit 0d464f
  std::string name;         ///< name of channel
Packit 0d464f
  std::string view;         ///< view for channel
Packit 0d464f
  
Packit 0d464f
  int part_number;          ///< part number: updated by SplitChannels
Packit 0d464f
  std::string internal_name;///< name used in headers: in singlepart mode, may contain viewname
Packit 0d464f
  
Packit 0d464f
  virtual ~MultiViewChannelName() {}
Packit 0d464f
    
Packit 0d464f
    //return layer for this channel, or "" if no layer
Packit 0d464f
    std::string getLayer() const 
Packit 0d464f
    {
Packit 0d464f
        std::size_t q=name.rfind('.');
Packit 0d464f
	if(  q==name.npos  )
Packit 0d464f
	{
Packit 0d464f
	    return "";
Packit 0d464f
	}
Packit 0d464f
	return name.substr(0,q);
Packit 0d464f
    
Packit 0d464f
  }
Packit 0d464f
Packit 0d464f
  std::string getSuffix() const
Packit 0d464f
  {
Packit 0d464f
        std::size_t q=name.rfind('.');
Packit 0d464f
	if(  q==name.npos  )
Packit 0d464f
	{
Packit 0d464f
	    return name;
Packit 0d464f
	}
Packit 0d464f
	return name.substr(q+1);
Packit 0d464f
      
Packit 0d464f
  }
Packit 0d464f
  
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
///\brief assigns individual channels to different parts based on their layer and view name
Packit 0d464f
///       input is an array, list, vector etc of MultiViewChannelName objects
Packit 0d464f
///       on entry, each MultiViewChannelName name/view must be set (view can be empty if not multiview)
Packit 0d464f
///
Packit 0d464f
///       if singlepart set, then on exit part_number will be zero, and internal_name will have view name inserted
Packit 0d464f
///       otherwise, each channel will be assigned to a different part based on its layer name and view name
Packit 0d464f
///
Packit 0d464f
/// @param begin pointer to first MultiViewChannelName item
Packit 0d464f
/// @param end   pointer to end of MultiViewChannelName item array
Packit 0d464f
/// @return      total number of parts required
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
template<typename T> int 
Packit 0d464f
SplitChannels(const T & begin,const T & end,bool multipart=true,const std::string & heroView="")
Packit 0d464f
{
Packit 0d464f
    if(!multipart)
Packit 0d464f
    {
Packit 0d464f
	for(T i=begin;i!=end;i++)
Packit 0d464f
	{
Packit 0d464f
	    i->part_number=0;
Packit 0d464f
	
Packit 0d464f
	    //does this have a view name set?
Packit 0d464f
	    if(i->view=="")
Packit 0d464f
	    {
Packit 0d464f
		i->internal_name=i->name;
Packit 0d464f
	    }else{
Packit 0d464f
		
Packit 0d464f
		std::string lname = i->getLayer();
Packit 0d464f
	   
Packit 0d464f
		// no layer, only non-hero views get view name in layer name
Packit 0d464f
	
Packit 0d464f
	    
Packit 0d464f
		if(lname=="")
Packit 0d464f
		{
Packit 0d464f
		    if(i->view==heroView)
Packit 0d464f
		    {
Packit 0d464f
			i->internal_name = i->name;
Packit 0d464f
		    }else{
Packit 0d464f
			i->internal_name = i->view+"."+i->name;
Packit 0d464f
		    }
Packit 0d464f
		}else{
Packit 0d464f
		    i->internal_name = lname+"."+i->view+"."+i->getSuffix();
Packit 0d464f
		}
Packit 0d464f
	    }
Packit 0d464f
	}
Packit 0d464f
	// single part created
Packit 0d464f
	return 1;
Packit 0d464f
    }else{
Packit 0d464f
	// step 1: extract individual layers and parts
Packit 0d464f
	// for each layer, enumerate which views are active
Packit 0d464f
	
Packit 0d464f
	std::map< std::string , std::set< std::string > > viewsInLayers;
Packit 0d464f
	for(T i=begin;i!=end;i++)
Packit 0d464f
	{
Packit 0d464f
	    viewsInLayers[i->getLayer()].insert(i->view);
Packit 0d464f
	}
Packit 0d464f
	
Packit 0d464f
	// step 2: assign a part number to each layer/view
Packit 0d464f
	
Packit 0d464f
	std::map< std::pair<std::string,std::string> , int > layerToPart;
Packit 0d464f
	
Packit 0d464f
	int partCount=0;
Packit 0d464f
	
Packit 0d464f
	for(std::map< std::string , std::set< std::string > >::const_iterator layer=viewsInLayers.begin();
Packit 0d464f
	    layer!=viewsInLayers.end();layer++)
Packit 0d464f
	{
Packit 0d464f
	    // if this layer has a heroView, insert that first
Packit 0d464f
	    bool layer_has_hero = layer->second.find(heroView)!=layer->second.end();
Packit 0d464f
	    if( layer_has_hero )
Packit 0d464f
	    {
Packit 0d464f
		layerToPart[ std::make_pair(layer->first,heroView) ] = partCount++;
Packit 0d464f
	    }
Packit 0d464f
	    
Packit 0d464f
	    
Packit 0d464f
	    // insert other layers which aren't the hero view
Packit 0d464f
	    for(std::set< std::string >::const_iterator view=layer->second.begin();
Packit 0d464f
		view!=layer->second.end();view++)
Packit 0d464f
	    {
Packit 0d464f
		if(*view!=heroView)
Packit 0d464f
		{
Packit 0d464f
		    layerToPart[ std::make_pair(layer->first,*view) ] = partCount++;
Packit 0d464f
		}
Packit 0d464f
	    }
Packit 0d464f
		
Packit 0d464f
	}
Packit 0d464f
	
Packit 0d464f
	// step 3: update part number of each provided channel
Packit 0d464f
	
Packit 0d464f
	for( T i=begin;i!=end;i++)
Packit 0d464f
	{
Packit 0d464f
	    i->internal_name=i->name;
Packit 0d464f
	    i->part_number = layerToPart[ std::make_pair(i->getLayer(),i->view) ];
Packit 0d464f
	}
Packit 0d464f
	
Packit 0d464f
	
Packit 0d464f
	// return number of parts created
Packit 0d464f
	return partCount;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// populate the chans vector<MultiViewChannelName> with a list of channels in the file
Packit 0d464f
// and their corresponding part number
Packit 0d464f
//
Packit 0d464f
template<class T> void
Packit 0d464f
GetChannelsInMultiPartFile(const MultiPartInputFile & file,T & chans)
Packit 0d464f
{
Packit 0d464f
    bool has_multiview=false;
Packit 0d464f
    StringVector mview; 
Packit 0d464f
    if(file.parts()==1)
Packit 0d464f
    {
Packit 0d464f
	if(hasMultiView(file.header(0)))
Packit 0d464f
	{
Packit 0d464f
	    mview=multiView(file.header(0));
Packit 0d464f
	    has_multiview=true;
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    for(int p=0;p
Packit 0d464f
    {
Packit 0d464f
	const ChannelList & c=file.header(p).channels();
Packit 0d464f
	
Packit 0d464f
	std::string view="";
Packit 0d464f
	if(file.header(p).hasView())
Packit 0d464f
	{
Packit 0d464f
	    view=file.header(p).view();
Packit 0d464f
	}
Packit 0d464f
	for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
Packit 0d464f
	{
Packit 0d464f
	    MultiViewChannelName m;
Packit 0d464f
            m.name=std::string(i.name());
Packit 0d464f
	    m.internal_name=m.name;
Packit 0d464f
Packit 0d464f
	    if(has_multiview)
Packit 0d464f
	    {
Packit 0d464f
		m.view=viewFromChannelName(m.name,mview);
Packit 0d464f
		m.name=removeViewName(m.internal_name,m.view);
Packit 0d464f
	    }else{
Packit 0d464f
		m.view=view;
Packit 0d464f
	    }
Packit 0d464f
            m.part_number=p;
Packit 0d464f
	    chans.push_back(m);
Packit 0d464f
		
Packit 0d464f
	}
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
Packit 0d464f
Packit 0d464f
#endif