Пример #1
0
DataPtr JPEGImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, int channelOffset )
{
	int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
	assert( area >= 0 );
	int dataWidth = 1 + dataWindow.size().x;
	int dataY = 0;

	typedef TypedData< std::vector< V > > TargetVector;
	
	typename TargetVector::Ptr dataContainer = new TargetVector();
	typename TargetVector::ValueType &data = dataContainer->writable();
	data.resize( area );

	ScaledDataConversion< unsigned char, V> converter;

	for ( int y = dataWindow.min.y; y <= dataWindow.max.y; ++y, ++dataY )
	{
		typename TargetVector::ValueType::size_type dataOffset = dataY * dataWidth;
		for ( int x = dataWindow.min.x; x <= dataWindow.max.x; ++x, ++dataOffset )
		{
			assert( dataOffset < data.size() );
			data[dataOffset] = converter( m_buffer[ m_numChannels * ( y * m_bufferWidth + x ) + channelOffset ] );
		}
	}
	return dataContainer;
}
Пример #2
0
void exposure_node_t::do_process( const image::const_image_view_t& src, const image::image_view_t& dst, const render::render_context_t& context)
{
    image::const_image_view_t src_view;
    image::image_view_t dst_view;
    Imath::Box2i area;

    if( input(1))
    {
	boost::gil::copy_pixels( src, dst);
	area = intersect( input(1)->defined(), defined());

	if( area.isEmpty())
	    return;

	src_view = input(0)->const_subimage_view( area);
	dst_view = subimage_view( area);
    }
    else
    {
	src_view = src;
	dst_view = dst;
    }

    boost::gil::tbb_transform_pixels( src_view, dst_view, exposure_fun( get_value<float>( param( "exp"))));

    if( input(1))
        image::key_mix( src_view, dst_view, boost::gil::nth_channel_view( input(1)->const_subimage_view( area), 3), dst_view);
}
Пример #3
0
void layer_node_t::do_calc_bounds( const render::context_t& context)
{
    Imath::Box2i bbox;

    float opacity = get_value<float>( param( "opacity"));

    if( opacity == 1.0f)
    {
        switch( get_value<int>( param( "layer_mode")))
        {
        case comp_mult:
        case comp_min:
        case comp_mix:
            bbox = ImathExt::intersect( input_as<image_node_t>( 0)->bounds(), input_as<image_node_t>( 1)->bounds());
        break;

        case comp_sub:
            bbox = input_as<image_node_t>( 0)->bounds();
        break;

        default:
            bbox = input_as<image_node_t>( 0)->bounds();
            bbox.extendBy( input_as<image_node_t>( 1)->bounds());
        }
    }
    else
    {
        bbox = input_as<image_node_t>( 0)->bounds();
        bbox.extendBy( input_as<image_node_t>( 1)->bounds());
    }

    set_bounds( bbox);
}
Пример #4
0
void expand_node_t::do_process( const render::context_t& context)
{
    Imath::Box2i area = ImathExt::intersect( input_as<image_node_t>()->defined(), defined());

    if( area.isEmpty())
        return;

    boost::gil::copy_pixels( input_as<image_node_t>()->const_subimage_view( area), subimage_view( area));
}
Пример #5
0
void crop_node_t::do_process( const render::render_context_t& context)
{
    Imath::Box2i area = intersect( input()->defined(), defined());

    if( area.isEmpty())
	return;

    boost::gil::copy_pixels( input()->const_subimage_view( area), subimage_view( area));
}
Пример #6
0
Imath::Box2i CopyChannels::computeDataWindow( const Gaffer::Context *context, const ImagePlug *parent ) const
{
	Imath::Box2i dataWindow;
	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it )
	{
		dataWindow.extendBy( (*it)->dataWindowPlug()->getValue() );
	}

	return dataWindow;
}
Пример #7
0
Imath::Box2i Merge::computeDataWindow( const Gaffer::Context *context, const ImagePlug *parent ) const
{
	Imath::Box2i dataWindow;
	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it )
	{
		// We don't need to check that the plug is connected here as unconnected plugs don't have data windows.
		dataWindow.extendBy( (*it)->dataWindowPlug()->getValue() );
	}

	return dataWindow;
}
Пример #8
0
void ImageStats::compute( ValuePlug *output, const Context *context ) const
{
	const int colorIndex = ::colorIndex( output );
	if( colorIndex == -1 )
	{
		// Not a plug we know about
		ComputeNode::compute( output, context );
		return;
	}

	const std::string channelName = this->channelName( colorIndex );
	const Imath::Box2i area = areaPlug()->getValue();

	if( channelName.empty() || BufferAlgo::empty( area ) )
	{
		output->setToDefault();
		return;
	}

	// Loop over the ROI and compute the min, max and average channel values and then set our outputs.
	Sampler s( inPlug(), channelName, area );

	float min = Imath::limits<float>::max();
	float max = Imath::limits<float>::min();
	double sum = 0.;

	for( int y = area.min.y; y < area.max.y; ++y )
	{
		for( int x = area.min.x; x < area.max.x; ++x )
		{
			float v = s.sample( x, y );
			min = std::min( v, min );
			max = std::max( v, max );
			sum += v;
		}
	}

	if( output->parent<Plug>() == minPlug() )
	{
		static_cast<FloatPlug *>( output )->setValue( min );
	}
	else if( output->parent<Plug>() == maxPlug() )
	{
		static_cast<FloatPlug *>( output )->setValue( max );
	}
	else if( output->parent<Plug>() == averagePlug() )
	{
		static_cast<FloatPlug *>( output )->setValue(
			sum / double( (area.size().x) * (area.size().y) )
		);
	}
}
Пример #9
0
void make_color_bars( const image_view_t& view, const Imath::Box2i& domain, const Imath::Box2i& defined)
{
    typedef detail::color_bars_fn deref_t;
    typedef deref_t::point_t point_t;
    typedef boost::gil::virtual_2d_locator<deref_t,false> locator_t;
    typedef boost::gil::image_view<locator_t> my_virt_view_t;

    point_t dims( domain.size().x+1, domain.size().y+1);
    my_virt_view_t bars( dims, locator_t( point_t(0,0), point_t(1,1), deref_t( dims)));

    boost::gil::copy_pixels( boost::gil::subimage_view( bars, defined.min.x - domain.min.x,
								defined.min.y - domain.min.y,
								defined.size().x+1, defined.size().y+1), view);
}
Пример #10
0
image_t *clip_t::get_output_image( OfxTime time, OfxRectD *optionalBounds)
{
    RAMEN_ASSERT( node());
    RAMEN_ASSERT( node()->composition());
    RAMEN_ASSERT( !node()->image_empty());
    RAMEN_ASSERT( time == node()->composition()->frame());
    RAMEN_ASSERT( getComponents() == kOfxImageComponentRGBA);
    RAMEN_ASSERT( getPixelDepth() == kOfxBitDepthFloat);

    Imath::Box2i area;

    if( optionalBounds)
    {
        area = Imath::Box2i( Imath::V2i( optionalBounds->x1, optionalBounds->y1), Imath::V2i( optionalBounds->x2 - 1, optionalBounds->y2 - 1));
        area = Imath::scale( area, 1.0f / node()->render_context().subsample);
        area = node()->vertical_flip( area);
    }
    else
        area = node()->defined();

    if( area.isEmpty())
    {
#ifndef NDEBUG
        DLOG( INFO) << "clip_t::getOutputImage, node = " << node()->name() << ", area == empty";
#endif

        return 0;
    }

    image::const_image_view_t view( node()->const_subimage_view( area));

    int rowbytes;
    void *ptr = view_get_ptr_and_stride( view, rowbytes);

    // convert to OFX coordinate sys
    area = node()->vertical_flip( area);

    OfxRectI bounds;
    bounds.x1 = area.min.x;
    bounds.y1 = area.min.y;
    bounds.x2 = area.max.x + 1;
    bounds.y2 = area.max.y + 1;

#ifndef NDEBUG
    DLOG( INFO) << "clip_t::getOutputImage, node = " << node()->name();
#endif

    return new image_t( *this, node()->image(), 1.0 / node()->render_context().subsample, ptr, bounds, bounds, rowbytes, std::string( ""));
}
Пример #11
0
Imath::M33f Transform2DPlug::matrix( const Imath::Box2i &displayWindow, double pixelAspect ) const
{
	// We need to transform from image space (with 0x0 being the bottom left)
	// to Gadget space (where 0x0 is the top left). To do this, we need to know the
	// size of the Format.
	
	///\todo: We don't handle the pixel aspect of the format here but we should!
	float formatHeight = displayWindow.size().y + 1;
	
	M33f p;
	V2f pivotVec = pivotPlug()->getValue();
	pivotVec.y = formatHeight - pivotVec.y;
	p.translate( pivotVec );
	
	M33f t;
	V2f translateVec = translatePlug()->getValue();
	translateVec.y *= -1.;
	t.translate( translateVec );
	
	M33f r;
	r.rotate( IECore::degreesToRadians( rotatePlug()->getValue() ) );
	M33f s;
	s.scale( scalePlug()->getValue() );
	
	M33f pi;
	pi.translate( pivotVec*Imath::V2f(-1.f) );
	M33f result = pi * s * r * t * p;

	return result;
}
Пример #12
0
TiledRgbaOutputFile::TiledRgbaOutputFile
    (const char name[],
     int tileXSize,
     int tileYSize,
     LevelMode mode,
     LevelRoundingMode rmode,
     const Imath::Box2i &displayWindow,
     const Imath::Box2i &dataWindow,
     RgbaChannels rgbaChannels,
     float pixelAspectRatio,
     const Imath::V2f screenWindowCenter,
     float screenWindowWidth,
     LineOrder lineOrder,
     Compression compression,
     int numThreads)
