swfmill is a command line XML to SWF to XML processor using SWFML, an XML vocabulary closely modeled after the SWF format. It i.e. it does not check if shapes you draw are closed, etc., so make sure to thoroughly test SWFs you make with it. Unlike the “simple” vocabulary, “basic” (like SWF) uses twips as a unit instead of pixels. 20 twips are one pixel.
If you don’t like the “simple” vocabulary or have some special requirements you can use it to transform your own XML vocabulary to “basic” SWFML and output an SWF. Technically, “simple” is a built-in default transform that does just that. There are some SWF specific extensions to manage IDs and to import other SWFs.
You can download windows and OS X and the sources for Linux. 64 bit processors are supported since version 0.2.3.
Please follow the links at the bottom of this page for some examples and documentation, and visit the homepage.
swfmill was written by Daniel Fischer and is published under the GPL.
That’s the most basic SWF you can make. It’s 320 by 240 pixels, tries to run at 12 frames per second, and has a white background. Note the <frame/> tag, except of the <movie/> and <background/> tags, all other tags belong into one. For simplicity’s sake, most examples below will assume you know that, and won’t include the header explicitly.
<?xml version="1.0" encoding="iso-8859-1" ?> <movie width="320" height="240" framerate="12"> <background color="#ffffff"/> <frame/> </movie>
If you save this XML code into a file sample.swfml (it could also be sample.xml or in fact anything else), you can compile it into a binary SWF with the following commandline:
swfmill simple sample.swfml sample.swf
The <clip/> tag lets you import JPGs, PNGs (including alpha), SWFs and SVGs (somewhat experimental). They will be available as MovieClips. This example will import library/foo.jpg and give it the ID foo. swfmill can also import TrueType fonts, but the syntax is different.
<frame> <clip id="foo" import="library/foo.jpg"/> </frame>
The <library/> tag, like almost all others, lives in a <frame/> tag. You can determine in which frame assets are included into your SWF by using multiple frames and putting it into the one you want your assets to be available in. You don’t have to import assets into the library, but then they won’t be available to ActionScript. Sometimes you don’t need an asset to be in the library, because you only want to use it as a part of another clip you define, or you place it onto the stage directly with the <place/> tag. Of course, you can have several <clip/> and <font/> tags in one <library/>. The example will import the same image as above, but this time into the library. The ID also serves as the linkage name if you import into the library.
<frame> <library> <clip id="foo" import="library/foo.jpg"/> </library> </frame>
Imoporting TTF fonts works almost like importing images or SWFs, but the <font/> tag is used and you can specify the characters you want included with the glyphs attribute. The example imports the numerical characters of vera.ttf.
<font id="vera" import="library/vera.ttf" glyphs="0123456789"/>
Note : In order to use special characters, you’d use the equivalent xml entity in the glyph attribute. For example é in place of é.
Note : That the font tag must exist inside a library tag for the linkage id to work with TextFormats and dynamically created TextFields, or that it is Exported for runtime sharing.
The font node get two attributes “id” and “name”. id will be to be used for the format attribute of textfields :
<textfield id="hellobox" width="200" height="50" size="10" font="vera" text="hello world!"/> <place id="hellobox" name="output" depth="10"/>
name attribute is used in order to get an actionscript reference to the embedded font. When using the TextField’s embedFonts property, you’ll be able to use the TextFormat.font property with this name. This attribute is also a way to group different font by families and retrieve them from actionscript (Flash 8 only).
Last thing to note, the id and attributes can be used together as the serve different purposes.
We can import sounds with a similar method, where “id” is the linkage id, and we put the following tag inside of the <library> tag:
<sound id="myID" import="blah.mp3"/>
and later in our actionscript (compiled prior via Mtasc, etc). we’d put:
var snd:Sound = new Sound();
snd.attachSound("myID");
snd.start();
Note: Requires pre-release 0.2.11.18 or later, and sound is not streamed. Note: Works with 56, 64, 128, 192 and 256 kbps MP3s. Note: joint stereo MP3s, WAV etc don’t play at all.
You can use shared libraries, too. SWFs created with swfmill always are available for runtime sharing, to import another SWF as a library keep a local copy for testing purposes and import it like this:
<import file="library/library.swf" url="http://foo.com/library.swf"/>
The class attribute of the <clip/> tag can be used to assign a class to your MovieClips. If you’re doing this, keep in mind that MTASC does not compile “unused” classes into your SWF, and it has no way of knowing you need them for this. You can “force” it to include the class by assigning it to a variable or adding the class to the mtasc command line explicitly, but a simple import won’t be enough. As usual when you do this, make sure that your class inherits from the intrinsic MovieClip class. In order for swfmill to find the class it must have been compiled previously. That means you don’t run swfmill first and compile your classes into it afterwards, but compile a classes.swf (although any other name would do) first with mtasc’s -header setting and import it in your swfml:
<frame> <clip import="classes.swf" /> <library> <clip id="foo" import="library/foo.jpg" class="org.osflash.Foo"/> </library> </frame>
As for version 0.2.9 you are able to use the new component tag. No need to use a library and a call tag. Here is a simple example. The combo is instantiated later by actionscript injected using MTASC.
<background color="#ffcccc"/> <frame> <component id="ComboBox" file="swc/ComboBox/ComboBox.swf"/> <frame/>
There are still 2 problems with components:
Here is a comparison with 3 components of the same family, an Alert window, a Label and a ProgressBar:
To publish a Flash 8 SWF using Swfmill, specify the player version in the movie tag like this:
<movie version="8" width="550" height="400" framerate="31">
Also, if you are compiling AS2 code for use in your SWF with MTASC, make sure you compile it with the -version 8 switch.
Since swfmill version 0.2.11.3, some of the new tags introduced in flash 8 were introduced. Here is a list of them :
- File attributes to set security sandbox file access and metadata :
<FileAttributes hasMetaData="0|1" useNetwork="0|1" />
Choose between the arguments separated by |. By default, useNetwork is set to 0 which means ‘filesystem’ (1 means ‘network’). But make sure to add to the <movie> root tag the attribute local-access like so :
<movie width="550" height="400" framerate="40" version="8"
local-access="filesystem|network">
- Metadata that search engine could index :
<meta title="my title" description="To be indexed" />
- Flash 8 filters and blending modes. Shared library published to flash 8 are now correctly handled.
Sometimes you need movie clips which contain multiple states. Probably the most common example of this is a button. Buttons will normally have 4 states, Up, Over, Down, and Disabled. You can create a MovieClip that contains all the states for a button, and then have an ActionScript class manage the events and change which state is displayed depending on the state the button is in.
Here’s an example of one way to create such a clip:
<movie width="320" height="240" framerate="12" version="7"> <clip id="upState" import="up.png"/> <clip id="downState" import="down.png"/> <clip id="overState" import="over.png"/> <clip id="disabledState" import="disabled.png"/> <frame> <library> <clip id="testButton"> <frame name="Up"> <place id="upState"depth="1"/> <stop/> </frame> <frame name="Over"> <place id="overState" depth="2"/> <stop/> </frame> <frame name="Down"> <place id="downState" depth="3"/> <stop/> </frame> <frame name="Disabled"> <place id="disabledState" depth="4"/> <stop/> </frame> </clip> </library> </frame> </movie>
To change which state is displayed you can simply do a gotoAndStop(name) call on the button’s movie clip.
There is one problem with the above solution. If your state images have transparencies then latter states could end up showing parts of the previous states. In theory you could set the depth values of the clips in all 4 frames to the same value, but this doesn’t seem to work for more than 2 frames (at least as of 0.2.12.2).
To get around the transparency problem you could also define your movie clip as follows:
<movie width="320" height="240" framerate="12" version="7"> <clip id="upState" import="up.png"/> <clip id="downState" import="down.png"/> <clip id="overState" import="over.png"/> <clip id="disabledState" import="disabled.png"/> <frame> <library> <clip id="testButton"> <frame> <place id="upState" name="Up" depth="1"/> <place id="overState" name="Over" depth="2"/> <place id="downState" name="Down" depth="3"/> <place id="disabledState" name="Disabled" depth="4"/> </frame> </clip> </library> </frame> </movie>
In this case you could simply have your code show/hide the child clips by name depending on which state you want displayed. It’s a little more work in the code to change states (you have to both show the state you want and hide the others) but you don’t have to worry about one state ‘seeing through’ to another.
Swfmill can be used to create Shared Libraries for Dynamic Font Loading at runtime, a nice hack described by Erixtekila. This is well documented, with examples, by Mike Barbero, here.
Essentially, you have to load an SWF (containing the font) which loads itself as a shared library. Here’s an example, shamelessly ripped from Mike’s page:
<?xml version="1.0" encoding="iso-8859-1" ?> <movie width="1" height="1" framerate="12"> <frame> <library> <font name="Charter" import="src/ct.ttf"/> <font name="Charter" import="src/ct__Italic.ttf"/> <font name="Charter" import="src/ct__Bold.ttf"/> <font name="Charter" import="src/ct__BoldItalic.ttf"/> </library> <Import url="http://localhost/test/charters.swf"></Import> </frame> </movie>
As you can see in the <import/> tag for the dynamic library, the URL for the SWF must be http://localhost/test/charters.swf. Relative paths work, too. So, when you need to load the font, you load the SWF you generated and it will load itself out of the browser cache.
The @name is set to the same value in all <font/> tags on purpose, so you can use e.g., <b/> in HTML TextFields. Of course it also works with just a single style, with only a selected subset of the glyphs, and so on.
Earlier in this document a method for importing components was provided. This method allows you to add the components directly into the SWFs using only swfmill, but can potentially cause much larger output files. If you have access to the Flash IDE there is another simple method to add components.
Basically, you will use the Flash IDE to generate a blank SWF which contains the components you will want to use. Then, in your XML you add a clip to the library that imports this SWF. It appears that simply importing the clip has the effect of adding the components to the library, without even having to instantiate the clip.
For example, if you create an SWF using the Flash IDE which simply contains the ComboBox component and build it as Components.swf you can then do this in the XML:
<frame> <library> <clip id="componentsContainer" import="Components.swf"/> </library> </frame>
then in your code wherever you wish to create the combo box you simply import the control’s class at the top:
import mx.controls.ComboBox
and then instantiate it with the following (replacing _root with the movie clip you want to attach to and “myComboBox” with the name you wish to give it):
_root.createClassObject(ComboBox, "myComboBox" _root.getNextHighestDepth()); var cb:ComboBox = _root["myComboBox"];
SVG support works great for files produced by Inkscape. There are a couple of bugs supporting other svg files (e.g. #12). Currently you can only import single SVG file into SWF (#14, seems to be fixed in trunk).
All groups (svg:g) in SVG are exported as movie clips (for Inkscape this affects layers as well as groups). These movie clips are named after either their inkscape:label attribute if that exists (first character ‘#’ removed if present) or id attribute (inkscape:label is better because it allows reusing name in different point of hierarchy. If group has transform attribute, all it’s contents are created in yet another movie clip (usually called instanceN) with appropriate transformations applied.
If some element has swfClass attribute, then specified class is assigned to a movieclip corresponding to that element. All prerequisites described above must also be satisfied here.
A few more words about Inkscape. To set label you can right-click any object and choose Object Properties. To set class you can select object, pop up an XML Editor (e.g. using Ctrl+Shift+X) and enter swfClass and appropriate value, then click set.