SWF Structures

Most of the tags will use sub-structures that are common to multiple tags. These are defined in the pages listed below.

SWF ARGB (swf_argb)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_argb {
	unsigned char		f_alpha;1
	unsigned char		f_red;
	unsigned char		f_green;
	unsigned char		f_blue;
};
  • 1. 0 represents a fully transparent color, 255 represents a solid color.

The color components can be set to any value from 0 (no intensity) to maximum intensity (255).1

It is important to note that even fully transparent pixels may not have their red, green, blue components set to 0. This is useful if you want to add a value to the alpha channel using one of the color transformation matrices. In that case, using all 0's would generate a black color.

  • 1. For some PNG images, the red, green and blue colors may need to be multiplied by their alpha channel value before saved. Use the following formula to compute the proper values:

       f_red = orginal red * f_alpha / 255

This format was added to be mostly compatible with the old PNG format (XRGB).

SWF Action (swf_action)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
/* basic definition of an action entry */
struct swf_action {
	unsigned char		f_action_id;
	f_action_has_length = (f_action_id & 0x80) != 0;
	if(f_action_has_length) {
		unsigned short		f_action_length;
		unsigned char		f_action_data[f_action_length];
	}
};

An action is defined with an identifier, and an optional size and data (pretty much like a tag).

Note that the optional size and data are defined only for actions with an identifier of 128 or more. The other identifiers are always defined by themselves. Actions without immediate data may still access data. In that case, the data is taken from the stack.

Please, see the action list for all the supported actions.

SWF Action 3 (swf_action3)

SWF Structure Info
Tag Flash Version: 
9
SWF Structure: 

Not documented here yet.

Since Flash version 9, actions can be saved in a new format named abcFormat by the Tamarin project from the Mozilla organization.