:
    _outputFile (0),
    _toYa (0)
{
    Header hd (displayWindow,
	       dataWindow.isEmpty()? displayWindow: dataWindow,
	       pixelAspectRatio,
	       screenWindowCenter,
	       screenWindowWidth,
	       lineOrder,
	       compression);

    insertChannels (hd, rgbaChannels, name);
    hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
    _outputFile = new TiledOutputFile (name, hd, numThreads);

    if (rgbaChannels & WRITE_Y)
	_toYa = new ToYa (*_outputFile, rgbaChannels);
}
Пример #13
0
void image_node_renderer_t::render( const Imath::Box2i& roi)
{
	RAMEN_ASSERT( has_context_);
	RAMEN_ASSERT( !roi.isEmpty());

    n_->set_interest( roi);
    breadth_first_inputs_apply( *n_, boost::bind( &image_node_t::calc_inputs_interest_fun, _1, new_context_));
    depth_first_inputs_search(  *n_, boost::bind( &image_node_t::calc_defined_fun, _1, new_context_));
    depth_first_inputs_search(  *n_, boost::bind( &image_node_t::subsample_areas_fun, _1, new_context_));

    if( do_log)
        depth_first_inputs_search( *n_, test_empty_images());

    depth_first_inputs_search( *n_, boost::bind( &node_t::clear_hash, _1));
    depth_first_inputs_search( *n_, boost::bind( &node_t::calc_hash_str, _1, new_context_));

    if( do_log)
        depth_first_inputs_search( *n_, print_areas());

	try
	{
	    n_->recursive_process( new_context_);
		render_done_ = true;
	}
	catch( std::bad_alloc&)
	{
		throw boost::enable_error_info( std::bad_alloc());
	}
}
Пример #14
0
RgbaOutputFile::RgbaOutputFile (const char name[],
				const Imath::Box2i &displayWindow,
				const Imath::Box2i &dataWindow,
				RgbaChannels rgbaChannels,
				float pixelAspectRatio,
				const Imath::V2f screenWindowCenter,
				float screenWindowWidth,
				LineOrder lineOrder,
				Compression compression):
    _outputFile (0)
{
    Header hd (displayWindow,
	       dataWindow.isEmpty()? displayWindow: dataWindow,
	       pixelAspectRatio,
	       screenWindowCenter,
	       screenWindowWidth,
	       lineOrder,
	       compression);

    ChannelList ch;

    if (rgbaChannels & WRITE_R)
	ch.insert ("R", Channel (HALF, 1, 1));
    if (rgbaChannels & WRITE_G)
	ch.insert ("G", Channel (HALF, 1, 1));
    if (rgbaChannels & WRITE_B)
	ch.insert ("B", Channel (HALF, 1, 1));
    if (rgbaChannels & WRITE_A)
	ch.insert ("A", Channel (HALF, 1, 1));

    hd.channels() = ch;
    _outputFile = new OutputFile (name, hd);
}
Пример #15
0
AcesOutputFile::AcesOutputFile
    (const std::string &name,
     const Imath::Box2i &displayWindow,
     const Imath::Box2i &dataWindow,
     RgbaChannels rgbaChannels,
     float pixelAspectRatio,
     const Imath::V2f screenWindowCenter,
     float screenWindowWidth,
     LineOrder lineOrder,
     Compression compression,
     int numThreads)
