Skip to content

Commit

Permalink
Catalogue : Add imageNames output plug
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Mar 19, 2024
1 parent ea88e4e commit d2287e9
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 31 deletions.
5 changes: 5 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
1.4.x.x (relative to 1.4.0.0b4)
=======

Improvements
------------

- Catalogue : Added `imageNames` output plug, containing the names of all images in the Catalogue. Among other things this can be used to drive a Wedge or ContactSheet node and a CatalogueSelect.

API
---

Expand Down
3 changes: 3 additions & 0 deletions include/GafferImage/Catalogue.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ class GAFFERIMAGE_API Catalogue : public ImageNode
Gaffer::StringPlug *directoryPlug();
const Gaffer::StringPlug *directoryPlug() const;

Gaffer::StringVectorDataPlug *imageNamesPlug();
const Gaffer::StringVectorDataPlug *imageNamesPlug() const;

/// All Catalogues share a single DisplayDriverServer instance
/// to receive rendered images. To send an image to the catalogues,
/// use an IECoreImage::ClientDisplayDriver with the "displayPort" parameter
Expand Down
32 changes: 32 additions & 0 deletions python/GafferImageTest/CatalogueTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1147,5 +1147,37 @@ def assertPostConditions() :
script.undo()
assertPreconditions()

def testImageNames( self ) :

def assertImageNames( catalogue ) :

self.assertEqual(
catalogue["imageNames"].getValue(),
IECore.StringVectorData( catalogue["images"].keys() )
)

catalogue = GafferImage.Catalogue()
plugDirtiedSlot = GafferTest.CapturingSlot( catalogue.plugDirtiedSignal() )
assertImageNames( catalogue )

catalogue["images"].addChild( catalogue.Image.load( self.imagesPath() / "blurRange.exr" ) )
self.assertIn( catalogue["imageNames"], { x[0] for x in plugDirtiedSlot } )
assertImageNames( catalogue )

del plugDirtiedSlot[:]
catalogue["images"].addChild( catalogue.Image.load( self.imagesPath() / "blurRange.exr" ) )
self.assertIn( catalogue["imageNames"], { x[0] for x in plugDirtiedSlot } )
assertImageNames( catalogue )

del plugDirtiedSlot[:]
catalogue["images"][0].setName( "newName" )
self.assertIn( catalogue["imageNames"], { x[0] for x in plugDirtiedSlot } )
assertImageNames( catalogue )

del plugDirtiedSlot[:]
catalogue["images"].reorderChildren( reversed( catalogue["images"].children() ) )
self.assertIn( catalogue["imageNames"], { x[0] for x in plugDirtiedSlot } )
assertImageNames( catalogue )

if __name__ == "__main__":
unittest.main()
15 changes: 15 additions & 0 deletions python/GafferImageUI/CatalogueUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,21 @@ def __setOutputIndex( self, image, index, *unused ) :

],

"imageNames" : [

"description",
"""
Output containing all the names of the images in the Catalogue.
Possible uses include :
- Looping over all images using a Wedge and a CatalogueSelect.
- Making a ContactSheet using the Collect mode and a CatalogueSelect.
""",

"layout:section", "Advanced"

],

},

)
Expand Down
93 changes: 62 additions & 31 deletions src/GafferImage/Catalogue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ Catalogue::Catalogue( const std::string &name )
addChild( new IntPlug( "imageIndex" ) );
addChild( new StringPlug( "name" ) );
addChild( new StringPlug( "directory" ) );
addChild( new StringVectorDataPlug( "imageNames", Plug::Out ) );
addChild( new IntPlug( "__imageIndex", Plug::Out ) );
addChild( new ObjectPlug( "__imageIndexMap", Plug::Out, IECore::NullObject::defaultNullObject() ) );
addChild( new StringPlug( "__invalidImageText", Plug::Out ) );
Expand Down Expand Up @@ -917,44 +918,54 @@ const Gaffer::StringPlug *Catalogue::directoryPlug() const
return getChild<StringPlug>( g_firstPlugIndex + 3 );
}

Gaffer::StringVectorDataPlug *Catalogue::imageNamesPlug()
{
return getChild<StringVectorDataPlug>( g_firstPlugIndex + 4 );
}

const Gaffer::StringVectorDataPlug *Catalogue::imageNamesPlug() const
{
return getChild<StringVectorDataPlug>( g_firstPlugIndex + 4 );
}

Gaffer::IntPlug *Catalogue::internalImageIndexPlug()
{
return getChild<IntPlug>( g_firstPlugIndex + 4 );
return getChild<IntPlug>( g_firstPlugIndex + 5 );
}

const Gaffer::IntPlug *Catalogue::internalImageIndexPlug() const
{
return getChild<IntPlug>( g_firstPlugIndex + 4 );
return getChild<IntPlug>( g_firstPlugIndex + 5 );
}