The code itself (action script) is the same, but the structure of an swf_action3 holds object oriented information about classes, methods and such in a really clean way (really! in comparison to the old way, that's dead clean!).

At this time, the swf_action3 structure is documented in the abcFormat.html file.

I will duplicate and test the structures at a later time.

SWF Any Filter (swf_any_filter)

SWF Structure Info
Tag Flash Version: 
8
SWF Structure: 
/* the filter type */
struct swf_filter_type {
	unsigned char	f_type;
};

struct swf_filter_glow {
	swf_filter_type	f_type;		/* 0, 2, 3, 4 or 7 */
	if(f_type == GradientGlow || f_type == GradientBevel) {
		unsigned char		f_count;
	}
	else {
		f_count = 1;
	}
	swf_rgba		f_rgba[f_count];
	if(f_type == Bevel) {
		swf_rgba		f_highlight_rgba[f_count];
	}
	if(f_type == GradientGlow || f_type == GradientBevel) {
		unsigned char		f_position[f_count];
	}
	signed long fixed	f_blur_horizontal;
	signed long fixed	f_blur_vertical;
	if(f_type != Glow) {
		signed long fixed	f_radian_angle;
		signed long fixed	f_distance;
	}
	signed short fixed	f_strength;
	unsigned		f_inner_shadow : 1;
	unsigned		f_knock_out : 1;
	unsigned		f_composite_source : 1;
	if(f_type == Bevel) {
		unsigned		f_on_top : 1;
	}
	else {
		unsigned		f_reserved : 1;
	}
	if(f_type == GradientGlow || f_type == GradientBevel) {
		unsigned		f_passes : 4;
	}
	else {
		unsigned		f_reserved : 4;
	}
};

struct swf_filter_blur {
	swf_filter_type		f_type;	/* 1 */
	unsigned long fixed	f_blur_horizontal;
	unsigned long fixed	f_blur_vertical;
	unsigned		f_passes : 5;
	unsigned		f_reserved : 3;
};

struct swf_filter_convolution {
	swf_filter_type	f_type;		/* 5 */
	unsigned char	f_columns;
	unsigned char	f_rows;
	long float	f_divisor;
	long float	f_bias;
	long float	f_weights[f_columns × f_rows];
	swf_rgba	f_default_color;
	unsigned	f_reserved : 6;
	unsigned	f_clamp : 1;
	unsigned	f_preserve_alpha : 1;
};

struct swf_filter_colormatrix {
	swf_filter_type	f_type;		/* 6 */
	long float	f_matrix[20];
};

struct swf_any_filter {
	swf_filter_type			f_fitler_type;
	swf_filter_blur			f_filter_blur;
	swf_filter_colormatrix		f_filter_colormatrix;
	swf_filter_convolution		f_filter_convolution;
	swf_filter_glow			f_filter_glow;
};

A filter defines how to transform the objects it is attached to. The first byte is the filter type. The data following depend on the type. Because each filter is much different, they are defined in separate structures. You can attach a filter to an object using an ActionScript or the PlaceObject3 tag.

The following describes the different filters available since version 8.

Value Name Version
0 Drop Shadow 8
1 Blur 8
2 Glow 8
3 Bevel 8
4 Gradient Glow 8
5 Convolution 8
6 Color Matrix 8
7 Gradient Bevel 8

 

Glow, Drop Shadow, Bevel, Gradient Glow and Gradient Bevel

The following structure describes the Glow, Drop Shadow, Bevel, Gradient Glow and Gradient Bevel which all use the same algorithm. Those with less parameters can use a faster (optimized) version of the full version algorithm.

These filters are used to generate what looks like a glow or a shadow. It uses the alpha channel of the object being filtered. Only the alpha is used in the computation of the shape until the end when the color is applied. The result is then composited with the object (unless f_knock_out is set to 1 in which case it replaces the object) before being drawn in the display.

The f_count is assumed to be 1 unless a gradient filter is used, in which case a byte will be defined here. Note: the maximum number of gradient is not specified in the Macromedia documentation. It can be assumed to be the same as for the other gradients and thus it either can be 1 to 8 or 1 to 15. I will need to test that too!

The f_rgba color is used as the final step to color the resulting shape. A standard shadow uses a black or dark gray color and a standard glow has a color between the general color of the object being filtered and white.

The f_hightlight_rgba color is used by the Bevel filter to color the second half of the final shape (f_rgba colors the first half). This is usually set to a glow color whereas the f_rgba is set to a shadow color.

The f_position is used as the position of that specific gradient entry. This is similar to the f_position parameter of the swf_gradient_record.

The f_blur_horizontal and f_blur_vertical values are used to blur the edges horizontally and vertically. See the Blur filter for more information about the blur effect.

The f_radian_angle and f_distance are used to move the shadow away from the object being placed. Notice that the angle is in radian. Increasing the angle turns the effect clockwise. An angle of 0.0 points to the right side of the object.

The f_strengh value is used to multiply the resulting grey scale. Smaller values make the shadow darker. 1.0 keeps the alpha channel as it is (beside the blur).

The f_inner_shadow flag means that the result is applied inside the parent object and not arround as you would expected for a shadow. If you need both: an inner and an outer shadow (necessary for semi-transparent objects) then you will need to setup two filters.

The f_knock_out flag means that the source object is not rendered in the result, only the shadow. This can be used (in general) to draw the edges of the object. It can also be used to apply a different transformation on the shadow than on the object (in which case the object will be twice in the display list: once to draw its shadow and once to draw itself.)

The f_composite_source must be set to 1 for the Drop Shadow.

The f_on_top flag indicates whether the resulting shadow and highlight should be rendered below (0) or over (1) the source image. This is at times referenced as Overlay.

The f_passes counter available with the gradient filters can be used to repeat the filter computations multiple times. This parameter should be set to 1, 2 or 3. A value of 0 is illegal and a larger value will not only slow down the computation time, it is likely to generate a bad result.

 

Blur

The Blur filter applies a seemingly complex mathematical equation to all the pixels in order to generate soft edges. To simplify: it adds the surrounding pixels to a center pixel and normalize the result. This generates the effect of a blurry image. Note that this blur is applied to squares (box filter).

The math in a C++ function goes like this:

	swf_rgba blur(const char *image, int x, int y, int blur_h, int blur_v)
	{
		/* we assume that blur_h/v are odd */
		int x1 = x - blur_h / 2;
		int x2 = x + blur_h / 2;
		int y1 = y - blur_v / 2;
		int y2 = y + blur_v / 2;
		swf_rgba blur;

		blur.reset();	/* set to all 0's */
		yp = y1;
		while(yp <= y2) {
			int xp = x1;
			while(xp <= x2) {
				blur += image(xp, yp);
				++xp;
			}
			++yp;
		}

		return blur / (blur_h * blur_v);
	}
Notes:   The Flash player implementation works on sub-pixels and this algorithm does not.
The fact that this algorithm uses a square means it will generate visible artifacts in your image if you use a large value for the blur (i.e. more than about 7.)
If you want this algorithm to work properly, make sure to save the results in a separate image so each pixel can be computed properly without the effect pre-applied.
This algorithm does not show any clipping; if you want to keep it fast, you need to keep it that way and enlarge the source image making the edges a repeat of the edge color and the corners the corresponding corner color.

The f_blur_horizontal and f_blur_vertical are expected to be larger than 1.0 to have an effect (usually at least 3, and in most cases 5 or more.)

The f_passes is a counter which should be at least 1. The blur effect will be repeated that many times on the image. When using 3, the resulting blur is close to a Gaussian Blur. Note that it will make the image bigger each time and applying this filter can be slow.

 

Convolution

The convolution filter can be used to generate a really nice blur or avoid the vertical jitter of an animation on a CRT monitor. It is similar to the Blur filter, except that the computation of the destination pixels is fully controlled.


Fig 1 — Convolution Filter Example

The image above shows an example of a convolution filter. The red pixel is the one being tweaked. The different gray color represent the heavier (darker) weight and the lighter weights. The pixels drawn in white are ignored (i.e. their weights will be set to 0.)

The convolution filter can be described with the following C function:

	swf_rgba convolution(swf_rgba *source, int x, int y, swf_filter_convolution convolution)
	{
		swf_rgba	result;
		swf_rgba	pixel;
		int		i, j, p, q, pmax, qmax;

		result.reset();		/* black */
		pmax = convolution.f_rows / 2;
		qmax = convolution.f_columns / 2;
		for(j = 0, p = -pmax; p < pmax; ++p, ++j) {
			for(i = 0, q = -qmax; q < qmax; ++q, ++i) {
				pixel = source[x + p][y + q];
				pixel += convolution.f_bias;
				pixel *= convolution.f_weights[i][j];
				pixel /= convolution.f_divisor;
				result += pixel;
			}
		}

		return result;
	}

We can clearly see that a weight of 0 cancels that very pixel effect. We can notice also that the divisor is not necessary here (however, it may be possible to tweak the divisor using an ActionScript and in that case it can be useful.)

A blur algorithm can use a convolution filter with the following parameters:

{
  { 0.000, 0.050, 0.050, 0.050, 0.000 },
  { 0.050, 0.075, 0.075, 0.075, 0.050 },
  { 0.050, 0.075, 0.000, 0.075, 0.050 },
  { 0.050, 0.075, 0.075, 0.075, 0.050 },
  { 0.000, 0.050, 0.050, 0.050, 0.000 }
}
  1. Set f_columns to 5
  2. Set f_rows to 5
  3. Set f_divisor to 1
  4. Set f_bias to 0
  5. Set f_weights to:
  6. Set f_clamp to 1
  7. Set f_preserve_alpha to 1


Fig 2 — Convolution filter to create a radian blur

When you want to remove most of the jitter on a television or any CRT monitor which use an interlace video mode, you can use the following setup:

  1. Set f_columns to 1
  2. Set f_rows to 3
  3. Set f_divisor to 1
  4. Set f_bias to 0
  5. Set f_weights to { 0.25, 0.5, 0.25 }
  6. Set f_default_color to black (0, 0, 0, 1)
  7. Set f_clamp to 0
  8. Set f_preserve_alpha to 1


Fig 3 — Convolution filter to limit interlace jitter

The f_columns and f_rows determine the size of the convolution filter.

The f_divisor divide the sum of the weighted pixel components. Note that you can incorporate the divisor in the weights. However, this is a mean to divide (or multiply) all the weights at once. Yet I suggest you put this parameter to 1 and change the weights instead.

The f_bias is added to the component of each pixel before they are multiplied by their corresponding factor.

The f_weights are used to determine how much of a given pixel color shall be used in the result.

The f_default_color color is used only if f_clamp is set to 0. This is the color to be used whenever it is necessary to compute the color of a pixel which is outside of the source.

f_clamp is used to determine the color to use whenever a pixel outside of the input image is necessary. When set to 1, the closest input pixel is used. When set to 0, the f_default_color is used.

If f_preserve_alpha is set to 1, then the source alpha channel is copied as is in the destination.

 

Color Matrix

The color matrix is a 5x5 matrix used to tweak or adjust the colors of your objects. A full matrix can be used to change the contrast, brightness and color (just like you do on your television.)

The matrix is composed of 5 components of red, green, blue and alpha. The 5th row is not saved in the filter and is assume to always be [0 0 0 0 1].


Fig 1 — Color Matrix Filter

The resulting color Q is computed as M · C, where C is a column matrix composed of the source pixel colors: red, green, blue, alpha and 1. The result is also a column matrix in which component 5 can be dropped.

Notice that f_matrix is composed of floats and not fixed point values.

In order to compute a color matrix from simple values, you want to use the following matrices and equations (see Appendix A. for more matrix computations.) Most of these equations are based on a paper written by Paul Haeberli in 1993.

Why is matrix computation on colors working so well? This is because the colors, when defined as (R, G, B) perfectly map to a 3 dimensional cube. The corner at (0, 0, 0) represents black, and the opposite corner at (1, 1, 1) represents white. The other corners represent Red, Green, Blue and their composites: Cyan, Yellow, Purple. Within the cube, all the usual 3D geometry computations apply to colors just the same as it applies to (x, y, z) vectors.

The following shows you have to modify the RGB components. The Alpha channel can in a similar way be modified. However, you usually do not want to change the alpha from the colors and thus it is likely that the only thing you will do with the alpha is a simple translation (change a0, a1, a2) and a scaling (change a3). By default, set the alpha row to [ 0 0 0 1 0 ] and the last column to [ 0 0 0 0 1 ].


Fig 2 — Color Matrix with no effect on the alpha channel

In the following pretty much all the values are assumed to be defined between 0.0 and 1.0. Though there is no real limits, using larger values or negative values can have unexpected effects such as a clamping of one or more of the color components.

The Grey Vector is the vector going from (0, 0, 0) to (1, 1, 1). It represents all the grays from black to white. It is important since it is used to represent the luminance of the image.

Use the scaling matrix B to change the brightness. This has the effect of making the color vector longer or shorter, but it still points in the same direction. Some people call this the image Intensity.


Fig 3 — Brightness Matrix B

In general, you want to set all scaling factors to the same value to change the brightness in a uniform way. By changing the scaling factors to different values you in effect change the color balance.

The luminance matrix L is used to determine how close your image is to the grey vector. The closer to the gray vector, the closer to a black and white image you will get. This is a saturation toward grey. The effect in the color cube is to move your color vector closer to the grey vector.


Fig 4 — Luminance Matrix (L)

The luminance matrix requires three weights (Rw, Gw, Bw) which are defined as (0.3086, 0.6094, 0.082). Note that the sum of these weights is 1.0.

The weights used here are linear. It is possible to use different weights for images which have different gammas. For instance, an NTSC image with a gamma of 2.2 has these weights: (0.299, 0.587, 0.114).

The saturation matrix S is used to saturate the colors. This matrix uses the weights defined for the Luminance matrix L. The effect in the color cube is to move your vector toward another vector. The Luminance is a special case which moves your vector toward the gray vector. And the identity matrix, which can also be considered a saturation matrix, is a special case which does not move your vector.


Fig 5 — Saturation Matrix (S)

The saturation parameter s shall be set to a value from -1 to 1. Note that a saturation of 1 generates an Identity Matrix and thus has no effect. A saturation of 0 generates a Luminance Matrix (s = 0 <=> S = L). A saturation of -1 generates a matrix which inverse all the colors of your image (negative).

Using the Brightness Matrix B and a translation matrix, it is possible to modify the contrast of your image by scaling the colors toward or away from the center (or some other point) of the color cube.


Fig 6 — Translation Matrix (T)

To apply a standard contrast c create a matrix Ts with offsets (0.5, 0.5, 0.5), a matrix Bc with the scaling factors set to c and compute the contrast matrix C as: C = -Ts · Bc · Ts

It is also possible to use a translation to change the colors of your image. This is not very useful since it is a simple addition (C' = C + T).

To change the hue of a color, it is necessary to rotate the color vector around the gray vector. It is easy to see that rotating the gray vector around itself generates itself. A gray hue cannot be changed. If you rotate the colors by 120°, red becomes green, green becomes blue and blue becomes red.

Note however that by only rotating the color, you generate a luminance error. This is because blue is not as bright as red or green and green is not as bright as red. To avoid the luminance loss, you need to apply a shear to make the luminance plane horizontal.

The following are all the steps used to rotate the Hue. Note that most matrices can be precomputed (in other words, you can very much optimize your code!)

Once you computed each of the matrices, you can merge them all together by multiplying them. The order should not matter except if you use a translation which isn't canceled (like the one for the contrast.)

M = B · S · C · H

Note that you do not need a Saturation and a Luminance since these are the same. However, you may still want to separate them for the sake of simplicity.

M = B · L · S · C · H

  • Gray Vector
  • Brightness (Matrix B)
  • Luminance (Matrix L)
  • Saturation (Matrix S)
  • Contrast (Matrix C)
  • Hue (Matrix H)

    Rotate the gray vector around the X axis by 45°. This places the the vector on the (x, y) plane.


    Fig 7 — rotation around the X axis

    Because we want to rotate by 45° the sine and cosine of the angle can directly be set to the inverse of the square root of 2.


    Fig 8 — sine and cosine in the rotation around the X axis

    Rotate the gray vector from the (x, y) plane to the positive Z direction. We want to rotate by about 35.2644°.


    Fig 9 — rotation around the Y axis

    The sine and cosine values of this equation can be computed with the square root of 2 and 3 as presented below:


    Fig 10 — sine and cosine in the rotation around the Y axis

    Apply the Rx and Ry matrices to the luminance offsets, and use the result to compute the shear matrix.


    Fig 11 — How to compute the shear factors

    The Rw, Gw and Bw are the Luminance factors as defined for matrix L.

    Now we can compute matrix K which is used for the luminance shear correction:


    Fig 12 — Hue Shear Matrix K

    Once you applied the Rx, Ry and K matrices to your color, you can safely rotate the result around the Z axis. This rotates the hue of the color. The rotation angle is expected to go from 0 to 2π.


    Fig 13 — Matrix to rotate the hue

    θ is set to the hue rotation angle.

    Once you rotated your vector using Rz you need to put your vector back where it belongs. This is done by multiplying by the inverse of the K, Ry and Rx in that order. Note that since these matrices are quite simple, calculating their inverse is very easy.

    K-1 is obtained by replacing B'w in the K matrix by –B'w.


    Fig 14 — Inverse of Matrix K

    Ry-1 and Rx-1 are obtained by replacing the sine values by their opposite.


    Fig 15 — Inverse of Matrix Ry


    Fig 16 — Inverse of Matrix Rx

    Given the hue rotation angle θ you can write:

    H = Rx · Ry · K · Rz · K-1 · Rx-1 · Ry-1

    • X Rotation
    • Y Rotation
    • Luminance Shear (Matrix K)
    • Hue rotation
    • Remove the shear, y rotation and x rotation
    • Final Hue Rotation Equation
  • And finally the SWF Color Matrix

 

Filters Union

The any filter is simply a union of all the filters. Note that only one type of filter can be defined in an any filter and also the size will depend on that filter (it is not the largest size of all filters; plus, some filters use a dynamically determined size!)

SWF Button (swf_button)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_button {
	char align;
	unsigned		f_button_reserved : 2;
	if(version >= 8) {
		unsigned		f_button_blend_mode : 1;
		unsigned		f_button_filter_list : 1;
	}
	else {
		unsigned		f_button_reserved : 2;
	}
	unsigned		f_button_state_hit_test : 1;
	unsigned		f_button_state_down : 1;
	unsigned		f_button_state_over : 1;
	unsigned		f_button_state_up : 1;
	if(any f_button_state_... != 0) {
		unsigned short		f_button_id_ref;
		unsigned short		f_button_layer;
		swf_matrix		f_matrix;
		if(f_tag == DefineButton2) {
			swf_color_transform		f_color_transform;
		}
		if(f_button_filter_list) {
			unsigned char		f_filter_count;
			swf_any_filter		f_filter;
		}
		if(f_button_blend_mode) {
			unsigned char		f_blend_mode;
		}
	}
};

A button structure defines a state and a corresponding shape reference. The shape will be affected by the specified matrix whenever used.

There are many acceptable combinations. The object which is referenced is drawn when its state matches the current state of the button. If only the f_button_state_hit_test is set, then the shape is always displayed.

In order to define the area where the button can be clicked, it is necessary to set the f_button_state_hit_test flag to 1. Also, when this flag is set, only a shape can be referenced (no edit text, sprite or text object will work in this case).

When the f_button_state_hit_test is set, the square used to delimit the referenced shape will be used to determine whether the mouse is over the button or not.

Shapes referenced with the f_button_state_down flag set are drawn when a mouse button is being pushed over this button.

Shapes referenced with the f_button_state_up flag set are drawn when no mouse button is being pushed over this button. When neither up or down is specified, up us assumed.

Shapes referenced with the f_button_state_over flag set are drawn when the mouse is moved over this button.

The f_button_layer is used like a depth parameter. The smallest layer is drawn first (behind) and the highest layer is drawn last (on top of all the other shapes).

Though four flags allow for 16 different states, you are likely to only use a few. The hit test can appear on each state. The down and up won't usually be used together, though, if they are the shape will be drawn when the button is clicked or not.

Since version 8, this structure supports blending modes and a list of filters.

The structure is always aligned to a byte. If all of the f_button_state_... flags are zeroes, then the entry is an EOB (End Of Buttons) entry.

SWF Color Transform (swf_color_transform)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_color_transform {
	char align;
	unsigned		f_color_has_add : 1;
	unsigned		f_color_has_mult : 1;
	unsigned		f_color_bits : 4;
	if(f_color_has_mult) {
		signed short fixed	f_color_red_mult : f_color_bits;
		signed short fixed	f_color_green_mult : f_color_bits;
		signed short fixed	f_color_blue_mult : f_color_bits;
		if(f_tag == PlaceObject2) {
			signed short fixed	f_color_alpha_mult : f_color_bits;
		}
	}
	if(f_color_has_add) {
		signed short fixed	f_color_red_add : f_color_bits;
		signed short fixed	f_color_green_add : f_color_bits;
		signed short fixed	f_color_blue_add : f_color_bits;
		if(f_tag == PlaceObject2) {
			signed short fixed	f_color_alpha_add : f_color_bits;
		}
	}
};

When the f_color_<component>_mult are not defined in the input file, use 1.0 by default. When the f_color_<component>_add are not defined in the input file, use 0.0 by default.

The factors are saved as 8.8 fixed values (divide by 256 to obtain a proper floating point value). Note that the values are limited to a signed 16 bits value. This allows for any value between -128.0 and +127.98828.

When the resulting color is defined, the multiplication is applied first as in:

	result-component = source-component * component-mult + component-add;

The result is then clamped between 0.0 and 1.0.


SWF Condition (swf_condition)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_condition {
	unsigned short		f_condition_length;1
	unsigned		f_condition_key : 7;
	unsigned		f_condition_menu_leave : 1;
	unsigned		f_condition_menu_enter : 1;
	unsigned		f_condition_pointer_release_ouside : 1;
	unsigned		f_condition_pointer_drag_enter : 1;
	unsigned		f_condition_pointer_drag_leave : 1;
	unsigned		f_condition_pointer_release_inside : 1;
	unsigned		f_condition_pointer_push : 1;
	unsigned		f_condition_pointer_leave : 1;
	unsigned		f_condition_pointer_enter : 1;
	swf_action		f_action_record[variable];
};
  • 1. The number of actions is variable, the f_condition_length parameter indicates the number of bytes and can be used to skip one condition and all of its actions at once. The action array must always be terminated by an End action entry (i.e 0x00).

A condition is defined in a DefineButton2 tag. It is a record of conditions. The record terminates when the size of the current (i.e. last) condition is zero. The length of that condition can be deduced from the total size of the tag minus the offset where the condition starts. Conditions are similar to events.

The f_key field represents a key code since version 4. The following table gives the code equivalence. Note that 0 means no key.

Key Code Name Version
0 (0x00) No key activation 3
1 (0x01) Left Arrow 4
2 (0x02) Right Arrow 4
3 (0x03) Home 4
4 (0x04) End 4
5 (0x05) Insert 4
6 (0x06) Delete 4
8 (0x08) Backspace 4
13 (0x0D) Enter 4
14 (0x0E) Up Arrow 4
15 (0x0F) Down Arrow 4
16 (0x10) Page Up 4
17 (0x11) Page Down 4
18 (0x12) Tab 4
19 (0x13) Escape 4
32-126 The corresponding ASCII code 4

SWF Envelope (swf_envelope)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_envelope {
	unsigned long		f_position;
	unsigned short		f_volume_left;
	unsigned short		f_volume_right;
};

When playing back a sound effect it is possible to modulate the sound to generate different effects (such as a fade in and out). The following defines the stereo volume of the sound.

The position is always given as if the sample data was defined with a rate of 44,100 bytes per seconds. For instance, the sample number 1 in a sound effect with a sample rate of 5.5K is given as position 8 in the envelope. All of these positions should be within the f_in_point and f_out_point.

Mono sound should use the same value for the left and right volumes. Note that it will automatically be averaged if necessary.

Note that the volume goes from 0 to 32768.

SWF Event (swf_event)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_event {
	char align;
	if(version >= 6) {
		unsigned	f_event_reserved : 13;
		if(version >= 7) {
			unsigned	f_event_construct : 1;
		}
		else {
			unsigned	f_event_reserved : 1;
		}
		unsigned	f_event_key_press : 1;
		unsigned	f_event_drag_out : 1;
		unsigned	f_event_drag_over : 1;
		unsigned	f_event_roll_out : 1;
		unsigned	f_event_roll_over : 1;
		unsigned	f_event_release_outside : 1;
		unsigned	f_event_release : 1;
		unsigned	f_event_press : 1;
		unsigned	f_event_initialize : 1;
	}
	else {
		unsigned	f_event_reserved : 7;
	}
	unsigned		f_event_data : 1;
	unsigned		f_event_key_up : 1;
	unsigned		f_event_key_down : 1;
	unsigned		f_event_mouse_up : 1;
	unsigned		f_event_mouse_down : 1;
	unsigned		f_event_mouse_move : 1;
	unsigned		f_event_unload : 1;
	unsigned		f_event_enter_frame : 1;
	unsigned		f_event_onload : 1;
	unsigned long		f_event_length;1
	swf_action		f_action_record[variable];
};
  • 1. The number of actions is variable, the f_event_length parameter indicates the number of bytes and can be used to skip all the actions at once. The action array must always be terminated by an End action entry.

An event is defined in a PlaceObject2 tag. It is a record of events terminated with a set of zero flags. Events are similar to conditions.

SWF External (swf_external)

SWF Structure Info
Tag Flash Version: 
3
SWF Structure: 
struct swf_external {
	unsigned short		f_object_id;
	string			f_symbol_name;
};

An external reference is a per of entries: an identifier and a name. The name is called the external symbol and is used to match the necessary definitions between two movies using Export, Import and Import2

SWF Fill Style (swf_fill_style)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
/* f_type = 0x00 - solid fill */
struct swf_fill_style_solid {
	unsigned char		f_type;
	if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
		swf_rgba	f_rgba;
		swf_rgba	f_rgba_morph;
	}
	else if(f_tag == DefineShape3) {
		swf_rgba	f_rgba;
	}
	else {
		swf_rgb		f_rgb;
	}
};

/* f_type = 0x10 - linear gradient fill,
	    0x12 - radial gradient fill
	    0x13 - focal gradient fill (V8.0) */
struct swf_fill_style_gradient {
	unsigned char		f_type;
	swf_matrix			f_gradient_matrix;
	if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
		swf_matrix	f_gradient_matrix_morph;
	}
	swf_gradient		f_gradient;
};