:
    _data (new Data)
{
    checkCompression (compression);

    Header newHeader (displayWindow,
		      dataWindow.isEmpty()? displayWindow: dataWindow,
		      pixelAspectRatio,
		      screenWindowCenter,
		      screenWindowWidth,
		      lineOrder,
		      compression);

    addChromaticities (newHeader, acesChromaticities());
    addAdoptedNeutral (newHeader, acesChromaticities().white);

    _data->rgbaFile = new RgbaOutputFile (name.c_str(),
					  newHeader,
					  rgbaChannels,
					  numThreads);

    _data->rgbaFile->setYCRounding (7, 6);
}
Пример #16
0
void flipbook_t::set_format( const Imath::Box2i& f, float aspect, int subsample)
{
    RAMEN_ASSERT( !f.isEmpty());

    format_ = ImathExt::scale( f, 1.0f / subsample);
    buffer_ = image::buffer_t( format_, 4);
    aspect_ = aspect;
}
Пример #17
0
void set_matte_node_t::do_process( const render::context_t& context)
{
    if( defined().isEmpty())
	return;

    boost::gil::tbb_transform_pixels( input_as<image_node_t>( 0)->const_subimage_view( defined()), image_view(),
					  copy_rgb_and_clear_alpha());

    Imath::Box2i area = ImathExt::intersect( defined(), input_as<image_node_t>( 1)->defined());

    if( !area.isEmpty())
	boost::gil::tbb_copy_pixels( boost::gil::nth_channel_view( input_as<image_node_t>( 1)->const_subimage_view( area), 3),
					    boost::gil::nth_channel_view( subimage_view( area), 3));

    if( get_value<bool>( param( "premultiply")))
	image::premultiply( image_view(), image_view());
}
Пример #18
0
Imath::Box2i Mix::computeDataWindow( const Gaffer::Context *context, const ImagePlug *parent ) const
{
	const float mix = mixPlug()->getValue();
	if( mix == 0.0f )
	{
		return inPlugs()->getChild< ImagePlug>( 0 )->dataWindowPlug()->getValue();
	}
	else if( mix == 1.0f && !maskPlug()->getInput<ValuePlug>() )
	{
		return inPlugs()->getChild< ImagePlug >( 1 )->dataWindowPlug()->getValue();
	}

	Imath::Box2i dataWindow;
	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it )
	{
		// We don't need to check that the plug is connected here as unconnected plugs don't have data windows.
		dataWindow.extendBy( (*it)->dataWindowPlug()->getValue() );
	}

	return dataWindow;
}
Пример #19
0
void keyer_node_t::sample_input( const Imath::Box2i& area, std::vector<Imath::Color3f>& colors) const
{
	if( input_pixels_.empty())
		return;

	Imath::Box2i subarea = Imath::intersect( area, input_data_window_);

	if( subarea.isEmpty())
		return;

	Imath::V2i p;
	
	for( p.y = subarea.min.y; p.y <= subarea.max.y; ++p.y)
	{
		for( p.x = subarea.min.x; p.x <= subarea.max.x; ++p.x)
		{
			image::pixel_t px( input_pixels_.const_rgba_view()( p.x - input_data_window_.min.x, p.y - input_data_window_.min.y));
			colors.push_back( Imath::Color3f( boost::gil::get_color( px, boost::gil::red_t()),
											   boost::gil::get_color( px, boost::gil::green_t()),
											   boost::gil::get_color( px, boost::gil::blue_t())));
		}
	}
}
Пример #20
0
void copy_channels_node_t::do_calc_bounds( const render::render_context_t& context)
{
    Imath::Box2i rod1 = input(0)->bounds();
    Imath::Box2i rod2 = input(1)->bounds();

    int ch_r = get_value<int>( param( "red"));
    int ch_g = get_value<int>( param( "green"));
    int ch_b = get_value<int>( param( "blue"));
    int ch_a = get_value<int>( param( "alpha"));

    // use alpha from input 1
    if( ch_a == copy_source)
    {
	set_bounds( rod1);
	return;
    }

    // alpha comes from input2
    if( ch_a != set_one && ch_a != set_zero)
    {
	set_bounds( rod2);
	return;
    }

    // alpha is zero or one, look at the other channels
    Imath::Box2i rod;

    if( ch_r == copy_source)
	rod = rod1;
    else
    {
	if( ch_r != set_zero && ch_r != set_one)
	    rod = rod2;
    }

    if( ch_g == copy_source)
	rod.extendBy( rod1);
    else
    {
	if( ch_g != set_zero && ch_r != set_one)
	    rod.extendBy( rod2);
    }

    if( ch_b == copy_source)
	rod.extendBy( rod1);
    else
    {
	if( ch_b != set_zero && ch_r != set_one)
	    rod.extendBy( rod2);
    }

    if( rod.isEmpty())
	rod = rod1;

    set_bounds( rod);
}
Пример #21
0
void copy_channels_node_t::do_calc_defined( const render::render_context_t& context)
{
    Imath::Box2i def1 = input(0)->defined();
    Imath::Box2i def2 = input(1)->defined();

    int ch_r = get_value<int>( param( "red"));
    int ch_g = get_value<int>( param( "green"));
    int ch_b = get_value<int>( param( "blue"));
    int ch_a = get_value<int>( param( "alpha"));

    // use alpha from input 1
    if( ch_a == copy_source)
    {
	set_defined( def1);
	return;
    }

    // alpha comes from input2
    if( ch_a != set_one && ch_a != set_zero)
    {
	set_defined( def2);
	return;
    }

    // alpha is zero or one, look at the other channels
    Imath::Box2i def;

    if( ch_r == copy_source)
	def = def1;
    else
    {
	if( ch_r != set_zero && ch_r != set_one)
	    def = def2;
    }

    if( ch_g == copy_source)
	def.extendBy( def1);
    else
    {
	if( ch_g != set_zero && ch_r != set_one)
	    def.extendBy( def2);
    }

    if( ch_b == copy_source)
	def.extendBy( def1);
    else
    {
	if( ch_b != set_zero && ch_r != set_one)
	    def.extendBy( def2);
    }

    if( def.isEmpty())
	def = def1;

    set_defined( def);
}
Пример #22
0
		virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize )
		{
			Box2i yUpBox = m_gafferFormat.yDownToFormatSpace( box );
			const V2i boxMinTileOrigin = ImagePlug::tileOrigin( yUpBox.min );
			const V2i boxMaxTileOrigin = ImagePlug::tileOrigin( yUpBox.max );
			for( int tileOriginY = boxMinTileOrigin.y; tileOriginY <= boxMaxTileOrigin.y; tileOriginY += ImagePlug::tileSize() )
			{
				for( int tileOriginX = boxMinTileOrigin.x; tileOriginX <= boxMaxTileOrigin.x; tileOriginX += ImagePlug::tileSize() )
				{
					for( int channelIndex = 0, numChannels = channelNames().size(); channelIndex < numChannels; ++channelIndex )
					{
						const V2i tileOrigin( tileOriginX, tileOriginY );
						ConstFloatVectorDataPtr tileData = getTile( tileOrigin, channelIndex );
						if( !tileData )
						{
							// we've been sent data outside of the data window
							continue;
						}

						// we must create a new object to hold the updated tile data,
						// because the old one might well have been returned from
						// computeChannelData and be being held in the cache.
						FloatVectorDataPtr updatedTileData = tileData->copy();
						vector<float> &updatedTile = updatedTileData->writable();

						const Box2i tileBound( tileOrigin, tileOrigin + Imath::V2i( GafferImage::ImagePlug::tileSize() - 1 ) );
						const Box2i transferBound = IECore::boxIntersection( tileBound, yUpBox );
						for( int y = transferBound.min.y; y<=transferBound.max.y; ++y )
						{
							int srcY = m_gafferFormat.formatToYDownSpace( y );
							size_t srcIndex = ( ( srcY - box.min.y ) * ( box.size().x + 1 ) * numChannels ) + ( transferBound.min.x - box.min.x ) + channelIndex;
							size_t dstIndex = ( y - tileBound.min.y ) * ImagePlug::tileSize() + transferBound.min.x - tileBound.min.x;
							const size_t srcEndIndex = srcIndex + transferBound.size().x * numChannels;
							while( srcIndex <= srcEndIndex )
							{
								updatedTile[dstIndex] = data[srcIndex];
								srcIndex += numChannels;
								dstIndex++;
							}
						}

						setTile( tileOrigin, channelIndex, updatedTileData );
					}
				}
			}

			dataReceivedSignal()( this, box );
		}
