• Keep in touch:
  • Linked In
  • Twitter
  • RSS

Archive for the ‘transform’ Category

Smooth Zooming Depends on Flash Version

I was recently helping out with an web application for creating custom slide-shows for cars using photos that dealers would upload to the site. The problem is straight-forward enough and when the first slide-show was generated with a reasonably high resolution image (640 x 480, gasp) we were greeted with the following scene:

The first reaction was that the Flash Player was having a hard time rendering the image at the default 20 frames per second, which seemed an unlikely event since movie was being viewed using the stand-alone Flash Player running on a core i7 desktop. Slowing the frame rate down did not do much, besides we needs to keep the frame rate high in order to get a smooth animation. The problem only seemed to affect zooming (panning was mostly ok) – the fine lines around the door appeared to be suffering from aliasing so after all the attempts to see if the movie could be tweaked to reduce the load on the Flash Player failed we tried smoothing the image first before adding it to the movie. The results were better but there were still visual artifacts and the quality of the image was starting to suffer before we got something that was watchable.

One interesting observation came when the Player screen was larger or when zooming in – the animation appeared smoother. The next attempt at a solution was to resized the image. The idea was that the Player had one image pixel for each screen pixel and that is why the aliasing was occuring. With more image pixels then the Player would be better able smooth the image when it was rendering it. At x2 the results were definitely better. At x4 the results were great, phew:

The only problem was that the file size was getting a little on the large size. Fortunately drastically reducing the JPEG quality during the resize process did not seem to visually degrade the image and the final movie size was comparable to the one with the original images.

So while we had a working solution and met the deadline (just) the results weren’t great. I took another look at the code which was based on Transform 2.3 and ported the method used to do the zooming over to Transform 3.0 – just to see if there was a bug or someother configuration problem that was biting us. Imagine the surprise when the the following movie was generated using the original sized images:

So what was the difference? Double-checking the code and the binary format of the files revealed nothing; correct fill style ? check; same classes, check; same binary? check; same swf version ? No! Rushing back to the web app I changed the default swf version for Transform 2.3 from 7 to 8 and voila a nice smooth zoom with images at their original size.

So what was going on ? To be honest I am not sure. The fill style using for displaying the image definitely specified image smoothing – I even checked the bits encoded on the file but for some reason the Flash Player decided to turn smoothing off – hence all the jagged lines. Only when the frame rate was insane (100 fps) or the images large (x4) did the Player turn smoothing on. It could be a bug, however image smoothing has been in the Flash specification for a long time so it is hard to believe that this problem went unnoticed or unfixed for long. Could it be an evil plot to force people to upgrade to Flash 8 and beyond? Although unlikely this give an insight into how the Flash Player works. The different text rendering engines that have been deployed by Macromedia and Adobe to get better text quality is well known however it also appears that there are different sub-systems for images handling too. Any movie with swf version 7 or below is likely to run into smoothing problems and anything using swf 8 or above will be ok.

MORAL: Unless you are targetting a specific hardware profile, for example, a set-top box or mobile device go for the highest version of Flash that your users will be able to easily view. For most applications this will probably be Flash 8.

Covert Actions

One interesting technique for obfuscating Flash files that I came across when using real-world files for testing Transform SWF was hiding actions in the body of a tag earlier in the movie. Here is how it works. The header field in a tag normally contains the type and length of the encoded body in bytes. The length field effectively tells the Flash Player where the next tag starts.

Here is a typical situation where a frame is displayed (ShowFrame) followed by the set of actions (DoAction) that will be executed for the next frame.

If you change the value of the length field in the ShowFrame tag (it should always be zero) you can hide a block of actions inside the body of the tag.

The Flash player has no problem executing this since ShowFrame tags do not contain any data so it happily ignores the hidden actions until they are jumped to by the following DoAction tag. The same technique is used within blocks of actions where the length field of a Table action (which contains the strings used in a script) is increased so allow actions to be appended to the encoded strings and so hide them.

The interesting part is not that the technique is possible but that the movie appears to be loaded into memory as-is, otherwise the actions that jump and return from the code in the hidden block would not work.

This type of obfuscation is not encountered very often, so Transform SWF 3.0, out of the box, is not able to decode the hidden actions. If you do decode a file then the hidden actions will simply get lost when the file is re-encoded. However you can easily add a custom decoder class to Movie that will decode all the tags as MovieObjects. Then step through the list comparing the type against the size of the encoded body. If you find a ShowFrame object (type = 1) where the number of bytes in the body is greater than zero and the next object is a DoAction (type = 12) then it is reasonable to assume the ShowFrame tag contains hidden actions.

This approach is easily defeated however if the actions are hidden in a tag where you would expect binary data, i.e. an image, since there is no discrepancy between the length of the tag and the actual payload. (I have never seen this variation so I am not sure it works). In this situation you would have to step through the decoded actions looking for a JUMP or IF where the offset was outside the block of actions in the tag and follow this to identify which tag contained the hidden actions. This is more complicated to deal with but not overly difficult.

Of course, the simplest way of handling this type of file is not to decode it in the first place. If someone went to the trouble of obfuscating the actions it means that they do not want third-parties looking at their work. So it is best to leave well alone.

Transform SWF 3.0.1 now available