/* f_type = 0x40 - tilled bitmap fill with smoothed edges,
	    0x41 - clipped bitmap fill with smoothed edges,
	    0x42 - tilled bitmap fill with hard edges (V7.0)1,
	    0x43 - clipped bitmap fill with hard edges (V7.0)2 */
struct swf_fill_style_bitmap {
	unsigned char		f_type;
	unsigned short		f_bitmap_ref;
	swf_matrix		f_bitmap_matrix;
	if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
		swf_matrix	f_bitmap_matrix_morph;
	}
};

union swf_fill_style {
	unsigned char		f_type;
	swf_fill_style_solid	f_solid;
	swf_fill_style_gradient	f_gradient;
	swf_fill_style_bitmap	f_bitmap;
};
  • 1. See description for more info.
  • 2. See description for more info.

The fill style is defined in the first byte. The values are defined below. Depending on that value, the fill style structure changes as shown below. swf_fill_style is a union of all the other structures.

Notice that types 0x42 and 0x43 are only available since version 7 and type 0x13 is only available since version 8.

Note that these values were introduced in Flash 7 but it looks like only player 8 supported the distinction between hard edges and smooth edges on a per shape basis. That would explain why I could not see any difference between smooth and hard shapes when I tested this feature in Flash 7.

Before Flash 8, all shapes would be smoothed if the global quality of the movie was set to BEST. In Flash 8, nothing is smoothed by default whatever the quality and the smoothed or hard selection in a shape can be used as a hint on a per shape basis. Following this specification closely can be important in some situations.

