def testEnabledOnlyAffectsMetadata( self ) : m = GafferImage.ImageMetadata() cs = GafferTest.CapturingSlot( m.plugDirtiedSignal() ) m["enabled"].setValue( False ) self.assertEqual( { x[0] for x in cs }, { m["enabled"], m["out"]["metadata"], m["out"] } )
def __testMetadataDoesNotAffectPixels( self, ext, overrideMetadata = {}, metadataToIgnore = [] ) : r = GafferImage.ImageReader() r["fileName"].setValue( self.__rgbFilePath+"."+ext ) d = GafferImage.DeleteImageMetadata() d["in"].setInput( r["out"] ) m = GafferImage.ImageMetadata() m["in"].setInput( d["out"] ) # lets tell a few lies # IPTC:Creator will have the current username appended to the end of # the existing one, creating a list of creators. Blank it out for # this test d["names"].setValue( "IPTC:Creator" ) m["metadata"].addMember( "PixelAspectRatio", IECore.FloatData( 2 ) ) m["metadata"].addMember( "oiio:ColorSpace", IECore.StringData( "Rec709" ) ) m["metadata"].addMember( "oiio:BitsPerSample", IECore.IntData( 8 ) ) m["metadata"].addMember( "oiio:UnassociatedAlpha", IECore.IntData( 1 ) ) m["metadata"].addMember( "oiio:Gamma", IECore.FloatData( 0.25 ) ) testFile = self.__testFile( "metadataHasNoAffect", "RGBA", ext ) self.failIf( os.path.exists( testFile ) ) w = GafferImage.ImageWriter() w["in"].setInput( m["out"] ) w["fileName"].setValue( testFile ) w["channels"].setValue( IECore.StringVectorData( m["out"]["channelNames"].getValue() ) ) testFile2 = self.__testFile( "noNewMetadata", "RGBA", ext ) self.failIf( os.path.exists( testFile2 ) ) w2 = GafferImage.ImageWriter() w2["in"].setInput( d["out"] ) w2["fileName"].setValue( testFile2 ) w2["channels"].setValue( IECore.StringVectorData( r["out"]["channelNames"].getValue() ) ) inMetadata = w["in"]["metadata"].getValue() self.assertEqual( inMetadata["PixelAspectRatio"], IECore.FloatData( 2 ) ) self.assertEqual( inMetadata["oiio:ColorSpace"], IECore.StringData( "Rec709" ) ) self.assertEqual( inMetadata["oiio:BitsPerSample"], IECore.IntData( 8 ) ) self.assertEqual( inMetadata["oiio:UnassociatedAlpha"], IECore.IntData( 1 ) ) self.assertEqual( inMetadata["oiio:Gamma"], IECore.FloatData( 0.25 ) ) with Gaffer.Context() : w["task"].execute() w2["task"].execute() self.failUnless( os.path.exists( testFile ) ) self.failUnless( os.path.exists( testFile2 ) ) after = GafferImage.ImageReader() after["fileName"].setValue( testFile ) before = GafferImage.ImageReader() before["fileName"].setValue( testFile2 ) inImage = w["in"].image() afterImage = after["out"].image() beforeImage = before["out"].image() inImage.blindData().clear() afterImage.blindData().clear() beforeImage.blindData().clear() self.assertEqual( afterImage, inImage ) self.assertEqual( afterImage, beforeImage ) self.assertEqual( after["out"]["format"].getValue(), r["out"]["format"].getValue() ) self.assertEqual( after["out"]["format"].getValue(), before["out"]["format"].getValue() ) self.assertEqual( after["out"]["dataWindow"].getValue(), r["out"]["dataWindow"].getValue() ) self.assertEqual( after["out"]["dataWindow"].getValue(), before["out"]["dataWindow"].getValue() ) afterMetadata = after["out"]["metadata"].getValue() beforeMetadata = before["out"]["metadata"].getValue() expectedMetadata = r["out"]["metadata"].getValue() # they were written at different times so we can't expect those values to match beforeMetadata["DateTime"] = afterMetadata["DateTime"] expectedMetadata["DateTime"] = afterMetadata["DateTime"] # the writer adds several standard attributes that aren't in the original file expectedMetadata["Software"] = IECore.StringData( "Gaffer " + Gaffer.About.versionString() ) expectedMetadata["HostComputer"] = IECore.StringData( platform.node() ) expectedMetadata["Artist"] = IECore.StringData( os.environ["USER"] ) expectedMetadata["DocumentName"] = IECore.StringData( "untitled" ) self.__addExpectedIPTCMetadata( afterMetadata, expectedMetadata ) for key in overrideMetadata : expectedMetadata[key] = overrideMetadata[key] beforeMetadata[key] = overrideMetadata[key] for key in metadataToIgnore : if key in expectedMetadata : del expectedMetadata[key] if key in beforeMetadata : del beforeMetadata[key] if key in afterMetadata : del afterMetadata[key] for metaName in expectedMetadata.keys() : self.assertTrue( metaName in afterMetadata.keys(), "Writer Metadata missing expected key \"{}\" set to \"{}\" : {}".format(metaName, str(expectedMetadata[metaName]), ext) ) self.assertEqual( expectedMetadata[metaName], afterMetadata[metaName], "Metadata does not match for key \"{}\" : {}".format(metaName, ext) ) for metaName in beforeMetadata.keys() : self.assertTrue( metaName in afterMetadata.keys(), "Writer Metadata missing expected key \"{}\" set to \"{}\" : {}".format(metaName, str(beforeMetadata[metaName]), ext) ) self.assertEqual( beforeMetadata[metaName], afterMetadata[metaName], "Metadata does not match for key \"{}\" : {}".format(metaName, ext) )
def __testMetadataDoesNotAffectPixels( self, ext, overrideMetadata = {}, metadataToIgnore = [] ) : reader = GafferImage.ImageReader() reader["fileName"].setValue( self.__rgbFilePath+"."+ext ) # IPTC:Creator will have the current username appended to the end of # the existing one, creating a list of creators. Blank out the initial # value for this test. regularMetadata = GafferImage.DeleteImageMetadata() regularMetadata["in"].setInput( reader["out"] ) regularMetadata["names"].setValue( "IPTC:Creator" ) # Add misleading metadata that if taken at face value could cause # us to write the wrong information to the file. Our governing rule # is that metadata is just "along for the ride", and should never # have any effect on the content of images themselves. misleadingMetadata = GafferImage.ImageMetadata() misleadingMetadata["in"].setInput( regularMetadata["out"] ) misleadingMetadata["metadata"].addMember( "PixelAspectRatio", IECore.FloatData( 2 ) ) misleadingMetadata["metadata"].addMember( "oiio:ColorSpace", IECore.StringData( "Rec709" ) ) misleadingMetadata["metadata"].addMember( "oiio:BitsPerSample", IECore.IntData( 8 ) ) misleadingMetadata["metadata"].addMember( "oiio:UnassociatedAlpha", IECore.IntData( 1 ) ) misleadingMetadata["metadata"].addMember( "oiio:Gamma", IECore.FloatData( 0.25 ) ) # Create ImageWriters to write out the images with regular # and misleading metadata. regularWriter = GafferImage.ImageWriter() regularWriter["in"].setInput( regularMetadata["out"] ) regularWriter["fileName"].setValue( self.__testFile( "regularMetadata", "RGBA", ext ) ) self.failIf( os.path.exists( regularWriter["fileName"].getValue() ) ) misledWriter = GafferImage.ImageWriter() misledWriter["in"].setInput( misleadingMetadata["out"] ) misledWriter["fileName"].setValue( self.__testFile( "misleadingMetadata", "RGBA", ext ) ) self.failIf( os.path.exists( misledWriter["fileName"].getValue() ) ) # Check that the writer is indeed being given misleading metadata. m = misledWriter["in"]["metadata"].getValue() self.assertEqual( m["PixelAspectRatio"], IECore.FloatData( 2 ) ) self.assertEqual( m["oiio:ColorSpace"], IECore.StringData( "Rec709" ) ) self.assertEqual( m["oiio:BitsPerSample"], IECore.IntData( 8 ) ) self.assertEqual( m["oiio:UnassociatedAlpha"], IECore.IntData( 1 ) ) self.assertEqual( m["oiio:Gamma"], IECore.FloatData( 0.25 ) ) # Execute the writers regularWriter["task"].execute() misledWriter["task"].execute() self.failUnless( os.path.exists( regularWriter["fileName"].getValue() ) ) self.failUnless( os.path.exists( misledWriter["fileName"].getValue() ) ) # Make readers to read back what we wrote out misledReader = GafferImage.ImageReader() misledReader["fileName"].setInput( misledWriter["fileName"] ) regularReader = GafferImage.ImageReader() regularReader["fileName"].setInput( regularWriter["fileName"] ) # Check that the pixel data, format and data window has not # been changed at all, regardless of which metadata # was provided to the writers. self.assertImagesEqual( misledWriter["in"], misledReader["out"], ignoreMetadata = True ) self.assertImagesEqual( misledReader["out"], regularReader["out"], ignoreMetadata = True ) # Load the metadata from the files, and figure out what # metadata we expect to have based on what we expect the # writer to add, and what the reader adds automatically # during loading. misledReaderMetadata = misledReader["out"]["metadata"].getValue() regularReaderMetadata = regularReader["out"]["metadata"].getValue() expectedMetadata = regularMetadata["out"]["metadata"].getValue() expectedMetadata["DateTime"] = regularReaderMetadata["DateTime"] expectedMetadata["Software"] = IECore.StringData( "Gaffer " + Gaffer.About.versionString() ) expectedMetadata["HostComputer"] = IECore.StringData( platform.node() ) expectedMetadata["Artist"] = IECore.StringData( os.environ["USER"] ) expectedMetadata["DocumentName"] = IECore.StringData( "untitled" ) expectedMetadata["fileFormat"] = regularReaderMetadata["fileFormat"] expectedMetadata["dataType"] = regularReaderMetadata["dataType"] self.__addExpectedIPTCMetadata( regularReaderMetadata, expectedMetadata ) for key, value in overrideMetadata.items() : expectedMetadata[key] = value regularReaderMetadata[key] = value # Now check that we have what we expect. for metaName in expectedMetadata.keys() : if metaName in metadataToIgnore : continue self.assertTrue( metaName in misledReaderMetadata.keys(), "Writer Metadata missing expected key \"{}\" set to \"{}\" : {}".format(metaName, str(expectedMetadata[metaName]), ext) ) if metaName == "DateTime" : dateTimeDiff = datetime.datetime.strptime( str( expectedMetadata[metaName] ), "%Y:%m:%d %H:%M:%S" ) - datetime.datetime.strptime( str( misledReaderMetadata[metaName] ), "%Y:%m:%d %H:%M:%S" ) self.assertLessEqual( abs( dateTimeDiff ), datetime.timedelta( seconds=1 ) ) else : self.assertEqual( expectedMetadata[metaName], misledReaderMetadata[metaName], "Metadata does not match for key \"{}\" : {}".format(metaName, ext) ) for metaName in regularReaderMetadata.keys() : if metaName in metadataToIgnore : continue self.assertTrue( metaName in misledReaderMetadata.keys(), "Writer Metadata missing expected key \"{}\" set to \"{}\" : {}".format(metaName, str(expectedMetadata[metaName]), ext) ) if metaName == "DateTime" : dateTimeDiff = datetime.datetime.strptime( str( regularReaderMetadata[metaName] ), "%Y:%m:%d %H:%M:%S" ) - datetime.datetime.strptime( str( misledReaderMetadata[metaName] ), "%Y:%m:%d %H:%M:%S" ) self.assertLessEqual( abs( dateTimeDiff ), datetime.timedelta( seconds=1 ) ) else : self.assertEqual( regularReaderMetadata[metaName], misledReaderMetadata[metaName], "Metadata does not match for key \"{}\" : {}".format(metaName, ext) )
def testLayerMapping( self ) : constant1 = GafferImage.Constant() constant1['color'].setValue( imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ) constant1["format"].setValue( GafferImage.Format( 10, 10, 1.000 ) ) metadata1 = GafferImage.ImageMetadata() metadata1["in"].setInput( constant1["out"] ) metadata1["metadata"].addMember( "test", 1 ) constant2 = GafferImage.Constant() constant2['color'].setValue( imath.Color4f( 0.2, 0.4, 0.6, 0.8 ) ) constant2["format"].setValue( GafferImage.Format( 20, 20, 1.000 ) ) metadata2 = GafferImage.ImageMetadata() metadata2["in"].setInput( constant2["out"] ) metadata2["metadata"].addMember( "test", 2 ) switch = GafferImage.ImageSwitch() switch["in"][0].setInput( metadata1["out"] ) switch["in"][1].setInput( metadata2["out"] ) e = Gaffer.Expression() switch.addChild( e ) e.setExpression( 'parent["index"] = context["collect:layerName"] != "A"', "python" ) collect = GafferImage.CollectImages() collect["in"].setInput( switch["out"] ) # Metadata and format are driven by the first layer collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A', 'B' ] ) ) self.assertEqual( collect["out"]["format"].getValue(), GafferImage.Format( 10, 10, 1) ) self.assertEqual( collect["out"]["metadata"].getValue(), IECore.CompoundData( { "test" : 1 } ) ) collect["rootLayers"].setValue( IECore.StringVectorData( [ 'B', 'A' ] ) ) self.assertEqual( collect["out"]["format"].getValue(), GafferImage.Format( 20, 20, 1) ) self.assertEqual( collect["out"]["metadata"].getValue(), IECore.CompoundData( { "test" : 2 } ) ) collect["rootLayers"].setValue( IECore.StringVectorData( [] ) ) self.assertEqual( collect["out"]["format"].getValue(), constant1["format"].getDefaultFormat( Gaffer.Context.current() ) ) self.assertEqual( collect["out"]["metadata"].getValue(), IECore.CompoundData() ) sampler = GafferImage.ImageSampler( "ImageSampler" ) sampler["pixel"].setValue( imath.V2f( 1, 1 ) ) sampler["channels"].setValue( IECore.StringVectorData( [ "A.R", "A.G","A.B","A.A" ] ) ) sampler["image"].setInput( collect["out"] ) collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A' ] ) ) self.assertEqual( list(collect["out"]["channelNames"].getValue()), [ "A.R", "A.G", "A.B", "A.A" ] ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ) # Test simple duplicate collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A', 'A' ] ) ) self.assertEqual( list(collect["out"]["channelNames"].getValue()), [ "A.R", "A.G", "A.B", "A.A" ] ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ) collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A', 'B' ] ) ) self.assertEqual( list(collect["out"]["channelNames"].getValue()), [ "A.R", "A.G", "A.B", "A.A", "B.R", "B.G", "B.B", "B.A" ] ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ) sampler["channels"].setValue( IECore.StringVectorData( [ "B.R", "B.G","B.B","B.A" ] ) ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.2, 0.4, 0.6, 0.8 ) ) # Test overlapping names take the first layer constant1["layer"].setValue( "B" ) collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A', 'A.B' ] ) ) sampler["channels"].setValue( IECore.StringVectorData( [ "A.B.R", "A.B.G","A.B.B","A.B.A" ] ) ) self.assertEqual( list(collect["out"]["channelNames"].getValue()), [ "A.B.R", "A.B.G", "A.B.B", "A.B.A" ] ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ) collect["rootLayers"].setValue( IECore.StringVectorData( [ 'A.B', 'A' ] ) ) self.assertEqual( list(collect["out"]["channelNames"].getValue()), [ "A.B.R", "A.B.G", "A.B.B", "A.B.A" ] ) self.assertEqual( sampler["color"].getValue(), imath.Color4f( 0.2, 0.4, 0.6, 0.8 ) )