How Flash Animation is managed by an SWF to SVG Translation Package
Steve Probets
SVG provides three methods of defining animations:
- Manipulation of the Document Object Model (DOM) via ECMAScript (JavaScript).
- Using the Synchronised Multimedia Integration Language (SMIL)
- Using SVG's own declarative animation syntax.
This document will look at how SVG objects generated from SWF files can be animated by the first of these methods, manipulation of the DOM using JavaScript.
As described elsewhere, SWF defines an animation by defining shapes and then applying positional, depth and colour transformations to those shapes when mapping them onto a stage. Each shape is given a unique identifier when it is defined enabling the following types of sequences to be specified within an SWF movie.
Frame 1 Define shape 1 Frame X Apply scaling, rotation and translation (transformation matrix) to shape 1 Place shape 1 at given depth Frame Y Remove shape 1 Apply new transformation matrix to shape 1 Apply colour transformation to shape 1 Place shape 1 at given depthThis enables representations of shapes to be specified and manipulated in a compact manner. For instance, should a given animation require a blue square to move from top left to bottom right of the stage whilst a yellow rectangle moves from bottom left to top right, with the square being displayed on top of the rectangle if the shapes occupy the same area of the stage, then this can be achieved by specifying one shape and manipulating instances of the shape as the animation progresses. A semantic description of how this could be achieved in SWF follows:
Frame 1 Define shape 1 to be a red square Place instance of shape one at depth 2 Place instance of shape one at depth 1 Apply transformation matrix to translate and scale instance of shape 1 to appropriate size and place (top left) Apply transformation matrix to translate and scale instance of shape 1 to appropriate size and place (bottom left) //note that to create a rectangle the horizontal and vertical //scaling factors must differ Apply colour transform to second instance of shape 1 to change red into yellow Show the instances Place another instance of shape one at depth 1 Frame 2 Remove the instance of shape 1 at depth 1 Remove the instance of shape 1 at depth 2 Apply transformation matrix to translate and scale shape 1 to appropriate size and place (on top left to bottom right diagonal) Place instance of shape 1 at depth 2 Apply transformation matrix to translate and scale shape 1 to appropriate size and place (on bottom left to top right diagonal) Apply colour transform to change red into yellow Place another instance of shape 1 at depth 1 ...Animations of this kind can be recreated in SVG using JavaScript functions to manipulate the DOM. In order to do this two files are generated, one contains the SVG definitions of the shapes, and the other contains the JavaScript that specifies how, when and where these shapes should be displayed in the SVG view-port. To create these files, the translation package must process the SWF file. As the shapes are encountered in SWF they are translated into SVG and written to a file (see the associated format comparisons document on the relationship of SWF shapes to SVG groups). All the shapes should be defined within a <defs> tag.
N.B. It seems likely that the <symbol> element should be used to defines these shapes, as the SVG specification indicates that this element should be used for defining template objects that will be instantiated multiple times, however current versions of the plug-in do not support this element, therefore work-arounds will be employed until such a time as the <symbol> element can be tested.
As the SWF file is processed a list is maintained of which shapes should be instantiated and at which depth they are to be displayed. Once all the shapes have been defined, instances of these shapes can be instantiated using the <use> tag.
Each shape should have one instantiation for each occurrence of the shape at a given depth. The shapes should be instantiated in depth order, this effectively specifies the stacking order for the shapes in SVG, and has to occur because there is no way to specify the depth of a shape within the SVG syntax. Once all the shapes have been instantiated they should be removed ready for the animation to start. This initial instatiation of the shapes, and then hiding the instantiations by setting the visibility property to hidden, means that it is very simple, in subsequent frames of the animation, to display shape instances at the correct depth.
If the <use> elements are given identifiers corresponding to the shape identifier with the depth appended, then JavaScript functions that manipulate the SVG items can easily be called when SWF constructs such as such as "Apply transformation matrix to shape 1" or "Place instance of shape 1 at depth 2" are encountered. Using the rectangle and square example outlined above, the SVG generated would be as follows:
<svg> <defs> <g id = "1"> <path style="..." d="..."/> </g> </defs> <use id = "instance_of_shape_1_at depth_1" href = "#1" style = "visibility: hidden"/> <use id = "instance_of_shape_1_at depth_2" href = "#1" style = "visibility: hidden"/> </svg>
The mapping of the shapes onto a SVG view-port to produce the animation is controlled by the associated HTML file. This file is generated as the SWF controls are encountered within each frame. The associated HTML file would take the following form:
<HTML> <HEAD> <script language=Java-script> function removeobj(tagid){ //JavaScript function to hide an instance from view el = document.SVGfl.getSVGDocument().getElementById(tagid) sty = el.getStyle() sty.setProperty("visibility","hidden") } function showobj(tagid,mat) { //JavaScript function to display an instance of a shape el = document.SVGfl.getSVGDocument().getElementById(tagid) sty = el.getStyle() el.setAttribute("transform","matrix(" + mat + ")") sty.setProperty("visibility","visible") } function cycleframes(frame) { if (frame == 1) { //initially set all the instances to be invisible removeobj("instance_of_shape_1_at depth_1") removeobj("instance_of_shape_1_at depth_2") //Now show only the required instances in their correct place showobj("instance_of_shape_1_at depth_1","10 0.00 0.00 10 0 0") showobj("instance_of_shape_1_at depth_2","10 0.00 0.00 20 0 100") } if (frame == 2) { showobj("instance_of_shape_1_at depth_1","10 0.00 0.00 10 10 10") showobj("instance_of_shape_1_at depth_2","10 0.00 0.00 20 10 90") } //etc. etc. if (frame < 100) { setTimeout("cycleframes(" + (frame + 1) + ")", 5) } } </script> </HEAD> <BODY onload="cycleframes(1)")<CENTER> <EMBED NAME="SVGfl" SRC="svgfile.svg" STANDBY="Loading SVG Viewer..." WIDTH="200" HEIGHT="200"> </BODY> </HTML>The JavaScript functions such as showobj and removeobj are static, the cycleframes function is the one that has to be built up dynamically during the translation process. This occurs as the SWF frames are encountered sequentially within the SWF file. Other JavaScript functions can be provided and called from within the cycleframes functions that perform colour transformations on objects etc.
Using the techniques outlined above the following SVG animations have been produced
Please note: You will need a beta release of Adobe's SVG plug-in to view the SVG. This can be obtained here. To check you have the correct release, view the "About the Adobe SVG Viewer" menu item available by right-clicking in any SVG file. If the version is "Beta Release 1, build 70" then you are OK to download the samples below. If you cannot find the "About ..." menu item, or it specifies a build no. less than 70 then you do not have the required plug-in. Also note that the files do not view properly under Netscape, use IE if possible.
File name | Flash file | SVG file |
Liquid Audio | SWF | SVG |
Audi | SWF | SVG |
Gilette | SWF | SVG |
Fatboy Slim * | SWF | SVG |
Newsflash | SWF | SVG |
Beasties * | SWF | SVG |
Trip | SWF | SVG |
Also note that the SVG files linked to above are, with the exception of those markes with an asterisk *, produced by the SWF2SVG converter. You may see some differences in the colours of certain graphical elements, as some very minor editing of the files has to be made by hand in order to get some colour transforms to work correctly (see below). Those files marked with an asterisk have had some minor alterations made where elements where the colour transforms are necessary in order for the graphic elements to be visible.
Problems
Some problems still remain. In SWF many shapes have definitions which map into SVG as follows:
<g id="15"> <path style="fill: #0000ff; stroke: none;" d="vectors to draw a rectangle" /> </g> <use id="I15" href="#15"/>As the animation progresses, a shape such as this may be manipulated through the DOM to draw any kind of parallelogram, the colour of which may also be altered through the a colour transformation matrix. Unfortunately, due to the inheritance properties specified in SVG, JavaScript control of the colour of shape 15 will not work in this case. This is because the fill colour is defined in a path definition inside the group definition through which the shape is identified. Removing the fill colour from the path definition (or at least moving it up the hierarchy to the instance specified in the <use> tag), enables the colour to be changed by the DOM, (at least this is the effect observed in the current implementation of the SVG plug-in for IE). If this is the case, the colour of shape 15 can be changed from blue to green if desired. However this can only be accomplished if the colour for instances of shape 15 are always specified with a colour transformation matrix in the SWF file, (in other words, a colour transformation matrix must always applied to shape 15 even if a blue shape was required). In reality, if a blue square was required it is likely that no colour transformation would be applied to the instance of shape 15 as the fill colour for the path has already been specified as blue. If the colour matrix was not applied when a blue square is required then removing the colour from the SVG path definition (required to enable the JavaScript to change the colour to green) would result in the fill colour for shape 15 defaulting to black instead of blue. What is required is for the DOM to be able to manipulate path segments. The SVG spec. indicates that this is possible although until the plug-ins implement this it cannot be implemented and tested.
Software
Although the software is not yet available for distribution, if you would like to try and convert your own SWF files then the latest beta version of the converter is accessible on-line. This gives you the opportunity to upload a SWF file and be returned a zip file consisting of an SVG file, an HTML wrapper and any associated JPEG file. As mentioned the software is still under development so please send any comments or problems to sgp@cs.nott.ac.uk.
Last Updated: 6 January 2000 (Steve Probets)