SWF Fill Style Array (swf_fill_style_array)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_fill_style_array {
	unsigned char		f_count;
	if(f_tag != DefineShape && f_count == 255) {
		unsigned short	f_real_count;
	}
	else {
		f_real_count = f_count;
	}
	swf_fill_style		f_fill_style[f_real_count];
};

The array of fill styles starts with a counter. When DefineShape is used, the counter can be any value from 0 (no style) to 255. When DefineShape2 or DefineShape3 are used, the value 255 is reserved so you can declare more than 255 styles.

SWF Gradient (swf_gradient)

SWF Structure Info
Tag Flash Version: 
3
SWF Structure: 
struct swf_gradient {
	if(tag == DefineShape4) {
		unsigned		f_spread_mode : 2;
		unsigned		f_interpolation_mode : 2;
		unsigned		f_count : 4;
	}
	else {
		unsigned		f_pad : 4;
		unsigned		f_count : 4;
	}
	swf_gradient_record	f_gradient_record[f_count];
	/* f_type is defined in the swf_fill_style encompassing this gradient */
	if(f_type == 0x13) {
		signed short fixed	f_focal_point;
	}
};

This structure defines a gradient. This is a set of colors which are used to define an image with colors smoothly varying from one color to the next. The gradient can be radial (circular) or linear (rectangular).

