void ColorSpaceTransformOp::modifyTypedPrimitive( ImagePrimitive * image, const CompoundObject * operands )
{
	const InputColorSpace &inputColorSpace = m_inputColorSpaceParameter->getTypedValue();
	const OutputColorSpace &outputColorSpace = m_outputColorSpaceParameter->getTypedValue();

	if ( inputColorSpace == outputColorSpace )
	{
		return;
	}

	std::vector< ConversionInfo > conversions;
	findConversion( inputColorSpace, outputColorSpace, conversions );

	if ( !conversions.size() )
	{
		throw InvalidArgumentException( ( boost::format( "ColorSpaceTransformOp: Cannot find appropriate conversion from '%s' to '%s'" ) % inputColorSpace % outputColorSpace ).str() );
	}

	std::vector< std::string > channelNames;
	typedef std::vector< std::vector< std::string > > ChannelSets;
	ChannelSets channelSets;
	std::vector< std::string > channels;

	for ( std::vector< std::string >::const_iterator it = channelsParameter()->getTypedValue().begin(); it != channelsParameter()->getTypedValue().end(); ++it )
	{
		const std::string &channelName = *it;

		channelNames.push_back( channelName );

		PrimitiveVariableMap::iterator channelIt = image->variables.find( channelName );
		if( channelIt==image->variables.end() || !(channelIt->second.data) )
		{
			throw Exception( str( format( "Channel \"%s\" does not exist." ) % channelName ) );
		}

		TypeId type = channelIt->second.data->typeId();

		if ( type == Color3fVectorDataTypeId || type == Color3dVectorDataTypeId )
		{
			// color data types define the three channels.

			if ( channels.size() )
			{
				/// silently ignores malformed sets.
				channels.clear();
			}
			channels.push_back( channelName );
			channelSets.push_back( channels );
			channels.clear();
		}
		else
		{
			// simple data types are assigned to one image channel.

			channels.push_back( channelName );

			if ( channels.size() == 3 )
			{
				channelSets.push_back( channels );
				channels.clear();
			}
		}
	}

	bool first = true;
	ConversionInfo previous;
	ConversionInfo current;
	for( std::vector< ConversionInfo >::const_iterator it = conversions.begin() ; it != conversions.end(); ++it )
	{
		current = *it;


		if ( first )
		{
			assert( current.get<1>() == inputColorSpace );
			first = false;
		}
		else
		{
			assert( previous.get<2>() == current.get<1>() );
		}
		ModifyOpPtr currentConversion = (*current.get<0>())( current.get<1>(), current.get<2>() );
		assert( currentConversion );

		if ( !currentConversion->isInstanceOf( ChannelOpTypeId ) && !currentConversion->isInstanceOf( ColorTransformOpTypeId ) )
		{
			throw InvalidArgumentException( ( boost::format( "ColorSpaceTransformOp: '%s' to '%s' conversion registered unsupported Op type '%s'" ) % inputColorSpace % outputColorSpace % currentConversion->typeName()).str() );
		}

		currentConversion->inputParameter()->setValue( image );
		currentConversion->copyParameter()->setTypedValue( false );

		ImagePrimitivePtr result = 0;
		if ( currentConversion->isInstanceOf( ChannelOpTypeId )	)
		{
			// The channel Op doesn't handle any unpremultiplication of the colour channels.
			// So we apply an unpremult before and a premult after, if premultiplied is on and alpha exists
			if( premultipliedParameter()->getTypedValue() )
			{
				std::string alphaPrimVar = alphaPrimVarParameter()->getTypedValue();
				if( image->variables.find( alphaPrimVar ) != image->variables.end() )
				{
					ImageUnpremultiplyOpPtr unpremultOp = new ImageUnpremultiplyOp();
					unpremultOp->alphaChannelNameParameter()->setTypedValue( alphaPrimVar );
					unpremultOp->channelNamesParameter()->setTypedValue( channelNames );
					unpremultOp->copyParameter()->setTypedValue( false );
					unpremultOp->inputParameter()->setValue( image );
					unpremultOp->operate();
				}
			}

			
			ChannelOpPtr op = assertedStaticCast< ChannelOp >( currentConversion );
			op->channelNamesParameter()->setTypedValue( channelNames );
			result = runTimeCast< ImagePrimitive >( op->operate() );
			
			if( premultipliedParameter()->getTypedValue() )
			{
				std::string alphaPrimVar = alphaPrimVarParameter()->getTypedValue();
				if( result->variables.find( alphaPrimVar ) != result->variables.end() )
				{
					ImagePremultiplyOpPtr premultOp = new ImagePremultiplyOp();
					premultOp->alphaChannelNameParameter()->setTypedValue( alphaPrimVar );
					premultOp->channelNamesParameter()->setTypedValue( channelNames );
					premultOp->copyParameter()->setTypedValue( false );
					premultOp->inputParameter()->setValue( result );
					premultOp->operate();
				}
			}
		}
		else
		{
			assert( currentConversion->isInstanceOf( ColorTransformOpTypeId ) );

			ColorTransformOpPtr op = boost::dynamic_pointer_cast< ColorTransformOp >( currentConversion );

			for ( ChannelSets::const_iterator it = channelSets.begin(); it != channelSets.end(); ++it )
			{
				op->inputParameter()->setValue( image );
				op->copyParameter()->setTypedValue( false );

				op->alphaPrimVarParameter()->setValue( alphaPrimVarParameter()->getValue() );
				op->premultipliedParameter()->setValue( premultipliedParameter()->getValue() );

				if ( it->size() == 1 )
				{
					op->colorPrimVarParameter()->setTypedValue( (*it)[0] );

					op->redPrimVarParameter()->setValue( op->redPrimVarParameter()->defaultValue()->copy() );
					op->greenPrimVarParameter()->setValue( op->greenPrimVarParameter()->defaultValue()->copy() );
					op->bluePrimVarParameter()->setValue( op->bluePrimVarParameter()->defaultValue()->copy() );
				}
				else
				{
					assert( it->size() == 3 );

					op->redPrimVarParameter()->setTypedValue( (*it)[0] );
					op->greenPrimVarParameter()->setTypedValue( (*it)[1] );
					op->bluePrimVarParameter()->setTypedValue( (*it)[2] );

					op->colorPrimVarParameter()->setValue( op->colorPrimVarParameter()->defaultValue()->copy() );

				}
				result = runTimeCast< ImagePrimitive >( op->operate() );
				assert( result.get() == image );
			}
		}

		assert( result.get() == image );
		( void ) result;

		previous = current;

	}
	assert( current.get<2>() == outputColorSpace );
}
Exemplo n.º 2
0
		// static function used by the cache mechanism to actually load the object data from file.
		static ObjectPtr computeFn( const ComputeParameters &params )
		{
			const std::string &filePath = params.first;
			MemberData *data = params.second;

			{
				/// Check if the file failed before...
				FileErrors::const_accessor cit;
				if ( data->m_fileErrors.find( cit, filePath ) )
				{
					throw Exception( ( format( "Previous attempt to read %s failed: %s" ) % filePath % cit->second ).str() );
				}
			}

			ObjectPtr result(0);
			try
			{
				path resolvedPath = data->m_searchPaths.find( filePath );
				if( resolvedPath.empty() )
				{
					string pathList;
					for( list<path>::const_iterator it =  data->m_searchPaths.paths.begin(); it!= data->m_searchPaths.paths.end(); it++ )
					{
						if ( pathList.size() > 0 )
						{
							pathList += ":" + it->string();
						}
						else
						{
							pathList = it->string();
						}
					}
					throw Exception( "Could not find file '" + filePath + "' at the following paths: " + pathList );
				}
	
				ReaderPtr r = Reader::create( resolvedPath.string() );
				if( !r )
				{
					throw Exception( "Could not create reader for '" + resolvedPath.string() + "'" );
				}
		
				result = r->read();
				/// \todo Why would this ever be NULL? Wouldn't we have thrown an exception already if
				/// we were unable to read the file?
				if( !result )
				{
					throw Exception( "Reader for '" + resolvedPath.string() + "' returned no data" );
				}
		
				if( data->m_postProcessor )
				{
					/// \todo We need to allow arguments to be passed to Op::operate() directly
					/// so that the same Op can be used from multiple threads with different arguments.
					/// This means adding an overloaded operate() method but more importantly making sure
					/// that all Ops only use their operands to access arguments and not go getting them
					/// from the Parameters directly.
					tbb::mutex::scoped_lock l( data->m_postProcessorMutex );
					ModifyOpPtr postProcessor = constPointerCast<ModifyOp>( data->m_postProcessor );
					postProcessor->inputParameter()->setValue( result );
					postProcessor->copyParameter()->setTypedValue( false );
					postProcessor->operate();
				}
			}
			catch ( std::exception &e )
			{
				data->registerFileError( filePath, e.what() );
				throw;
			}
			catch ( ... )
			{
				data->registerFileError( filePath, "Unexpected error." );
				throw;
			}
			return result;
		}