In this post, we will animate the clipping area using the Silverlight animation technique (ie, no more the timer).
This time, the painting is "The station in the forest" from Paul Delvaux, a Belgian surrealist painter (1897-1994).
Project / source code
Again, as in part II, we display two (identical) images at the same location : the first one, in the background, with an opacity of 0.2 and the second one, on top, with a clipping area. The clipping area, representing a keyhole, is a closed figure (named pf) made of an arc segment and two line segments (since it's a closed figure, there is no need to specify the closing line segment) :
<Image Source="Delvaux.jpg" Width="400" Height="270" Opacity="0.2" />
<Image Source="Delvaux.jpg" Width="400" Height="270" >
<Image.Clip>
<PathGeometry >
<PathFigure x:Name="pf" StartPoint="20,35" IsClosed="True" >
<ArcSegment IsLargeArc="True" Point="40,35" Size="20,20" SweepDirection="Clockwise" />
<LineSegment Point="45,75" />
<LineSegment Point="15,75" />
</PathFigure>
</Image.Clip>
</Image>
We'll move and scale the clipping area, ie the keyhole. To do so, we first define two transforms for the second image : a TranslateTranform (name keyholeXlate) and a ScaleTransform (named keyholeScale) :
<Image Source="Delvaux.jpg" Width="400" Height="270" >
<Image.Clip>
<PathGeometry>
<PathFigure ..... >
.....
</PathFigure>
<PathGeometry.Transform>
<TransformGroup>
<TranslateTransform x:Name="keyholeXlate"/>
<ScaleTransform x:Name="keyholeScale" />
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
</Image.Clip>
</Image>
We now define the animation. We have four elements to animate (not counting a last and dummy - though important - animation, whose purpose will be explained later on) :
- we make the keyhole bigger and bigger : two ScaleTransform with ScaleX and ScaleY jumping from 1 to 5 in 15 seconds,
- an horizontal move (TranslateTransform) in three steps (thus with four DoubleAnimationUsingKeyFrames) to sweep the painting in zigzag,
- a vertical move (TranslateTransform).
<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
<Grid.Resources>
<Storyboard x:Name="stb" RepeatBehavior="Forever" >
<DoubleAnimation Storyboard.TargetName="keyholeScale" Storyboard.TargetProperty="ScaleX"
From="1" To="5" Duration="0:0:15" />
<DoubleAnimation Storyboard.TargetName="keyholeScale" Storyboard.TargetProperty="ScaleY"
From="1" To="5" Duration="0:0:15" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="keyholeXlate"
Storyboard.TargetProperty="X" >
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:5" Value="120" />
<LinearDoubleKeyFrame KeyTime="0:0:10" Value="-17" />
<LinearDoubleKeyFrame KeyTime="0:0:15" Value="50" />
</DoubleAnimationUsingKeyFrames >
<DoubleAnimation Storyboard.TargetName="keyholeXlate" Storyboard.TargetProperty="Y"
From="0" To="30" Duration="0:0:15" />
<PointAnimation Storyboard.TargetName="pf" Storyboard.TargetProperty="StartPoint"
From="20,35" To="20,35.001" Duration="0:0:15" />
</Storyboard>
</Grid.Resources>
.....
</Grid>
Why do we move the StartPoint vertically from 35 to 35.001 in 15 seconds ? Such an unnoticeable animation seems to be ridiculous, to say the least ! This line is just there to make things work ! There is a bug in beta 2 : without such a dummy move, nothing is ever redrawn and nothing happens !
Of course, we still need to execute stb.Begin() in the function handling the Loaded event.
Now, let's change things to have the keyhole fixed and the painting animated :
Project / source code
The image in front is a painting named "Castel in the Pyrrhénées" from René Magritte, another Belgian surrealist painter (1898-1967). A black keyhole was inserted in this masterpiece (shame on me). Using Microsoft Photo Editor, we force black as the transparent color and save the image in png format.
The two images (Delvaux in the background and Magritte in the foreground) are inserted in a canvas whose size is the size of the foreground image. The canvas is clipped to the foreground image :
<Canvas Width="266" Height="460" Clip="M0,0 h266 v460 h-266 z" >
<Image x:Name="img" Source="Delvaux.jpg" Width="400" Height="270" >
.....
</Image>
<Image Source="Magritte.png" Width="266" Height="460" />
</Canvas>
We now define an animation for the background image, in four step : from left to right, from top to bottom, from right to left and finally from bottom to top :
<Image x:Name="img" Source="Delvaux.jpg" Width="400" Height="270" >
<Image.Resources>
<Storyboard x:Name="stb" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="img"
Storyboard.TargetProperty="(Canvas.Left)" >
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="105" />
<LinearDoubleKeyFrame KeyTime="0:0:5" Value="-210" />
<LinearDoubleKeyFrame KeyTime="0:0:7" Value="-210" />
<LinearDoubleKeyFrame KeyTime="0:0:12" Value="105" />
<LinearDoubleKeyFrame KeyTime="0:0:14" Value="105" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="img"
Storyboard.TargetProperty="(Canvas.Top)" >
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="105" />
<LinearDoubleKeyFrame KeyTime="0:0:5" Value="105" />
<LinearDoubleKeyFrame KeyTime="0:0:7" Value="10" />
<LinearDoubleKeyFrame KeyTime="0:0:12" Value="10" />
<LinearDoubleKeyFrame KeyTime="0:0:14" Value="105" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Image.Resources>
</Image>
See you for a forthcoming post on visual effects.