The f_count field is limited depending on the tag used and the version of SWF as defined below:

Range Tag Version
1 to 8 DefineShape 3
1 to 8 DefineShape2 3
1 to 8 DefineShape3 3
1 to 15 DefineShape4 8
1 to 8 DefineShapeMorph 3
1 to 8(1) DefineShapeMorph2 8
(1)  To be determined. The Macromedia documentation says it is limited to 8, the player needs to be tested to verify that DefineShapeMorph2 cannot support 15 gradients

The f_spread_mode is an enumeration and appeared in version 8 (undefined values are reserved.)

Value Comment Version
0 Pad 8
1 Reflect 8
2 Repeat 8

The f_interpolation_mode is an enumeration and appeared in version 8 (undefined values are reserved.)

Value Comment Version
0 Normal RGB mode 8
1 Linear RGB mode 8

The f_focal_point is a position from the left edge of the gradient square to the center and then to the right edge of the gradient. The left edge is at position -1.0, the center at 0.0 and the right edge at +1.0. This is particularly useful for radial gradients.

SWF Gradient Record (swf_gradient_record)

SWF Structure Info
Tag Flash Version: 
3
SWF Structure: 
struct swf_gradient_record {
	if(f_tag == DefineMorphShape || f_tag == DefineMorphShape2) {
		unsigned char	f_position;
		swf_rgba	f_rgba;
		unsigned char	f_position_morph;
		swf_rgba	f_rgba_morph;
	}
	else if(f_tag == DefineShape3 || f_tag == DefineShape4) {
		unsigned char	f_position;
		swf_rgba	f_rgba;
	}
	else {
		unsigned char	f_position;
		swf_rgb		f_rgb;
	}
};

The first record position should be 0 and the last 255. The intermediate should use the corresponding value depending on their position in the gradient effect.

