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); }
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); }
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); }
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; }
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; }
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; }
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; }
// 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; }
void ImageCompositeOp::composite( CompositeFn fn, DataWindowResult dwr, ImagePrimitive * imageB, const CompoundObject * operands ) { assert( fn ); assert( imageB ); assert( operands ); const StringVectorParameter::ValueType &channelNames = channelNamesParameter()->getTypedValue(); if ( !channelNames.size() ) { throw InvalidArgumentException( "ImageCompositeOp: No channels specified" ); } ImagePrimitivePtr imageA = runTimeCast< ImagePrimitive > ( imageAParameter()->getValue() ); assert( imageA ); const std::string &alphaChannel = alphaChannelNameParameter()->getTypedValue(); if ( !imageA->arePrimitiveVariablesValid() ) { throw InvalidArgumentException( "ImageCompositeOp: Input image has invalid channels" ); } const int inputMode = m_inputModeParameter->getNumericValue(); if ( inputMode == Unpremultiplied ) { ImagePremultiplyOpPtr premultOp = new ImagePremultiplyOp(); premultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel ); premultOp->channelNamesParameter()->setTypedValue( channelNames ); if ( imageA->variables.find( alphaChannel ) != imageA->variables.end() ) { /// Make a new imageA, premultiplied premultOp->copyParameter()->setTypedValue( true ); premultOp->inputParameter()->setValue( imageA ); imageA = assertedStaticCast< ImagePrimitive >( premultOp->operate() ); assert( imageA->arePrimitiveVariablesValid() ); } if ( imageB->variables.find( alphaChannel ) != imageB->variables.end() ) { /// Premultiply imageB in-place premultOp->copyParameter()->setTypedValue( false ); premultOp->inputParameter()->setValue( imageB ); premultOp->operate(); } } else { assert( inputMode == Premultiplied ); } const Imath::Box2i displayWindow = imageB->getDisplayWindow(); Imath::Box2i newDataWindow = imageB->getDataWindow(); if ( dwr == Union ) { newDataWindow.extendBy( imageA->getDataWindow() ); } else { assert( dwr == Intersection ); newDataWindow = boxIntersection( newDataWindow, imageA->getDataWindow() ); } newDataWindow = boxIntersection( newDataWindow, displayWindow ); ImageCropOpPtr cropOp = new ImageCropOp(); /// Need to make sure that we don't create a new image here - we want to modify the current one in-place. So, /// we turn off the "copy" parameter of ModifyOp. cropOp->copyParameter()->setTypedValue( false ); cropOp->inputParameter()->setValue( imageB ); cropOp->cropBoxParameter()->setTypedValue( newDataWindow ); cropOp->matchDataWindowParameter()->setTypedValue( true ); cropOp->resetOriginParameter()->setTypedValue( false ); cropOp->operate(); assert( imageB->arePrimitiveVariablesValid() ); assert( imageB->getDataWindow() == newDataWindow ); /// \todo Use the "reformat" parameter of the ImageCropOp to do this, when it's implemented imageB->setDisplayWindow( displayWindow ); FloatVectorDataPtr aAlphaData = getChannelData( imageA.get(), alphaChannel, false ); FloatVectorDataPtr bAlphaData = getChannelData( imageB, alphaChannel, false ); const int newWidth = newDataWindow.size().x + 1; const int newHeight = newDataWindow.size().y + 1; const int newArea = newWidth * newHeight; assert( newArea == (int)imageB->variableSize( PrimitiveVariable::Vertex ) ); for( unsigned i=0; i<channelNames.size(); i++ ) { const StringVectorParameter::ValueType::value_type &channelName = channelNames[i]; FloatVectorDataPtr aData = getChannelData( imageA.get(), channelName ); assert( aData->readable().size() == imageA->variableSize( PrimitiveVariable::Vertex ) ); FloatVectorDataPtr bData = getChannelData( imageB, channelName ); assert( bData->readable().size() == imageB->variableSize( PrimitiveVariable::Vertex ) ); FloatVectorDataPtr newBData = new FloatVectorData(); newBData->writable().resize( newArea ); imageB->variables[ channelName ].data = newBData; for ( int y = newDataWindow.min.y; y <= newDataWindow.max.y; y++ ) { int offset = (y - newDataWindow.min.y ) * newWidth; for ( int x = newDataWindow.min.x; x <= newDataWindow.max.x; x++, offset++ ) { float aVal = readChannelData( imageA.get(), aData.get(), V2i( x, y ) ); float bVal = readChannelData( imageB, bData.get(), V2i( x, y ) ); float aAlpha = aAlphaData ? readChannelData( imageA.get(), aAlphaData.get(), V2i( x, y ) ) : 1.0f; float bAlpha = bAlphaData ? readChannelData( imageB, bAlphaData.get(), V2i( x, y ) ) : 1.0f; assert( offset >= 0 ); assert( offset < (int)newBData->readable().size() ); newBData->writable()[ offset ] = fn( aVal, aAlpha, bVal, bAlpha ); } } } /// displayWindow should be unchanged assert( imageB->getDisplayWindow() == displayWindow ); assert( imageB->arePrimitiveVariablesValid() ); /// If input images were unpremultiplied, then ensure that the output is also if ( inputMode == Unpremultiplied && imageB->variables.find( alphaChannel ) != imageB->variables.end() ) { ImageUnpremultiplyOpPtr unpremultOp = new ImageUnpremultiplyOp(); /// Unpremultiply imageB in-place unpremultOp->copyParameter()->setTypedValue( false ); unpremultOp->channelNamesParameter()->setTypedValue( channelNames ); unpremultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel ); unpremultOp->inputParameter()->setValue( imageB ); unpremultOp->operate(); assert( imageB->arePrimitiveVariablesValid() ); } else { assert( inputMode == Premultiplied ); } }