Skip to content

Commit

Permalink
Premult/Unpremult : Add ignoreMissingAlpha plug
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldresser-ie committed Jul 5, 2024
1 parent f963611 commit a3f9440
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 31 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Improvements
- The following parameters can now be made visible in the GraphEditor :
- The `flake_layers` parameter of the `car_paint` shader.
- The `data_seed`, `proc_seed`, `obj_seed`, and `face_seed` parameters of the `color_jitter` shader.
- Premultiply / Unpremultiply : Added ignoreMissingAlpha plug.

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

Gaffer::BoolPlug *ignoreMissingAlphaPlug();
const Gaffer::BoolPlug *ignoreMissingAlphaPlug() const;

Gaffer::BoolPlug *useDeepVisibilityPlug();
const Gaffer::BoolPlug *useDeepVisibilityPlug() const;
//@}
Expand Down
3 changes: 3 additions & 0 deletions include/GafferImage/Unpremultiply.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class GAFFERIMAGE_API Unpremultiply : public ChannelDataProcessor
//@{
Gaffer::StringPlug *alphaChannelPlug();
const Gaffer::StringPlug *alphaChannelPlug() const;

Gaffer::BoolPlug *ignoreMissingAlphaPlug();
const Gaffer::BoolPlug *ignoreMissingAlphaPlug() const;
//@}

void affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const override;
Expand Down
7 changes: 7 additions & 0 deletions python/GafferImageTest/PremultiplyTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ def testAlphaChannel( self ) :
h2 = premult["out"].channelData( "R", imath.V2i( 0 ) ).hash()
self.assertNotEqual( h1, h2 )

premult["alphaChannel"].setValue("doesNotExist")
with self.assertRaisesRegex( Gaffer.ProcessException, "Channel 'doesNotExist' does not exist" ) :
GafferImageTest.processTiles( premult["out"] )

premult["ignoreMissingAlpha"].setValue( True )
self.assertImagesEqual( premult["out"], premult["in"] )

def testEnableBehaviour( self ) :

g = GafferImage.Premultiply()
Expand Down
8 changes: 8 additions & 0 deletions python/GafferImageTest/UnpremultiplyTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ def testAlphaChannel( self ) :
h2 = unpremult["out"].channelData( "R", imath.V2i( 0 ) ).hash()
self.assertNotEqual( h1, h2 )

unpremult["alphaChannel"].setValue("doesNotExist")
with self.assertRaisesRegex( Gaffer.ProcessException, "Channel 'doesNotExist' does not exist" ) :
GafferImageTest.processTiles( unpremult["out"] )

unpremult["ignoreMissingAlpha"].setValue( True )
self.assertImagesEqual( unpremult["out"], unpremult["in"] )


def testEnableBehaviour( self ) :

g = GafferImage.Unpremultiply()
Expand Down
10 changes: 10 additions & 0 deletions python/GafferImageUI/PremultiplyUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@

],

"ignoreMissingAlpha" : [

"description",
"""
If set, this node will do nothing if the specified `alphaChannel`
is not found, instead of throwing an error.
""",

],

"useDeepVisibility" : [

"description",
Expand Down
10 changes: 10 additions & 0 deletions python/GafferImageUI/UnpremultiplyUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@

],

"ignoreMissingAlpha" : [

"description",
"""
If set, this node will do nothing if the specified `alphaChannel`
is not found, instead of throwing an error.
""",

],

}

)
71 changes: 53 additions & 18 deletions src/GafferImage/Premultiply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Premultiply::Premultiply( const std::string &name )
{
storeIndexOfNextChild( g_firstPlugIndex );
addChild( new StringPlug( "alphaChannel", Gaffer::Plug::In, "A" ) );
addChild( new BoolPlug( "ignoreMissingAlpha", Gaffer::Plug::In, false ) );
addChild( new BoolPlug( "useDeepVisibility", Gaffer::Plug::In, false ) );
}

Expand All @@ -71,16 +72,26 @@ const Gaffer::StringPlug *Premultiply::alphaChannelPlug() const
return getChild<StringPlug>( g_firstPlugIndex );
}

