Archives

Search Box

Meta

Posts Tagged ‘Java’

After an elephantine gestation period Transform SWF 3.0 has finally been kicked out of the door and is ready for life in the big, wide world.

The big new feature is that the code supports Flash 10. Another important change is that now you can write your own decoder classes, so for example, if you want to process files to extract or update only the images you can easily write a class that decodes only the image tags and leaves everything else as binary data. Combined with the new stream based I/O this means that you can easily process large numbers of files without using much memory. Pretty much everything else was refactoring, cleaning up and generally making everything as pretty as possible. So if you are already using Transform SWF 2.3 then the new code will appear familiar, though the methods may have changed. All the Cookbook examples have been ported to use version 3.0 so this is the best place to get oriented with the new API.

With the upcoming release of Transform SWF 3.0 on Sept 15th it was time to move all the existing Cookbook examples over to use the new code. The process was surprisingly easy, though a little tedious, so that bodes well for anyone upgrading any existing applications.

The major changes in Version 3.0 were essentially structural and general cleanup rather than “semantic”. There is still a one-to-one mapping from the data structures in the Flash File Format Specification to classes in Transform. The classes are still essentially Java Beans that know how to encoded and decode themselves so the new version will be familiar, if not quite identical. Some of the changes, major and minor which affect porting existing code include:

Shorter class names. The “FS” prefix (a hangover from the original Objective-C code written a very long time ago) is gone and tedious to use names such as SetBackgroundColor, FSPlaceObject2 and FSRemoveObject2 now become the slimmer and fleeter: Background, Place2 and Remove2 respectively.

Fewer constructors for classes with optional fields. Instead of having constructors for every combination of optional fields, with FSPlaceObject2 being the canonical, bloated and easy to misuse example, now the classes are their own Builders. Typically there is one constructor and the set methods return the object allowing several calls to be chained together. For example, creating a ShapeStyle used to be:new ShapeStyle(1, 1, 0, 0, 0) now it is the much more readable but slightly verbose: new ShapeStyle().setLineStyle(1).setFillStyle(1).setMove(0, 0)

Movie objects used to maintain a counter used for generating unique identifiers for definitions. This is no longer the case and applications have to maintain the counter themselves. This means that calls such as: DefineMovieClip clip = new DefineMovieClip(movie.newIdentifier(), new ArrayList()); are now replaced by: int uid = 1;
...
DefineMovieClip clip = new DefineMovieClip(uid++, new ArrayList());

Integer constants are replaced by enums, e.g. the codes representing compound events for movie clip event handlers are now replaced by the Event enum and multiple events are represented with EnumSets.

Immutable classes make for fast copying of the parent object, so all actions and basic data types such as bounding boxes, coordinate and colour transforms are now immutable. Constructing immutable objects with multiple values, e.g. the Push NewFunction[2] actions and all Filters now employ special Builder classes:Push.Builder builder = new Push.Builder();
builder.add(integer).add(string);
actions.add(builder.build());

New Factories and Service Providers. The utilities classes that were used to generates the objects representing images, sounds and text were refactored to follow the Service Provider pattern. This was the biggest structural change, though the impact on existing code is relatively minor. For example creating the definition for an image was: FSImageConstructor imageGenerator = new FSImageConstructor(imageFile);
FSDefineObject image = imageGenerator.defineImage(movie.newIdentifier()); In the new version this becomes:final ImageFactory factory = new ImageFactory();
factory.read(new File(imageFile));
final ImageTag image = factory.defineImage(uid++);

Movie is now strictly a container. The fields such as version, signature, frameSize and frameRate are now part of the new MovieHeader class. This change was designed to make it easier for people to write their own decoders and to be consistent with other meta-data objects such as MovieMetaData and MovieAttributes since it was not practical to move everything into Movie. For example: FSMovie movie = new FSMovie();
movie.setFrameRate(1.0f);
movie.setFrameSize(new FSBounds(-4000, -4000, 4000, 4000)); Now becomes: Movie movie = new Movie();
MovieHeader header = new MovieHeader();
header.setFrameRate(1.0f);
header.setFrameSize(new Bounds(-4000, -4000, 4000, 4000));
movie.add(header);

There was one gotcha that took a little time to figure out (though not long). I ported Translate SWF to use classes in the new version of Transform rather rely on private copies intended to make the library independent of Transform. Now that actions are immutable:List<Object>values = push.getValues(); returned a copy of the array of values rather than a reference, so:List<Object>values = push.getValues();
values.add(literal); has no effect. However once I had figured out / remembered what the problem was the change was trivial:List<Object>values = push.getValues();
values.add(literal);
actions.set(index, new Push(values));

Not all the change required to port an existing codebase are listed. The best guide would be to perform a diff between the new Cookbook examples when they are released, with the current version for Transform 2.3. That should give a good overview of what needs changing, at least for relatively simple applications.