Пример #23
0
// All the work is done here
int joinEXRs( int tilesX, int tilesY, const char* baseName, bool deleteTiles, bool Verbose )
{
   int exitCode = 0;

   // Expand names
   if( Verbose ) printf("Image file name = '%s', tilesX=%d, tilesY=%d\n", baseName, tilesX, tilesY);
   int numTiles = tilesX * tilesY;

   // Allocate memory:
   char ** tileNames = new char * [numTiles];
   Imf::InputFile ** iFiles = new Imf::InputFile * [numTiles];
   for( int i = 0; i < numTiles; i++)
   {
      tileNames[i] = new char[FILENAME_MAXLEN];
      iFiles[i] = 0;
   }

   // Insert tile info and check if files exist
   int nonEmptyTile = -1;
   struct stat stFileInfo;

   for( int i = 0; i < numTiles; i++)
   {
      sprintf( tileNames[i], "%s.tile_%d.exr", baseName, i);
      if( Verbose ) printf("Tile name  %d = '%s'\n", i, tileNames[i]);

      if( stat( tileNames[i], &stFileInfo ) == 0 )
      {
         // File exists - so open it and check for validness
         iFiles[i] = new Imf::InputFile( tileNames[i]);
         if( false == iFiles[i]->isComplete())
         {
            fprintf( stderr, "Error: File '%s' is incomplete or is not an OpenEXR file.\n", tileNames[i]); fflush( stderr);
            delete iFiles[i];
            iFiles[i] = 0;
            exitCode = 1;
         }
         else if( nonEmptyTile == -1 )
         {
            nonEmptyTile = i;
         }
      }
      else
      {
         fprintf( stderr, "Error: File '%s' not founded.\n", tileNames[i]); fflush( stderr);
         exitCode = 1;
      }
   }

   if( nonEmptyTile < 0) // All tiles were empty
   {
      fprintf( stderr, "Error: No tile files founded.\n"); fflush( stderr);
   }
   else
   {
   // Gather info from a non-empty tile file
   Imf::Header inHeader = iFiles[nonEmptyTile]->header();
   Imath::Box2i imageBox = inHeader.displayWindow(); // size of the resulting image
   int imageWidth = imageBox.max.x - imageBox.min.x + 1;
   int imageHeight = imageBox.max.y - imageBox.min.y + 1;

   // Iterate through all the channels and reserve mem for the whole display window
   // also add channels to the header of the output file
   Imf::Header outHeader( imageWidth, imageHeight);
   std::map< Imf::Name, ChannelInfo* > chInfos; // this will hold pixel data and stride for each channel in input files
   Imf::ChannelList channels = inHeader.channels();
   Imf::ChannelList::ConstIterator itCh;
   for( itCh = channels.begin(); itCh != channels.end(); itCh++ )
   {
      chInfos[itCh.name()] = new ChannelInfo( typeSize( itCh.channel().type), imageHeight, imageWidth );
      outHeader.channels().insert( itCh.name(), Imf::Channel( itCh.channel().type));
      if( Verbose) printf("Channel: '%s' | stride: %d\n", itCh.name(), typeSize( itCh.channel().type));
   }

   // Collect data from files
   Imath::Box2i tileBox;      // each tile's data window
   Imath::Box2i resultBox;    // resulting data window (should be sum of all tiles' data windows)
   Imf::FrameBuffer fb;
   for( int i = 0; i < numTiles; i++)
   {
      if( iFiles[i] == 0) // no file for this tile
         continue;

      tileBox = iFiles[i]->header().dataWindow();
      resultBox.extendBy( tileBox );

      if( Verbose) printf("Data win: xmin=%d xmax=%d ymin=%d ymax=%d\n", tileBox.min.x, tileBox.max.x, tileBox.min.y, tileBox.max.y);

      channels = iFiles[i]->header().channels();
      for( itCh = channels.begin(); itCh != channels.end(); itCh++ )
         fb.insert( itCh.name(),
                    Imf::Slice( itCh.channel().type,                // pixel type
                    (char*)&chInfos[itCh.name()]->array2d[0][0],    // base
                    chInfos[itCh.name()]->stride,                   // x stride
                    chInfos[itCh.name()]->stride * imageWidth,      // y stride
                    1, 1, 0.0 ) );                                  // x,y sampling, fill value

      iFiles[i]->setFrameBuffer(fb);
      iFiles[i]->readPixels( tileBox.min.y, tileBox.max.y);
   }

   // Write out everything:
   outHeader.dataWindow() = resultBox;
   Imf::OutputFile imageFile( baseName, outHeader );
   imageFile.setFrameBuffer(fb);
   imageFile.writePixels( resultBox.max.y-resultBox.min.y+1 );

   printf("Joined EXR image successfully written.\n");

   // Free files:
   for( int i = 0; i < numTiles; i++)
      if( iFiles[i] != 0 ) delete iFiles[i];
   delete [] iFiles;

   if( deleteTiles )
   {
      for( int i = 0; i < numTiles; i++)
         if( unlink( tileNames[i]) != 0)
         {
            perror("Remove");
            printf("Can't remove file '%s'\n", tileNames[i]);
         }
   }
   }

   // Free names:
   for( int i = 0; i < numTiles; i++)
      delete [] tileNames[i];
   delete [] tileNames;

   return exitCode;
}
Пример #24
0
DataPtr CINImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow )
{
	typedef TypedData< std::vector< V > > TargetVector;

	// figure out the offset into the bitstream for the given channel
	assert( m_header->m_channelOffsets.find( name ) != m_header->m_channelOffsets.end() );
	int channelOffset = m_header->m_channelOffsets[name];

	assert( (int)m_header->m_imageInformation.channel_information[channelOffset].bpp == 10 );
	int bpp = m_header->m_imageInformation.channel_information[channelOffset].bpp;
	// todo: make sure ushort is enough for the current bpp
	int ushortShift = sizeof(unsigned short)*8 - bpp;

	// form the mask for this channel
	unsigned int mask = 0;
	for (int pi = 0; pi < bpp; ++pi)
	{
		mask = 1 + (mask << 1);
	}
	mask <<= ((32 - bpp) - channelOffset * bpp);

	ScaledDataConversion< unsigned short, V> converter;

	typename TargetVector::Ptr dataContainer = new TargetVector();
	typename TargetVector::ValueType &data = dataContainer->writable();
	int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
	assert( area >= 0 );
	data.resize( area );

	int dataWidth = 1 + dataWindow.size().x;

	Box2i wholeDataWindow = this->dataWindow();

	const int yMin = dataWindow.min.y - wholeDataWindow.min.y;
	const int yMax = dataWindow.max.y - wholeDataWindow.min.y;

	const int xMin = dataWindow.min.x - wholeDataWindow.min.x;
	const int xMax = dataWindow.max.x - wholeDataWindow.min.x;

	int dataY = 0;
	for ( int y = yMin ; y <= yMax ; ++y, ++dataY )
	{
		typename TargetVector::ValueType::size_type dataOffset = dataY * dataWidth;
		std::vector<unsigned int>::size_type bufferOffset = y * m_bufferWidth + xMin;

		for ( int x = xMin;  x <= xMax ; ++x, ++dataOffset, ++bufferOffset  )
		{
			assert( dataOffset < data.size() );

			unsigned int cell = m_buffer[ bufferOffset ];
			if ( m_reverseBytes )
			{
				cell = reverseBytes( cell );
			}

			// assume we have 10bit log, two wasted bits aligning to 32 longword
			unsigned short cv = (unsigned short) ( ( mask & cell ) >> ( 2 + ( 2 - channelOffset ) * bpp ) );
			assert( cv < 1024 );
			data[dataOffset] = converter( (cv << ushortShift) + ((1 << ushortShift) - 1) );
		}
	}
	return dataContainer;
}
Пример #25
0
image_t *clip_t::get_input_image( OfxTime time, OfxRectD *optionalBounds)
{
    RAMEN_ASSERT( node());
    RAMEN_ASSERT( node()->composition());
    RAMEN_ASSERT( port_ != -1);
    RAMEN_ASSERT( getPixelDepth() == kOfxBitDepthFloat);

    image_node_t *in = node()->input_as<image_node_t>( port());

    if( !in)
    {
#ifndef NDEBUG
        DLOG( INFO) << "clip_t::getImage, node = " << node()->name() << ", port = " << port() << ", result = 0";
#endif

        return 0;
    }

    render::context_t context = node()->render_context();
    context.composition = node()->composition();
    context.result_node = in;
    context.frame = time;

    render::context_guard_t guard( node()->composition()->current_context(), in);
    render::image_node_renderer_t r( context);

    Imath::Box2i area;

    if( optionalBounds)
    {
        // TODO: is this correct if the effect does not support tiles?
        area = Imath::Box2i( Imath::V2i( optionalBounds->x1, optionalBounds->y1), Imath::V2i( optionalBounds->x2 - 1, optionalBounds->y2 - 1));
        area = node()->vertical_flip( area);
        r.render( area);

        area.min.x = optionalBounds->x1;
        area.min.y = optionalBounds->y1;
        area.max.x = optionalBounds->x2 - 1;
        area.max.y = optionalBounds->y2 - 1;
        area = node()->vertical_flip( area);
        area = intersect( in->defined(), area);
    }
    else
    {
        r.render();
        area = in->defined();
    }

    if( area.isEmpty())
    {
#ifndef NDEBUG
        DLOG( INFO) << "clip_t::getImage, node = " << node()->name() << ", port = " << port() << ", area == empty";
#endif

        return 0;
    }

    image::buffer_t pixels = in->image();
    image::const_image_view_t view( in->const_subimage_view( area));

    area = node()->vertical_flip( area);

    OfxRectI bounds;
    bounds.x1 = area.min.x;
    bounds.y1 = area.min.y;
    bounds.x2 = area.max.x + 1;
    bounds.y2 = area.max.y + 1;

    std::stringstream s;
    for( int i = 0; i < 16; ++i)
        s << (int) in->digest()[i];


#ifndef NDEBUG
    if( optionalBounds)
        DLOG( INFO) << "clip_t::getImage, node = " << node()->name() << ", port = " << port() << ", bounds = " << *optionalBounds;
    else
        DLOG( INFO) << "clip_t::getImage, node = " << node()->name() << ", port = " << port();
#endif

    image_t *result = 0;

    if( getComponents() == kOfxImageComponentRGBA)
    {
        int rowbytes;
        void *ptr = view_get_ptr_and_stride( view, rowbytes);
        result = new image_t( *this, pixels, 1.0 / node()->render_context().subsample, ptr, bounds, bounds, rowbytes, s.str());
    }
    else
    {
        // TODO: create an gray scale image and copy the alpha channel
        RAMEN_ASSERT( 0);
    }

    in->release_image();
    return result;
}
Пример #26
0
OfxRectD clip_t::getRegionOfDefinition( OfxTime time) const
{
    RAMEN_ASSERT( node());

    const image_node_t *in = 0;
    bool use_default = false;
    bool restore_time = false;
    float saved_frame;

    // calling getRoD for the output clip does not make a lot of sense, but some plugins do...
    if( port_ == -1)
        in = node();
    else // normal case
        in = node()->input_as<const image_node_t>( port_);

    if( !in)
    {
        in = node();
        use_default = true;
    }

    if( node()->composition())
    {
        saved_frame = node()->composition()->frame();

        if( saved_frame != time)
        {
            restore_time = true;
            composition_t *c = const_cast<composition_t*>( node()->composition());
            c->set_frame( time);
        }
    }

    Imath::Box2i b;

    if( use_default)
    {
        for( int i = 0; i < in->num_inputs(); ++i)
        {
            if( const image_node_t *src = in->input_as<const image_node_t>( i))
                b.extendBy( src->bounds());
        }

        if( b.isEmpty())
        {
            if( in->composition())
                b = node()->composition()->default_format().area();
            else
                b = preferences_t::Instance().default_format().area();
        }
    }
    else
        b = in->bounds();

    b = node()->vertical_flip( b);

    OfxRectD v;
    v.x1 = b.min.x;
    v.y1 = b.min.y;
    v.x2 = b.max.x + 1;
    v.y2 = b.max.y + 1;

    if( restore_time)
    {
        composition_t *c = const_cast<composition_t*>( node()->composition());
        c->set_frame( saved_frame);
    }

#ifndef NDEBUG
    DLOG( INFO) << "clip_t::getRoD, node = " << node()->name() << ", port = " << port() << ", result = " << v;
#endif

    return v;
}
Пример #27
0
void Crop::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const
{
	if ( output == cropWindowPlug() )
	{
		int areaSource = areaSourcePlug()->getValue();
		Imath::Box2i cropWindow;

		switch ( areaSource )
		{
			case Crop::DataWindow:
			{
				cropWindow = inPlug()->dataWindowPlug()->getValue();
				break;
			}
			case Crop::DisplayWindow:
			{
				cropWindow = inPlug()->formatPlug()->getValue().getDisplayWindow();
				break;
			}
			case Crop::Format:
			{
				cropWindow = formatPlug()->getValue().getDisplayWindow();
				if( formatCenterPlug()->getValue() )
				{
					const Imath::Box2i displayWindow = inPlug()->formatPlug()->getValue().getDisplayWindow();
					Imath::V2i centerOffset( cropWindow.center() - displayWindow.center() );

					cropWindow.min -= centerOffset;
					cropWindow.max -= centerOffset;
				}
				break;
			}
			default:
			{
				cropWindow = areaPlug()->getValue();
				break;
			}
		}

		static_cast<Gaffer::AtomicBox2iPlug *>( output )->setValue( cropWindow );
	}
	else if( output->parent<Plug>() == offsetPlug() )
	{
		ImagePlug::GlobalScope c( context );
		V2i offset( 0 );
		if( affectDisplayWindowPlug()->getValue() )
		{
			if( resetOriginPlug()->getValue() )
			{
				offset -= cropWindowPlug()->getValue().min;
			}
			else if( areaSourcePlug()->getValue() == Crop::Format && formatCenterPlug()->getValue() )
			{
				offset -= cropWindowPlug()->getValue().min - formatPlug()->getValue().getDisplayWindow().min;
			}
		}
		static_cast<IntPlug *>( output )->setValue(
			output == offsetPlug()->getChild( 0 ) ? offset[0] : offset[1]
		);
	}
	else
	{
		ImageProcessor::compute( output, context );
	}
}
Пример #28
0
gray_image_view_t buffer_t::gray_subimage_view( const Imath::Box2i& area) const
{
    check_area_inside_image( area);
    return boost::gil::subimage_view( gray_view(), area.min.x - bounds_.min.x, area.min.y - bounds_.min.y,
										area.size().x+1, area.size().y+1);
}
Пример #29
0
DataPtr EXRImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, const Imf::Channel *channel )
{
	assert( channel );
	Imath::V2i pixelDimensions = dataWindow.size() + Imath::V2i( 1 );
	unsigned numPixels = pixelDimensions.x * pixelDimensions.y;

	typedef TypedData<vector<T> > DataType;
	typename DataType::Ptr data = new DataType;
	data->writable().resize( numPixels );

	Imath::Box2i fullDataWindow = this->dataWindow();
	if( fullDataWindow.min.x==dataWindow.min.x && fullDataWindow.max.x==dataWindow.max.x )
	{
		// the width we want to read matches the width in the file, so we can read straight
		// into the result buffer
		FrameBuffer frameBuffer;
		T *buffer00 = data->baseWritable() - dataWindow.min.y * pixelDimensions.x - fullDataWindow.min.x;
		Slice slice( channel->type, (char *)buffer00, sizeof(T), sizeof(T) * pixelDimensions.x );
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );
		// exr library will choose the best order to read scanlines automatically (increasing or decreasing)
		try
		{
			m_inputFile->readPixels( dataWindow.min.y, dataWindow.max.y );
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
			return data;
		}
	}
	else
	{
		// widths don't match, we need to read into a temporary buffer and then transfer just
		// the bits we need into the result buffer.
		int numTmpPixels = fullDataWindow.size().x + 1;
		vector<T> tmpBuffer( numTmpPixels );
		T *tmpBufferTransferStart = &(tmpBuffer[0]) + dataWindow.min.x - fullDataWindow.min.x;
		size_t tmpBufferTransferLength = pixelDimensions.x * sizeof( T );
		T *transferDestination = &(data->writable()[0]);

		// slice has yStride of 0 so each successive scanline just overwrites the previous one
		Slice slice( channel->type, (char *)(&(tmpBuffer[0]) - fullDataWindow.min.x), sizeof(T), 0 );
		FrameBuffer frameBuffer;
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );

		int yStart = dataWindow.min.y;
		int yEnd = dataWindow.max.y;
		int yStep = 1;
		try
		{
			for( int y=yStart; y!=(yEnd+yStep); y+=yStep )
			{
				m_inputFile->readPixels( y );
				memcpy( (char *)transferDestination, (const char *)tmpBufferTransferStart, tmpBufferTransferLength );
				transferDestination += pixelDimensions.x;
			}
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
			return data;
		}
	}