Gaffer::ObjectPlug *Catalogue::imageIndexMapPlug()
{
return getChild<ObjectPlug>( g_firstPlugIndex + 5 );
return getChild<ObjectPlug>( g_firstPlugIndex + 6 );
}

const Gaffer::ObjectPlug *Catalogue::imageIndexMapPlug() const
{
return getChild<ObjectPlug>( g_firstPlugIndex + 5 );
return getChild<ObjectPlug>( g_firstPlugIndex + 6 );
}

Gaffer::StringPlug *Catalogue::invalidImageTextPlug()
{
return getChild<StringPlug>( g_firstPlugIndex + 6 );
return getChild<StringPlug>( g_firstPlugIndex + 7 );
}

const Gaffer::StringPlug *Catalogue::invalidImageTextPlug() const
{
return getChild<StringPlug>( g_firstPlugIndex + 6 );
return getChild<StringPlug>( g_firstPlugIndex + 7 );
}

Switch *Catalogue::imageSwitch()
{
return getChild<Switch>( g_firstPlugIndex + 7 );
return getChild<Switch>( g_firstPlugIndex + 8 );
}

const Switch *Catalogue::imageSwitch() const
{
return getChild<Switch>( g_firstPlugIndex + 7 );
return getChild<Switch>( g_firstPlugIndex + 8 );
}

Catalogue::InternalImage *Catalogue::imageNode( Image *image )
Expand Down Expand Up @@ -1254,11 +1265,16 @@ void Catalogue::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outp
ImageNode::affects( input, outputs );

auto image = input->parent<Image>();
if( image && image->parent() == imagesPlug() &&
( input == image->namePlug() || input == image->outputIndexPlug() )
)
if( image && image->parent() == imagesPlug() )
{
outputs.push_back( imageIndexMapPlug() );
if( input == image->namePlug() || input == image->outputIndexPlug() )
{
outputs.push_back( imageIndexMapPlug() );
}
if( input== image->namePlug() )
{
outputs.push_back( imageNamesPlug() );
}
}

if( input == imageIndexPlug() || input == imageIndexMapPlug() )
Expand Down Expand Up @@ -1298,6 +1314,13 @@ void Catalogue::hash( const Gaffer::ValuePlug *output, const Gaffer::Context *co
imageIndexMapPlug()->hash( h );
}
}
else if( output == imageNamesPlug() )
{
for( const auto &image : Image::Range( *imagesPlug() ) )
{
image->namePlug()->hash( h );
}
}
}

void Catalogue::compute( ValuePlug *output, const Context *context ) const
Expand Down Expand Up @@ -1353,33 +1376,41 @@ void Catalogue::compute( ValuePlug *output, const Context *context ) const

static_cast<ObjectPlug *>( output )->setValue( result );
}

if( output != internalImageIndexPlug() )
else if( output == internalImageIndexPlug() )
{
ImageNode::compute( output, context );
return;
int index = -1;
const std::string &imageName = context->get<std::string>( g_imageNameContextName, g_emptyString );
if( imageName.empty() )
{
index = imageIndexPlug()->getValue();
}
else
{
Context::EditableScope mapScope( context );
mapScope.remove( g_imageNameContextName );
ConstImageIndexMapDataPtr imageIndexMap = boost::static_pointer_cast<const ImageIndexMapData>( imageIndexMapPlug()->getValue() );
auto it = imageIndexMap->map.find( imageName );
if( it != imageIndexMap->map.end() )
{
index = it->second;
}
}
static_cast<IntPlug *>( output )->setValue( index + 1 );
}

int index = -1;
const std::string &imageName = context->get<std::string>( g_imageNameContextName, g_emptyString );
if( imageName.empty() )
else if( output == imageNamesPlug() )
{
index = imageIndexPlug()->getValue();
StringVectorDataPtr result = new StringVectorData;
for( const auto &image : Image::Range( *imagesPlug() ) )
{
result->writable().push_back( image->getName().string() );
}
static_cast<StringVectorDataPlug *>( output )->setValue( result );
}
else
{
Context::EditableScope mapScope( context );
mapScope.remove( g_imageNameContextName );
ConstImageIndexMapDataPtr imageIndexMap = boost::static_pointer_cast<const ImageIndexMapData>( imageIndexMapPlug()->getValue() );
auto it = imageIndexMap->map.find( imageName );
if( it != imageIndexMap->map.end() )
{
index = it->second;
}
ImageNode::compute( output, context );
}

static_cast<IntPlug *>( output )->setValue( index + 1 );

}

const std::type_info &Catalogue::internalImageTypeInfo()
Expand Down

0 comments on commit d2287e9

Please sign in to comment.