Gaffer::BoolPlug *Premultiply::useDeepVisibilityPlug()
Gaffer::BoolPlug *Premultiply::ignoreMissingAlphaPlug()
{
return getChild<BoolPlug>( g_firstPlugIndex + 1 );
}

const Gaffer::BoolPlug *Premultiply::useDeepVisibilityPlug() const
const Gaffer::BoolPlug *Premultiply::ignoreMissingAlphaPlug() const
{
return getChild<BoolPlug>( g_firstPlugIndex + 1 );
}

Gaffer::BoolPlug *Premultiply::useDeepVisibilityPlug()
{
return getChild<BoolPlug>( g_firstPlugIndex + 2 );
}

const Gaffer::BoolPlug *Premultiply::useDeepVisibilityPlug() const
{
return getChild<BoolPlug>( g_firstPlugIndex + 2 );
}

void Premultiply::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
ChannelDataProcessor::affects( input, outputs );
Expand All @@ -91,6 +102,7 @@ void Premultiply::affects( const Gaffer::Plug *input, AffectedPlugsContainer &ou
input == inPlug()->deepPlug() ||
input == inPlug()->sampleOffsetsPlug() ||
input == alphaChannelPlug() ||
input == ignoreMissingAlphaPlug() ||
input == useDeepVisibilityPlug()
)
{
Expand All @@ -100,29 +112,44 @@ void Premultiply::affects( const Gaffer::Plug *input, AffectedPlugsContainer &ou

void Premultiply::hashChannelData( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{

ChannelDataProcessor::hashChannelData( output, context, h );

std::string alphaChannel;
ConstStringVectorDataPtr inChannelNamesPtr;
bool ignoreMissingAlpha;
bool useDeepVisibility;
bool deep;
{
ImagePlug::GlobalScope c( context );
alphaChannel = alphaChannelPlug()->getValue();
inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
ignoreMissingAlpha = ignoreMissingAlphaPlug()->getValue();
useDeepVisibility = useDeepVisibilityPlug()->getValue();
inPlug()->deepPlug()->hash( h );
deep = inPlug()->deepPlug()->getValue();
}

h.append( alphaChannel == context->get<std::string>( ImagePlug::channelNameContextName ) );
if(
(!useDeepVisibility && alphaChannel == context->get<std::string>( ImagePlug::channelNameContextName ) ) ||
( useDeepVisibility && !deep )
)
{
h = inPlug()->channelDataPlug()->hash();
return;
}

const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
if( ignoreMissingAlpha )
{
h = inPlug()->channelDataPlug()->hash();
return;
}
else
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
}
}

inPlug()->channelDataPlug()->hash( h );
ChannelDataProcessor::hashChannelData( output, context, h );

ImagePlug::ChannelDataScope channelDataScope( context );
channelDataScope.setChannelName( &alphaChannel );
Expand All @@ -142,24 +169,39 @@ void Premultiply::processChannelData( const Gaffer::Context *context, const Imag
std::string alphaChannel;
ConstStringVectorDataPtr inChannelNamesPtr;
bool useDeepVisibility;
bool ignoreMissingAlpha;
bool deep;
{
ImagePlug::GlobalScope c( context );
alphaChannel = alphaChannelPlug()->getValue();
inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
useDeepVisibility = useDeepVisibilityPlug()->getValue();
ignoreMissingAlpha = ignoreMissingAlphaPlug()->getValue();
deep = inPlug()->deepPlug()->getValue();
}

if( !useDeepVisibility && channel == alphaChannel )
if(
// Unless we're doing useDeepVisibility, we don't process the alpha channel
( !useDeepVisibility && channel == alphaChannel ) ||
// If it's a flat image, useDeepVisibility means don't do anything
// ( There is never a sample in front, so the visibility is always 100% )
( useDeepVisibility && !deep )
)
{
return;
}

const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
if( ignoreMissingAlpha )
{
return;
}
else
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
}
}

ImagePlug::ChannelDataScope channelDataScope( context );
Expand All @@ -179,13 +221,6 @@ void Premultiply::processChannelData( const Gaffer::Context *context, const Imag
return;
}

if( !deep )
{
// If it's a flat image, useDeepVisibility means don't do anything
// ( There is never a sample in front, so the visibility is always 100%
return;
}

channelDataScope.remove( ImagePlug::channelNameContextName );
ConstIntVectorDataPtr sampleOffsetsData = inPlug()->sampleOffsetsPlug()->getValue();

Expand Down
67 changes: 54 additions & 13 deletions src/GafferImage/Unpremultiply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Unpremultiply::Unpremultiply( const std::string &name )
{
storeIndexOfNextChild( g_firstPlugIndex );
addChild( new StringPlug( "alphaChannel", Gaffer::Plug::In, "A" ) );
addChild( new BoolPlug( "ignoreMissingAlpha", Gaffer::Plug::In, false ) );
}

Unpremultiply::~Unpremultiply()
Expand All @@ -70,13 +71,24 @@ const Gaffer::StringPlug *Unpremultiply::alphaChannelPlug() const
return getChild<StringPlug>( g_firstPlugIndex );
}