#ifndef NDEBUG
	for ( typename DataType::ValueType::const_iterator it = data->readable().begin(); it != data->readable().end(); ++it )
	{
		assert( *it == *it ); // Will fail iff NaN
	}
#endif

	return data;
}
Пример #30
0
///\todo: It seems that if a JPG is written with RGBA channels the output is wrong but it should be supported. Find out why and fix it.
/// There is a test case in ImageWriterTest which checks the output of the jpg writer against an incorrect image and it will fail if it is equal to the writer output.
void ImageWriter::execute( const Contexts &contexts ) const
{
	if( !inPlug()->getInput<ImagePlug>() )
	{
		throw IECore::Exception( "No input image." );
	}

	// Loop over the execution contexts...
	for( Contexts::const_iterator it = contexts.begin(), eIt = contexts.end(); it != eIt; it++ )
	{
		Context::Scope scopedContext( it->get() );
		
		std::string fileName = fileNamePlug()->getValue();
		fileName = (*it)->substitute( fileName );
		
		boost::shared_ptr< ImageOutput > out( ImageOutput::create( fileName.c_str() ) );
		if ( !out )
		{
			throw IECore::Exception( boost::str( boost::format( "Invalid filename: %s" ) % fileName ) );
		}
		
		// Grab the intersection of the channels from the "channels" plug and the image input to see which channels we are to write out.
		IECore::ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue();
		std::vector<std::string> maskChannels = channelNamesData->readable();
		channelsPlug()->maskChannels( maskChannels );
		const int nChannels = maskChannels.size();
		
		// Get the image channel data.
		IECore::ImagePrimitivePtr imagePtr( inPlug()->image() );
		
		// Get the image's display window.
		const Imath::Box2i displayWindow( imagePtr->getDisplayWindow() );
		const int displayWindowWidth = displayWindow.size().x+1;
		const int displayWindowHeight = displayWindow.size().y+1;

		// Get the image's data window and if it then set a flag.
		bool imageIsBlack = false;
		Imath::Box2i dataWindow( imagePtr->getDataWindow() );
		if ( inPlug()->dataWindowPlug()->getValue().isEmpty() )
		{
			dataWindow = displayWindow;
			imageIsBlack = true;
		}

		int dataWindowWidth = dataWindow.size().x+1;
		int dataWindowHeight = dataWindow.size().y+1;
	
		// Create the image header. 
		ImageSpec spec( dataWindowWidth, dataWindowHeight, nChannels, TypeDesc::FLOAT );

		// Add the channel names to the header whilst getting pointers to the channel data. 
		std::vector<const float*> channelPtrs;
		spec.channelnames.clear();
		for ( std::vector<std::string>::iterator channelIt( maskChannels.begin() ); channelIt != maskChannels.end(); channelIt++ )
		{
			spec.channelnames.push_back( *channelIt );
			IECore::FloatVectorDataPtr dataPtr = imagePtr->getChannel<float>( *channelIt );
			channelPtrs.push_back( &(dataPtr->readable()[0]) );

			// OIIO has a special attribute for the Alpha and Z channels. If we find some, we should tag them...
			if ( *channelIt == "A" )
			{
				spec.alpha_channel = channelIt-maskChannels.begin();
			} else if ( *channelIt == "Z" )
			{
				spec.z_channel = channelIt-maskChannels.begin();
			}
		}
		
		// Specify the display window.
		spec.full_x = displayWindow.min.x;
		spec.full_y = displayWindow.min.y;
		spec.full_width = displayWindowWidth;
		spec.full_height = displayWindowHeight;
		spec.x = dataWindow.min.x;
		spec.y = dataWindow.min.y;
	
		if ( !out->open( fileName, spec ) )
		{
			throw IECore::Exception( boost::str( boost::format( "Could not open \"%s\", error = %s" ) % fileName % out->geterror() ) );
		}

		// Only allow tiled output if our file format supports it.	
		int writeMode = writeModePlug()->getValue() & out->supports( "tile" );
	
		if ( writeMode == Scanline )
		{
			// Create a buffer for the scanline.
			float scanline[ nChannels*dataWindowWidth ];
			
			if ( imageIsBlack )
			{
				memset( scanline, 0, sizeof(float) * nChannels*dataWindowWidth );

				for ( int y = spec.y; y < spec.y + dataWindowHeight; ++y )
				{
					if ( !out->write_scanline( y, 0, TypeDesc::FLOAT, &scanline[0] ) )
					{
						throw IECore::Exception( boost::str( boost::format( "Could not write scanline to \"%s\", error = %s" ) % fileName % out->geterror() ) );
					}
				}
			}
			else
			{
				// Interleave the channel data and write it by scanline to the file.	
				for ( int y = spec.y; y < spec.y + dataWindowHeight; ++y )
				{
					for ( std::vector<const float *>::iterator channelDataIt( channelPtrs.begin() ); channelDataIt != channelPtrs.end(); channelDataIt++ )
					{
						float *outPtr = &scanline[0] + (channelDataIt - channelPtrs.begin()); // The pointer that we are writing to.
						// The row that we are reading from is flipped (in the Y) as we use a different image space internally to OpenEXR and OpenImageIO.
						const float *inRowPtr = (*channelDataIt) + ( y - spec.y ) * dataWindowWidth;
						const int inc = channelPtrs.size();
						for ( int x = 0; x < dataWindowWidth; ++x, outPtr += inc )
						{
							*outPtr = *inRowPtr++;
						}
					}

					if ( !out->write_scanline( y, 0, TypeDesc::FLOAT, &scanline[0] ) )
					{
						throw IECore::Exception( boost::str( boost::format( "Could not write scanline to \"%s\", error = %s" ) % fileName % out->geterror() ) );
					}
				}
			}
		}
		// Tiled output
		else
		{
			// Create a buffer for the tile.
			const int tileSize = ImagePlug::tileSize();
			float tile[ nChannels*tileSize*tileSize ];

			if ( imageIsBlack )
			{
				memset( tile, 0,  sizeof(float) * nChannels*tileSize*tileSize );
				for ( int tileY = 0; tileY < dataWindowHeight; tileY += tileSize )
				{
					for ( int tileX = 0; tileX < dataWindowWidth; tileX += tileSize )
					{
						if ( !out->write_tile( tileX+dataWindow.min.x, tileY+spec.y, 0, TypeDesc::FLOAT, &tile[0] ) )
						{
							throw IECore::Exception( boost::str( boost::format( "Could not write tile to \"%s\", error = %s" ) % fileName % out->geterror() ) );
						}
					}
				}
			}
			else
			{
				// Interleave the channel data and write it to the file tile-by-tile.
				for ( int tileY = 0; tileY < dataWindowHeight; tileY += tileSize )
				{
					for ( int tileX = 0; tileX < dataWindowWidth; tileX += tileSize )
					{
						float *outPtr = &tile[0];	

						const int r = std::min( tileSize+tileX, dataWindowWidth );
						const int t = std::min( tileSize+tileY, dataWindowHeight );

						for ( int y = 0; y < t; ++y )
						{
							for ( std::vector<const float *>::iterator channelDataIt( channelPtrs.begin() ); channelDataIt != channelPtrs.end(); channelDataIt++ )
							{
								const int inc = channelPtrs.size();
								const float *inRowPtr = (*channelDataIt) + ( tileY + t - y - 1 ) * dataWindowWidth;
								for ( int x = 0; x < r; ++x, outPtr += inc )
								{
									*outPtr = *inRowPtr+(tileX+x);
								}
							}
						}

						if ( !out->write_tile( tileX+dataWindow.min.x, tileY+spec.y, 0, TypeDesc::FLOAT, &tile[0] ) )
						{
							throw IECore::Exception( boost::str( boost::format( "Could not write tile to \"%s\", error = %s" ) % fileName % out->geterror() ) );
						}
					}
				}
			}

		}

		out->close();
	}
}