Exploring the Microsoft Client Continuum

Image Sequencing

Image sequencing. The Holy Grail of Silverlight hacks for developers coming from Flash. The reason this Flash staple may seem more cumbersome to reproduce in Silverlight, though, is because of a key difference between the two environments. The primary animation metaphor in Flash is frame based animations, while in Silverlight it is time based.

When using XAML Storyboards, it is a lot less important what your Silverlight playback frame rate is. You tell the Storyboard at what time you want a particular property to have a specific value and it gets done. In Flash, on the other hand, you say "I want this frame to look like this, and I want that frame to look like that." Many may find it easier to be much more specific and precise with Silverlight's time based animations when dealing with vectors and motion. However, the frame based model that drives image sequencing gets a bit harder to figure out.

There are three main approaches many Flash developers try when attempting to duplicate an image sequence in Silverlight. The first one is usually to stack all of the image files on top of each other and control their Opacity. This is the least optimal of the approaches since transparent elements on the screen still take a toll on the processor. Also, for every image you turn on, you need to turn another one off. I don't recommend this.

The second approach is similar to the first, but instead of Opacity the developer sets the Visibility of each Image to Visible or Collapsed. This is much more efficient then simply toggling the Opacity, though the approach still requires the added burden of monitoring two different elements at a time; the element becoming Visible and the element becoming visually Collapsed. However, there are definitely times when this technique may be the right approach.

Personally, the third approach is the one I use most often and the one we will demonstrate here. We will arrange the images in a film strip while clipping the strip down to the dimensions of a single frame. Then we can control the animation by moving the strip a fixed distance every given interval.

Project 1. Manipulating a Film Strip

In this first project, we will build out the film strip and clipping structure. Image sequencing is usually created to either have the current frame influenced by the user's behavior or to have it run sequentially, either stopping when the animation is completed, playing the animation in reverse upon completion, or looping the animation continually. Here, we will look at controlling the current position based on the cursor while in the next project we will look at continually looping the film strip to create an animation.

Often times, image sequencing is used for interface elements that have been rendered in 3D or when the project requires a realism that would be prohibitively hard to achieve in vectors. Also, there are times when the images have already been auto generated by another program. Common examples may be elements with elaborate particle or blur effects, game character walk cycles, or interface panels that transform spatially between states. Since Silverlight does not support alpha channel videos as of yet, Image Sequencing becomes the only way to handle this problem effectively.

For this example, I wanted to have a Globe the user can spin by moving their cursor. The background of each Image in the sequence needs to be transparent, so the user can see behind the Globe to the other elements on the page. Therefore, I created a simple animation in After Effects and rendered it accordingly. After dropping my Frame Rate in Render Settings, I set my Output Mode as follows:

After rendering the spinning 3D globe into a sequence of 37 PNG images with transparent background, my folder looked like this:

If I were building this in Flash or Silverlight, the above step would still be similar and a very common way of creating transparent Image Sequences. After Effects makes things much easier by giving you output name settings, so you can reference these images in a logically sequential order.

Now let's add these images to a new Silverlight Project we will create named Lesson09_a. We also create a folder under this Silverlight project and name the folder images. The usual changes have been made to Page.xaml, including modifying LayoutRoot to be a Canvas and adding a Loaded handler to it. I added a LinearGradientBrushdientBrush to the background of LayoutRoot so I can see transparency of the images at work. But the important lines are found in Line 13 through Line 16 below:

This is the basic framework for building out our movie strip and clipping frame. My outer Canvas is named frame. Each of the images I generated from After Effects has a width of 150px and a height of 140px. I will use this as my clipping data for frame, but for now, let's leave it with no clip defined so we can see the images getting attached. I also added a temporary, semi-opaque background to (Line 14) so you can better see what the clipping region will be. Frame has a nested Canvas on Line 15 that is named holder. It is here that we will add all the Images and arrange them horizontally. Let's do that next by going to Page.xaml.cs.

With this simple loop, we are dynamically creating a BitmapImage reference for each image in our ../images/ folder and creating a new Image object to display it. Line 30 makes sure that they are all spaced exactly one image width apart and we display them by adding them to the visual children of our holder canvas. Getting ready for the next bit of code, we also added a MouseMove() handler on Line 33 through Line 38.

If you run it now, you'll see the first few globes stacked next to each other running off the page, though the first Globe should be placed properly in the semi-white square indicating the boundaries of frame which we will clip later. ter.

Let's add some MouseMove code to animate the sequence based on user interaction. Here it is:

If we go back to Page.xaml.cs and remove the temporary Background color of frame and add a clipping region, it ends up looking like this:

The basic effect is finished and here is the result:

Get Microsoft Silverlight