Gaffer::BoolPlug *Unpremultiply::ignoreMissingAlphaPlug()
{
return getChild<BoolPlug>( g_firstPlugIndex + 1 );
}

const Gaffer::BoolPlug *Unpremultiply::ignoreMissingAlphaPlug() const
{
return getChild<BoolPlug>( g_firstPlugIndex + 1 );
}

void Unpremultiply::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
ChannelDataProcessor::affects( input, outputs );

if(
input == inPlug()->channelDataPlug() ||
input == alphaChannelPlug()
input == alphaChannelPlug() ||
input == ignoreMissingAlphaPlug()
)
{
outputs.push_back( outPlug()->channelDataPlug() );
Expand All @@ -85,11 +97,32 @@ void Unpremultiply::affects( const Gaffer::Plug *input, AffectedPlugsContainer &

void Unpremultiply::hashChannelData( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
std::string alphaChannel = alphaChannelPlug()->getValue();
std::string alphaChannel;
ConstStringVectorDataPtr inChannelNamesPtr;
bool ignoreMissingAlpha;

ChannelDataProcessor::hashChannelData( output, context, h );
{
ImagePlug::GlobalScope c( context );
alphaChannel = alphaChannelPlug()->getValue();
inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
ignoreMissingAlpha = ignoreMissingAlphaPlug()->getValue();
}

inPlug()->channelDataPlug()->hash( h );
const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
{
if( ignoreMissingAlpha )
{
h = inPlug()->channelDataPlug()->hash();
return;
}
else
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
}
}

ChannelDataProcessor::hashChannelData( output, context, h );

ImagePlug::ChannelDataScope channelDataScope( context );
channelDataScope.setChannelName( &alphaChannel );
Expand All @@ -99,25 +132,33 @@ void Unpremultiply::hashChannelData( const GafferImage::ImagePlug *output, const

void Unpremultiply::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const
{
std::string alphaChannel = alphaChannelPlug()->getValue();
std::string alphaChannel;
ConstStringVectorDataPtr inChannelNamesPtr;
bool ignoreMissingAlpha;

if ( channel == alphaChannel )
{
return;
ImagePlug::GlobalScope c( context );
alphaChannel = alphaChannelPlug()->getValue();
inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
ignoreMissingAlpha = ignoreMissingAlphaPlug()->getValue();
}

ConstStringVectorDataPtr inChannelNamesPtr;
if ( channel == alphaChannel )
{
ImagePlug::GlobalScope c( context );
inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
return;
}

const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
{
std::ostringstream channelError;
channelError << "Channel '" << alphaChannel << "' does not exist";
throw( IECore::Exception( channelError.str() ) );
if( ignoreMissingAlpha )
{
return;
}
else
{
throw IECore::Exception( fmt::format( "Channel '{}' does not exist", alphaChannel ) );
}
}

ImagePlug::ChannelDataScope channelDataScope( context );
Expand Down

0 comments on commit a3f9440

Please sign in to comment.