Transform SWF 3.0.1 is now available for download. This release fixes the following bugs:

  • Decoding JPEG images with odd number of bytes in the image data throws an exception.
  • DefineButton2 does not execute any actions.
  • BigDecoder throws an excaption when pre-fetching 4 bytes and only 2 bytes are available.

This release is also available from the Maven Central Repository.

groupId: com.flagstone
artifactId: transform
version: 3.0.1

Well, It Took A While

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.

Hard To Port?

Quick question: Is porting an application from Transform 2.3 to 3.0 difficult?
Quick answer: no.

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);

Generally porting was pretty painless. The biggest annoyance was having to changing type declarations for arrays from: ArrayList actions = new ArrayList(); to: List<Action> actions = new ArrayList<Action>();

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.

Going, going….

Getting the latest Java version of Transform SWF out of the door has been an enormous amount of work. Most of theĀ  problems were a direct result of reading Joshua Bloch’s “Effective Java” more than a few times – a remarkably good book, discovering PMD andĀ Software Craftsmanship – yes I know this is 2010 and not 2001. Also starting a family and having a day-job did not help either.

So with new versions of Transform and Translate scheduled for release on Sept 15th I started thinking about the C++ versions of the libraries which, although quite useful, have been languishing untouched for quite some time now. Initially I was quite looking forward to getting them freshened up and getting the code to the point where I could say that it was rather nice, or at least it didn’t suck as much. But then, well, I started thinking about what that would take. Getting the code updated to support Flash 10 was not really the hard part – after all at the lowest level, C++ and Java syntax are not that different, especially when reading and writing bytes with streams, so the new Java code could easily be moved over to the C++ version. The harder part was cross-platform support. There are simply too many platform variations to be able to support it effectively. CMake does a good job of reducing the effort by making cross-platform builds easy, but the real issue is answering the “I can’t get it to work” requests. Limiting the set to compiler X on platform Y is too restrictive and does not solve the problem since there are still X * Y * Z versions to deal with.

So the C++ code is going to be retired – permanently this time. Instead if you need a library for generating Flash files with C and C++ bindings then take a look at Ming. After a dormant period, activity on the project is picking up again. They have support for Flash 8. Platform support is good, though building on Windows is kind of hairy (more on that later). I tried porting some examples from the Cookbook to Ming and the API is quite effective. The basic concepts and actions to generate a Flash file are the same and re-writing the simpler examples such as, BasicShapes, did not take long – the hardest (time-consuming) part was changing ints to doubles.

So over the next few weeks I am going to port the rest of the Cookbook to see, overall, how easy it is to use Ming. I’ll also post the code and ming libraries since there seems to be some demand for windows binaries and not a lot of success at creating them.

Now in Beta

Version 3.0 of Transform SWF for Java is now officially in beta. Rather than run with this for an enternity (Google, I’m looking at you) the goal is to get to a production release by the end of the summer – nominally early September.

The focus of work from now on is to start expanding the unit tests and so lessen the dependence on testing with real-world Flash files. Although these are useful and provide a great way of verifying that the code does really work as opposed to simply passing the tests it is not practical to include them in directly in the project for various reasons – file size and copyright being the two largest issues.

All the planned refactoring has been completed so the API should be considered stable. If there are changes, most likely resulting from feature requests I will send out notification in advance so there are no suprises on the next update.

This version is also available from the Maven Central Repository:

<dependency>
<groupId>com.flagstone</groupId>
<artifactId>transform</artifactId>
<version>3.0-b1</version>
</dependency>

A big thank you to Sonatype for providing a Maven repository for Open Source projects and rapid syncing with Maven Central.

Regular status reports and details of any issues reported will be posted on the transform-swf-updates mailing list.

Now Goes To Eleven

Well not quite, but full support for Flash 10 is included in the alpha release of Transform SWF 3.0 which is now available from the downloads page.

Although this release has an alpha label it has been extensively tested using a large suite of real world Flash files with only a few minor issues.

The current plan is it keep the release in alpha for a short time – probably up to the end of June – to do some more testing and continue with the polishing and general clean-up of the code then move to a formal beta until the end of August and from there release 3.0 formally in early September once everybody is back from vacation and the reported bugs and issues have been resolved.

Regular status reports and details of any issues reported will be posted on the transform-swf-updates mailing list.

Transform SWF 2.3.3 for Java now available

Transform SWF 2.3.3 for Java is now available for download. This release fixes two bugs when decoding AWT Fonts to generate font definitions using the FSTextConstructor.

Bug Fixes:

  • Using characters with high value character codes causes errors.
  • AWT Fonts on Mac OSX are offset.

The release notes, http://www.flagstonesoftware.com/downloads/transform-java-2.3.3.txt has all the details.

Transform SWF 2.3.2 for Java now available

Transform SWF 2.3.2 for Java is now available for download. This release fixes bugs when encoding movies with not UTF-8 character sets and improves the handling of sound files.

Bug Fixes:

  • FSMovie does not set the character encoding in FSCoder.
  • FSSoundConstructor accepts sounds with any sample rate.
  • Extended arrays in FSShapeStyle are encoded as bit fields

The release notes, http://www.flagstonesoftware.com/downloads/transform-java-2.3.2.txt has all the details.