A linear gradient is defined from left to right. A radial from inside to outside. In order to see the full effect of the gradient, one needs to define its matrix properly. The gradients are always drawn in a square with coordinates -819.2, -819.2 to +819.2, +819.2 (in pixels, that's 16384 in TWIPs). The usual is to scale the gradient square down, translate to the proper position and rotate as necessary. There is no point in rotating a radial gradient.

IMPORTANT NOTE: If you use positions (see f_position) which are too close to each others, you are likely to see a reverse effect of what you would expect (Well... at least in the Macromedia plugin V5.0 — the gradient goes the wrong way between each color change!!!).



Fig 1. Red to green radial fill

The image in Fig 1. shows you a radial fill using pure red as the color at position 0 and pure green at position 255. It is often used to draw a round corner of an object such as a button.



Fig 2. Red to green linear fill

The image in Fig 2. shows you a linear fill using pure red as the color at position 0 and pure green at position 255. It goes from left to right when no rotation is applied. Using a rotation provides means to have the colors going top to bottom or in diagonals.

SWF Kerning (swf_kerning)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_kerning {
	if(f_font2_wide) {
		unsigned short		f_kerning_code1;
		unsigned short		f_kerning_code2;
	}
	else {
		unsigned char		f_kerning_code1;
		unsigned char		f_kerning_code2;
	}
	signed short		f_kerning_adjustment;
};

The following table defines the number of TWIPs to move left or right before to draw the 2nd character when the 1st one was drawn right before it. For instance, the letters AV may be drawn really close so the V is written over the A. To the contrary, WI may be seperated some more so the I doesn't get merged to the top of the W.

The computation to move the drawing pen is done as follow:

  /* writing 'AV' */
  x += f_font2_advance['A'] + f_kerning['AV'].f_kerning_adjustment;

where 'x' is the position at which f_kerning_code1 was draw.



Fig 1. Kerning "AV" and "WI"


SWF Line Style (swf_line_style)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_line_style {
	if(f_tag == DefineMorphShape) {
		unsigned short twips	f_width;
		unsigned short twips	f_width_morph;
		swf_rgba		f_rgba;
		swf_rgba		f_rgba_morph;
	}
	else if(f_tag == DefineShape4 || f_tag == DefineMorphShape2) {
		unsigned short twips	f_width;
		if(f_tag == DefineMorphShape2) {
			unsigned short twips	f_width_morph;
		}
		unsigned		f_start_cap_style : 2;
		unsigned		f_join_style : 2;
		unsigned		f_has_fill : 1;
		unsigned		f_no_hscale : 1;
		unsigned		f_no_vscale : 1;
		unsigned		f_pixel_hinting : 1;
		unsigned		f_reserved : 5;
		unsigned		f_no_close : 1;
		unsigned		f_end_cap_style : 2;
		if(f_join_style == 2) {
			unsigned short fixed	f_miter_limit_factor;
		}
		if(f_has_fill) {
			swf_fill_style		f_fill_style;
		}
		else {
			swf_rgba		f_rgba;
			if(f_tag == DefineMorphShape2) {
				swf_rgba		f_rgba_morph;
			}
		}
	}
	else if(f_tag == DefineShape3) {
		unsigned short twips	f_width;
		swf_rgba		f_rgba;
	}
	else {
		unsigned short twips	f_width;
		swf_rgb				f_rgb;
	}
};

The width of the line is in TWIPS (1/20th of a pixel).

The f_start_cap_style and f_end_cap_style can be:

  • 0 - Round cap,
  • 1 - No cap,
  • 2 - Square cap.

Round is the default, the way line caps looked before version 8. No Cap means that nothing is added at the tip of the line. This means the line stops exactly where you say it should end. The Square Cap is like the No Cap, but it has the cap which is about Width / 2.

The f_join_style can be:

  • 0 - Round join,
  • 1 - Bevel join,
  • 2 - Miter join.

Each time a line is multiple segments, each segment join is rendered using this definition. A Round Join is what we had before. A Bevel Join is a straight line between the end edges of each line (rectangle representing a line.) The Miter Join is similar to a Bevel, except that you can control the length between the tips and the closure of the line. When the miter limit factor is large, it continues the edges of the lines and it looks like triangles or squares.

The f_no_hscale and f_no_vscale flags, when set to 1, request that the stroke thickness not be scaled along with the object.

When f_pixel_hinting is set to 1, the SWF Player forces all the anchors to be placed on a pixel (it ignores sub-pixels.) This can be useful to create small objects which you do not want blurry.

The f_no_close can be set to 1 to request that the first and last points be rendered with caps rather than a join even if they are equal (and thus close the shape.)

The f_miter_limit_factor field is defined whenever the join is set to Miter Join (2). The value is unsigned from 0.0 to about 255.0. Note that under 1.0, it has no effect.

SWF Line Style Array (swf_line_style_array)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_line_style_array {
	unsigned char		f_count;
	if(f_tag != DefineShape && f_count == 255) {
		unsigned short	f_real_count;
	}
	else {
		f_real_count = f_count;
	}
	swf_line_style		f_line_style[f_real_count];
};

The array of line styles starts with a counter. When DefineShape is used, the counter can be any value from 0 (no style) to 255. When DefineShape2 or DefineShape3 are used, the value 255 is reserved so you can declare more than 255 styles (up to 65535.)

SWF Matrix (swf_matrix)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_matrix {
	char align;
	unsigned		f_has_scale : 1;
	if(f_has_scale) {
		unsigned	f_scale_bits : 5;
		signed fixed	f_scale_x : f_scale_bits;
		signed fixed	f_scale_y : f_scale_bits;
	}
	unsigned		f_has_rotate : 1;
	if(f_has_rotate) {
		unsigned	f_rotate_bits : 5;
		signed fixed	f_rotate_skew0 : f_rotate_bits;
		signed fixed	f_rotate_skew1 : f_rotate_bits;
	}
	unsigned		f_translate_bits : 5;
	signed			f_translate_x : f_rotate_bits;
	signed			f_translate_y : f_rotate_bits;
};

By default...

  • f_scale_x and f_scale_y are set to 1.0
  • f_rotate_skew0 and f_rotate_skew1 are set to 0.0
  • f_translate_x and f_translate_y must be specified. The translation can be set to (0, 0) to avoid any side effects.

Scale is a ratio. Rotate is an angle in radian. Translate is in TWIPs (1/20th of a pixel.)

SWF Morph Shape with Style (swf_morph_shape_with_style)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_morph_shape_with_style {
	swf_styles		f_styles;
	swf_shape_record	f_shape_records[variable];
	char align;
	swf_styles_count	f_styles_count;
	swf_shape_record	f_shape_records_morph[variable];
};

The array of shape records starts with a set of styles definition and is followed by shape records. The list of shape records ends with a null record.

Note that f_shape_records_morph cannot include any reference to styles and lines, nor include new styles. It is likely that the f_styles_count will always be 0x11. Also, it is always byte aligned.

SWF Params (swf_params)

SWF Structure Info
Tag Flash Version: 
7
SWF Structure: 
struct swf_params {
	unsigned char		f_param_register;
	string			f_param_name;
};

Since version 7 of SWF, there is a new way to create a function allows you to not only name parameters but also to put their content in a register. This is done by specifying a register number along an (optional) parameter name.

The f_param_register specifies whether the corresponding parameter will be saved in1:

  • A register (when it's not zero)
  • A named variable (when the name is not an empty string)
  • Both

Note that the auto-generated variables (those defined by the "preload" flags to the Declare Function (V7)) are also saved in registers. You have to make sure you save your own variables in registers that are not already in use by these system variables2.

The f_param_name string will be ignored whenever the f_param_register parameter is not zero. Otherwise, it is used to save the corresponding parameter in a variable of that name. Since up to 255 registers can be used, it rarely will be necessary to save local variables in named variables when using the Declare Function (V7) action.

  • 1. Note that "neither" is not an option, thus although both the register number and name are optional, at least one of them needs to be defined.
  • 2. All the auto-generated variables are saved in sequential order before the user parameters. This means all the user parameters must have a register number larger than the auto-generated variables.

SWF RGB (swf_rgb)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_rgb {
	unsigned char		f_red;
	unsigned char		f_green;
	unsigned char		f_blue;
};

Each color component is a value from 0 (no intensity) to 255 (full intensity).

SWF RGBA (swf_rgba)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_rgba {
	unsigned char		f_red;
	unsigned char		f_green;
	unsigned char		f_blue;
	unsigned char		f_alpha;1
};
  • 1. 0 represent a fully transparent color, 255 represents a solid color.

The color components can be set to any value from 0 (no intensity) to maximum intensity (255).1

It is important to note that even fully transparent pixels may not have their red, green, blue components set to 0. This is useful if you want to add a value to the alpha channel using one of the color transformation matrices. In that case, using all 0's would generate a black color.

  • 1. For some PNG images, the red, green and blue colors may need to be multiplied by their alpha channel value before saved. Use the following formula to compute the proper values:

       f_red = orginal red * f_alpha / 255

SWF Rectangle (swf_rect)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_rect {
	char align;
	unsigned		f_size : 5;
	signed twips		f_x_min : f_size;
	signed twips		f_x_max : f_size;
	signed twips		f_y_min : f_size;
	signed twips		f_y_max : f_size;
};

The rectangles are very well compressed in an SWF file. These make use of a 5 bits size which specifies how many bits are present in the following four fields. Don't forget that the bits are read from the MSB to the LSB and in big endian like when multiple bytes are necessary.

SWF Shape (swf_shape)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_shape {
	swf_styles_count	f_styles_count;
	swf_shape_record	f_shape_records[variable];
};

Fonts uses this declaration. It does not include any style (fill or line) definitions. The drawing will use fill 0 when the inside of the shape should not be drawn and 1 when it is to be filled. The line style should not be defined.

SWF Shape Record (swf_shape_record)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
/* if f_shape_record_type = 0 & f_end_of_shape = 0
then that's the end of the list of shape records */
struct swf_shape_record_end { unsigned f_shape_record_type : 1; unsigned f_end_of_shape : 5; };
/* f_shape_record_type = 0 & at least one of the following five bits is not zero
then change style, fill and position setup */
struct swf_shape_record_setup { unsigned f_shape_record_type : 1; if(f_tag == DefineShape) {1 unsigned f_shape_reserved : 1; /* always zero */ } else { unsigned f_shape_has_new_styles : 1; } unsigned f_shape_has_line_style : 1; unsigned f_shape_has_fill_style1 : 1; unsigned f_shape_has_fill_style0 : 1; unsigned f_shape_has_move_to : 1; if(f_shape_has_move_to) { unsigned f_shape_move_size : 5; signed twips f_shape_move_x : f_shape_move_size; signed twips f_shape_move_y : f_shape_move_size; } if(f_shape_has_fill_style0) { unsigned f_shape_fill_style0 : f_fill_bits_count; } if(f_shape_has_fill_style1) { unsigned f_shape_fill_style1 : f_fill_bits_count; } if(f_shape_has_line_style) { unsigned f_shape_line_style : f_line_bits_count; } if(f_shape_has_new_styles) { swf_styles f_styles; } }; /* f_shape_record_type = 1 -- edge record */ struct swf_shape_record_edge { unsigned f_shape_record_type : 1; unsigned f_shape_edge_type : 1; unsigned f_shape_coord_size : 4; f_shape_coord_real_size = f_shape_coord_size + 2; if(f_shape_edge_type == 0) { signed twips f_shape_control_delta_x : f_shape_coord_real_size; signed twips f_shape_control_delta_y : f_shape_coord_real_size; signed twips f_shape_anchor_delta_x : f_shape_coord_real_size; signed twips f_shape_anchor_delta_y : f_shape_coord_real_size; } else { unsigned f_shape_line_has_x_and_y : 1; if(f_shape_line_has_x_and_y == 1) { signed twips f_shape_delta_x : f_shape_coord_real_size; signed twips f_shape_delta_y : f_shape_coord_real_size; } else { unsigned f_shape_line_has_x_or_y : 1; if(f_shape_line_has_x_or_y == 0) { signed twips f_shape_delta_x : f_shape_coord_real_size; } else { signed twips f_shape_delta_y : f_shape_coord_real_size; } } } }; union swf_shape_record { swf_shape_record_end f_shape_end; swf_shape_record_setup f_shape_setup; swf_shape_record_edge f_shape_edge; };
  • 1. From my tests with the official Macromedia Flash plugin, it looks that there is always a bit at this position. It seems however that it cannot be set to 1 in v1.0 of the tag (i.e. when the DefineShape tag is used).

The shape records are typed. Depending on that type, the contents vary. The following defines one structure for each type. The shape record is a union of these structures.

It is important to note that the f_shape_move_x and f_shape_move_y are not deltas from the current point, but a position from the current shape origin. All the other positions are defined as deltas from the previous position, including the anchors which are deltas from the control point position!

The control point defines how much the curve is curved. Please, see The geometry in SWF for more information.

SWF Shape with Style (swf_shape_with_style)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_shape {
	swf_styles_count	f_styles_count;
	swf_shape_record	f_shape_records[variable];
};

The array of shape records starts with a set of style definitions and is followed by shape records. The last record is marked by a null record.

SWF Sound Info (swf_sound_info)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_soundinfo {
	unsigned short		f_sound_id_ref;
	unsigned		f_reserved : 2;
	unsigned		f_stop_playback : 1;
	unsigned		f_no_multiple : 1;
	unsigned		f_has_envelope : 1;
	unsigned		f_has_loops : 1;
	unsigned		f_has_out_point : 1;
	unsigned		f_has_in_point : 1;
	if(f_has_in_point) {
		unsigned long	f_in_point;
	}
	if(f_has_out_point) {
		unsigned long	f_out_point;
	}
	if(f_has_loop_count) {
		unsigned short	f_loop_count;
	}
	if(f_has_envelope) {
		unsigned char	f_envelope_count;
		swf_envelope	f_envelope[f_envelope_count];
	}
};

Information on how to playback a sound effect. These are found in a StartSound and a DefineButtonSound.

The f_sound_id_ref is a reference to an earlier DefineSound tag.

The f_stop_playback can be set to 1 in which case the sound stops as soon as the next ShowFrame is reached. All the other flags should be set to 0 when this one is 1.

The f_no_multiple flag indicates whether the same sound effect can be played more than once at a time.

The f_in/out_point indicate the start and end points where the sound should start playing and where it will end. f_in_point should always be smaller than f_out_point. By default, f_in_point is taken as being 0 and f_out_point is set to the f_sound_samples_count value.

The f_loop_count defines the number of times the sound will be played back. I don't know yet whether there is a special value which means playback forever.

SWF Styles (swf_styles)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_styles {
	swf_fill_style_array	f_fill_styles;
	swf_line_style_array	f_line_styles;
	swf_styles_count	f_styles_count;
};

This structure is found in the shape with style and change style structures.

SWF Styles Count (swf_styles_count)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_styles {1
	unsigned char		f_fill_bits_count : 4;
	unsigned char		f_line_bits_count : 4;
};
  • 1. Since always aligned, you can read one byte and mask/shift bits quickly on this one.

Note that the line & fill bits are declared as "unsigned char" because they will always be aligned. The proper definition would probably be a bit field though.

SWF Tag (swf_tag, swf_long_tag)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_tag {
	unsigned short		f_tag_and_size;
	f_tag = f_tag_and_size >> 6;
	f_tag_data_size = f_tag_and_size & 0x3F;
	if(f_tag_data_size == 63) {
		unsigned long	f_tag_data_real_size;
	}
	else {
		f_tag_data_real_size = f_tag_data_size;
	}
};

struct swf_long_tag { /* i.e. the last 6 bits of f_tag_and_size = 0x3F */
	unsigned short		f_tag_and_size;
	f_tag = f_tag_and_size >> 6;
	unsigned long	f_tag_data_real_size;
};

The tag and size are saved in a 16 bits little endian unsigned integer. The tag is always aligned to a byte (not a bit). The size is defined in the lower 6 bits. And the short value is in a little endian format as expected by the declaration. If the size is 63 (0x3F), then another 4 bytes are read for the size. This is used for really large tags such as fonts with many characters, audio, video, or images.

WARNING: The following tags only support the long format (i.e. f_tag_and_size & 0x3F == 0x3F even if the size is less than 63.) These are:


SWF Text Entry (swf_text_entry)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_text_entry {
	unsigned		f_glyph_index : f_glyph_bits;
	signed			f_advance : f_advance_bits;
};

The swf_text_entry structure defines a list of characters and the number of TWIPs to skip to go to the next character. Note that f_advance is a signed value. Thus you can write characters from right to left which is useful to write characters in languages such as Arabic in a native way. The number of bits used to define each field of this structure is defined in the DefineText or DefineText2 tags.

SWF Text Record (swf_text_record)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_text_record_end {
	unsigned		f_end : 8;	/* all zeroes */
};

struct swf_text_record_setup {
	unsigned		f_type_setup : 1;	/* always one */
	unsigned		f_reserved : 3;
	unsigned		f_has_font : 1;
	unsigned		f_has_color : 1;
	unsigned		f_has_move_y : 1;
	unsigned		f_has_move_x : 1;
	if(f_has_font) {
		unsigned short		f_font_id_ref;
	}
	if(f_has_color) {
		if(tag == DefineText) {
			swf_rgb		f_color;
		}
		else {	/* if tag is DefineText2 */
			swf_rgba	f_color;
		}
	}
	if(f_has_move_x) {
		signed short		f_move_x;
	}
	if(f_has_move_y) {
		signed short		f_move_y;
	}
	if(f_has_font) {
		unsigned short		f_font_height;
	}
};

struct swf_text_record_glyphs {
	unsigned		f_type_glyph : 1;		/* always zero */
	unsigned		f_glyph_count : 7;		/* at least one */
	swf_text_entry		f_entry[f_glyph_count];
};

struct swf_text_record_string {
	unsigned		f_type_setup : 1;	/* always one */
	unsigned		f_reserved : 3;
	unsigned		f_has_font : 1;
	unsigned		f_has_color : 1;
	unsigned		f_has_move_y : 1;
	unsigned		f_has_move_x : 1;
	if(f_has_font) {
		unsigned short		f_font_id_ref;
	}
	if(f_has_color) {
		if(tag == DefineText) {
			swf_rgb		f_color;
		}
		else {	/* if tag is DefineText2 */
			swf_rgba	f_color;
		}
	}
	if(f_has_move_x) {
		signed short		f_move_x;
	}
	if(f_has_move_y) {
		signed short		f_move_y;
	}
	if(f_has_font) {
		unsigned short		f_font_height;
	}
	unsigned char		f_glyph_count;		/* at least one */
	swf_text_entry		f_entry[f_glyph_count];
};

union swf_text_record {
	unsigned		f_flags : 8;
	swf_text_record_end	f_end;
	if(version >= 7) {
		swf_text_record_string	f_string;
	}
	else {
		swf_text_record_setup	f_setup;
		swf_text_record_glyphs	f_glyphs;
	}
};

The swf_text_record structure is a union composed of a swf_text_record_setup definition followed by characters. Multiple records can follow each others. The list is ended with one byte set to 0.

WARNING: it seems that Macromedia didn't think about a file having two records of type glyph one after another (it makes their plugins crash); you will have to insert a setup record between each glyph record (the setup can be empty: i.e. add one byte equal to 0x80). The very first setup has to at least define the font.

NOTE: this has been corrected by Macromedia it now shows as one structure including the style and an array of glyphs. This fixes the problem at once. It however makes the structure look a bit more complicated.

The very first byte of a record determines its type. When it is set to zero, it is the end of text records. In all versions (though it was not defined that way before), you need to alternate the setup and glyph records. It seems that even older versions would support more than 127 characters, however, if you plan to use 128 to 255 characters in a text records, I recommend you create a version 7 movie. So, in other words, go ahead and use the swf_text_record_string with f_glyph_count set to a value from 1 to 127 in a version 1 to 6 movie.

To make sure that none of the setup records are recognized as the end record, you should always set the bit 7 to 1 (f_type_setup). You don't otherwise have to have any font, color or displacement definition in setups (except the very first which needs to specify a font).

The f_glyph_count must be at least 1. If you don't have any characters, just don't create a text entry.

The f_move_x and f_move_y always specify a position from the origin where the text object is placed like in a shape.

SWF XRGB (swf_xrgb)

SWF Structure Info
Tag Flash Version: 
1
SWF Structure: 
struct swf_xrgb {
	unsigned char		f_pad;
	unsigned char		f_red;
	unsigned char		f_green;
	unsigned char		f_blue;
};

Images without an alpha channel which are saved using 32 bits (format 5) use XRGB colors.

The f_pad field should be set to zero or 255.

The color components can be set to any value from 0 (no intensity) to maximum intensity (255).

SWF Zone Array (swf_zone_array)

SWF Structure Info
Tag Flash Version: 
8
SWF Structure: 
struct swf_zone_array {
	unsigned char		f_zone_count;		/* always 2 in V8.0 */
	swf_zone_data		f_zone_data[f_zone_count];
	/* I inverted the bits below, but I'm not too sure what is correct, do you know? */
	unsigned		f_reserved : 6;
	unsigned		f_zone_y : 1;		/* probably always 1 in V8.0 */
	unsigned		f_zone_x : 1;		/* probably always 1 in V8.0 */
};

An array of alignment zones defines hints about glyphs defined in a DefineFont3.

The f_zone_count specifies how many zones are defined in a zone array. In version 8 of SWF, the count must be set to 2.

The f_zone_data is an array of zones, each defining a position and a size.

The f_zone_x and f_zone_y defines whether the horizontal and vertical positions and sizes are defined. At least one of these flag shall be set to 1.1

  • 1. Since in version 8 you must have 2 in f_zone_count, you most certainly need to set both of these flags to 1 in that version. In effect, all you can currently do is define one rectangle (zone).

SWF Zone Data (swf_zone_data)

SWF Structure Info
Tag Flash Version: 
8
SWF Structure: 
struct swf_zone_data {
	short float		f_zone_position;
	short float		f_zone_size;
};

The swf_zone_array includes an array of zone data as described below:

The f_zone_position specifies the X or Y coordinate. The array can either include only horizontal, only vertical or both sets of coordinates.

The f_zone_size specifies the Width or Height of the zone.