Personally, I find that a little boring and amateurish. I think it would be much more interesting if we combined some of the trigonometry from Lesson08 and allowed you to rotate the Globe more like a dial. I'll add an Ellipse to LayoutRoot named bkg that goes behind the frame canvas while also replacing the MouseMove() handler with the following code:

And the result is much better:

Get Microsoft Silverlight

Project 2. Advanced Image Sequencing Effects

Let's end this lesson looking at a more advanced example. You may have noticed that the above exercises were made easier by having the PNG files already added to your project in the ../images/ folder. As such, they were treated as resources when the solution was built and therefore included in the XAP file that gets generated. The down side to this, therefore, is that the Silverlight XAP file grew to nearly 2MB to accommodate the inclusion of all 37 PNG images. Also, we should be able to tie in a Storyboard to have the animated images continually loop. Finally, what about situations where we want our assets to be downloaded separately, but we have them stored in a .ZIP file for better compression and transmission? In this lesson, we'll explore all of these advanced topics.

Since we are going to be consuming a .ZIP file on our client, we will need to work with the more powerful WebClient object in Silverlight we first visited in Lesson 05. Therefore, if you are following along and wish to duplicate this solution, make sure you let Visual Studio create a Web Hosting project for you. Interacting with a WebClient object requires you to run the solution in a hosted environment. You can't simply open the HTML from the file system.

Our initial modifications to Page.xaml should look very similar to what we did above, though I've added a couple TextBlocks which we will get to shortly. Here are the updates to Page.xaml:

Once we get the animation loaded and working, we are going to do a couple modifications to the above code to allow Scaling and also create a reflection animation. But for now, this is all we need in Page.xaml.

I've added a Loaded handler in User Control up top, so lets go to Page.xaml.cs and start adding our logic:

The code that creates and prepares the WebClient object is found on Lines 35 through 46. We want to add event handlers during DownloadProgressChanged to inform the user of how much we've downloaded and we also need to know when the .ZIP download has been completed. Line 41 is where we tell our WebClient object named wc to pull down the .ZIP from the server.

I added a .ZIP file of all 37 Red Globe images we used in our first example to my Silverlight Web Host project like so:

Since the .ZIP exists on the Web Hosting server and not in my XAML file as a resource, the initial size of my XAML file will be greatly reduced.

The WebClient handlers, dynamic image creation and basic animation loop look like this:

Notice how the zipData stream is queried at Line 70 to provide the an inner StreamResourceInfo for each of the images in redGlobe.zip. We can then turn each individual image stream into a BitmapImage and use this as the Source for a proper Image object to display on screen in the holder. Once the film strip is created, we can then call our animation on Line 86 and the basic animation loop begins on Lines 89 to 97. By default, Silverlight runs at 60 frames a second so I added a dampener on Line 92 to slow down my index. Line 95 sets the condition to repeat the animation loop by starting the index back to zero after each image has been on the screen for a total of 3 frames each.

If you run it right now, you'll see the Red Globe animation being loaded into our Silverlight movie and playing next to the Silverlight text on screen. This is all the code needed for loading a sequence of PNG images in a .ZIP file from the hosting server and having them animate continually in your Silverlight movie.

However, let's make a couple more additions to spice this project up, since it still looks a little boring...

What we're going to do is add a reflection to the globe by adding another frame and holder to our screen on Line 28 through Line 44 below. This reflection will have its ScaleY inverted at Line 41 within a Canvas RenderTransform and will also have an OpacityMask set at Line 33 to create the gradiated transparency effect common to these types of glossy reflections. The reflection canvas has its own nested Canvas for its filmstrip called rHolder found on Line 44. We will then wrap up the original frame and the reflection Canvas together in a parent Canvas called globeComp starting at Line 24 which will server as our composite collection. It is this parent Canvas globeComp which we will Move and Scale (Line 26) around the screen to create the illusion of three dimensional space.

Here are the updates to Page.xaml:

In our code behind file, we need to modify buildStrip() to attach images to rHolder in reflection and we also need to modify our sb.Completed handler with our additional animation procedures.

Here is the updated buildStrip function:

Since we want to be following the cursor within our animation loop, we modified the initial UserControl_Loaded function to update a public mouse point with the current cursor position. Also, we want to sell the illusion of 3D by swapping depths between globeComp and the textLayer, so we also initialized specific ZIndex Properties for them to be used in our animation loop.

Here are our changes to the Loaded event:

And here is our updated animation loop:

Our red globe animation now has a reflection and moves around the screen with added depth. These additions have helped up sell the effect and made the experience richer.

Here is the finished Silverlight result:

Get Microsoft Silverlight

Additional Resources

Two great rotating Earth tutorials online for After Effects if you want to try it out yourself. Use the output settings as referenced above when you have your animation ready to render:

Have a question or comment on this article? Have a suggestion for new content?
Send your feedback.
Microsoft Communities