Hack 9 Video Fade to Black and Fade to White

figs/moderate.gif figs/hack9.gif

Create fade to black and fade to white video transitions.

Transitions can be applied to both still images and videos. For example, you can apply a color transformation to a video [Hack #8] to create instantaneous color effects. This hack applies a color transformation over time to create fade effects.

Transitions Over Time

For a time-based transition, we need a code structure that allows us to apply incremental changes to the color values over a number of frames. Two common transitions are "fade to black" and "fade to white." The color transform objects you need to end up with an all-black or all-white image are as follows:

transToBlack ={ra:100, rb:-255, ga:100, gb:-255, 

               ba:100, bb:-255, aa:100, ab:0};

transToWhite ={ra:100, rb:255, ga:100, gb:255,

               ba:100, bb:255, aa:100, ab:0};

You will notice that these transforms change only the offset values (to either +255 or -255). The result is that the RGB value R:255, G:255, B:255 is added to each pixel to create a fade to white, or subtracted from each pixel to create a fade to black. Given that the three color channels have a range of 0 to 255 (0x00 to 0xFF in hex), this fades each pixel to either 255 (white) or 0 (black), regardless of the pixel's original color.

The following code gives us a way of spreading this color change over a number of frames to produce a fade over time:

function trans(targetClip, frames, targetTrans) {

  var transCol = new Color(targetClip);

  // Get the current color transform applied to the clip, if any

  var getTrans = transCol.getTransform( );

  var diffTrans = new Object( );

  // Calculate the differences for each of the 8 properties

  // and store them in the diffTrans color object.

  for (var i in targetTrans) {

    diffTrans[i] = (targetTrans[i]-getTrans[i])/frames;

  }

  targetClip.onEnterFrame = function( ) {

    var getTrans = transCol.getTransform( );

    for (var i in diffTrans) {

      getTrans[i] += diffTrans[i];

    }

    transCol.setTransform(getTrans);

    frames--;

    if (frames == 0) {

      // Explicitly set the target transform just in case the 

      // target numbers were not exactly divisible by the 

      // number of frames, then clean up.

      transCol.setTransform(targetTrans);

      delete this.onEnterFrame;

      delete transCol;

    }

  };

}

We need to know three things to animate a color video transition: the target clip (inside which the video is embedded), the number of frames we want the transition to occur for, and the transition type, such as fade to black or fade to white (or more correctly, the associated color transform object).

This is all covered by the arguments to our trans( ) function: targetClip, frames, and targetTrans. For example, here we use it to set a fade to white transition on a video within the myVideo_mc clip, over a duration of 24 frames:

transToWhite = {ra:100, rb:255, ga:100, gb:255, ba:100, bb:255, aa:100, ab:0};

trans(myVideo_mc, 24, transToWhite);

The trans( ) function does three things.

First, it extracts the current color transform object applied to the target clip, using Color.getTransform( ), and stores it in getTrans. Then, it sets up an object, diffTrans, which tells us how much we need to add to getTrans every frame to end up at the final transform, targetTrans, within the specified number of frames. Assuming that no other transforms have been applied in the authoring tool, getTrans is always:

{ra:100, rb:0, ga:100, gb:0, ba:100, bb:0, aa:100, ab:0}

Why? If no transform has been applied, getTrans is a neutral transform object?the same one you will see in the Advanced Effects panel, shown in Figure 2-1, when no color changes are applied.

And targetTrans is whatever was specified in the trans( ) function invocation. For fade to white, targetTrans is:

{ra:100, rb:255, ga:100, gb:255, ba:100, bb:255, aa:100, ab:0}

Subtracting targetTrans from getTrans and dividing by the number of frames gives us the difference to be applied during each frame iteration. We store these values in the diffTrans object:

diffTrans[i] = (targetTrans[i]-getTrans[i])/frames;

Following through with our preceding example, including a 24-frame transition, diffTrans would be:

{ra: 0 rb:10.625, ga:0, gb:10.625, ba:0, bb:10.625, aa:0, ab:0}

Finally, the trans( ) function needs to set up an onEnterFrame( ) handler to animate our color transition from getTrans to targetTrans over time. This is accomplished by defining a function and assigning it to the onEnterFrame property, as shown in the preceding code example.

In all honesty, applying a transition over a set number of frames doesn't make the most sense. Videos are time-based media, so we should rightly perform the color transformation over multiple steps using a time-based interval (created with setInterval( )). Time-based intervals make it easier to use the effect with a video and make the transition duration independent of the timeline's frame rate.

So the frame-based technique really is more useful for applying color transformations to movie clips that don't contain videos. We demonstrated the time-based method earlier [Hack #8], so let's examine the frame-based technique more closely here.

The onEnterFrame( ) handler defined within trans( ) adds diffTrans to the current transform object each frame until the effect is completed:

for (var i in diffTrans) {

  getTrans[i] += diffTrans[i];

}

transCol.setTransform(getTrans);

At the end of the transition, the transform may not have reached its target due to rounding errors, so we need to explicitly set it just to make sure. After we have done that, all we need to do to finish is clean up.

frames--;

if (frames == 0) {

  // Explicitly set the target transform just in case the 

  // target numbers were not exactly divisible by the 

  // number of frames, then clean up.

  transCol.setTransform(targetTrans);

  delete this.onEnterFrame;

  delete transCol;

}

Try running the script with other transformations, such as those earlier in this hack and the preceding hack.

Final Thoughts

The cool thing about the preceding two hacks is that they can target any movie clip, not just those containing video. For example, targeting _root allows you to apply transitions to the entire SWF file at runtime (although this might be too processor-intensive to be practical in some situations). As well as producing some cool effects, color transforms also have practical uses: inverting the color of all content on the Stage for 100 milliseconds might signify an incorrect response (Windows changes the screen color briefly to alert users of errors if you enable accessibility options, because a beep noise isn't audible to hearing-impaired users).

Adding video-like color transitions to something that is static (such as a bitmap) also has a big advantage: it can fool users into thinking that they are watching a video, particularly if you are really sly and have actual video portions mixed into the sequence. This technique works wonders for hiding your video preloads!

The more observant among you may have noticed that I haven't altered the alpha channel in the color transformation examples presented. However, to adjust the alpha channel, simply specify a transform object in which the ra, ga, ba, or aa properties are not equal to 100. By adjusting the alpha channel, you can start doing some really cool things such as cross-fades, in which you fade from one video clip into another (or even better, cross-fade seamlessly between video and Flash vector content). Alpha transitions are processor-intensive, but lucky for us, Flash Player 7 has a much faster video playback engine, so even that is not a big problem anymore.

The same principles apply to sound transforms. You can use sound transform objects supported by the Sound class to add scripted volume effects and cross-speaker fades [Hack #60] .