Archive for the 'Flash' Category

Some useful tips on Flash, caching and Php

Wednesday, September 13th, 2006

Making the test for some strange flash cache behaviour I've learned some useful tips:

You can be sure a movie will be loaded appending a query string to the file name:

Actionscript:
  1. loadMovie("clip.swf?123", target);

 

You can force the user to reload a movie when you release a new version:

Actionscript:
  1. clipname= "cache"+VERSION+"-clip.swf";
  2. loadMovie(clipname, target); //Loaded
  3. //After the first load the movie is cached:
  4. loadMovie(clipname, target2); //Cached

And use a .htaccess file (ModRewrite required):

Apache:
  1. RewriteEngine on
  2. RewriteCond %{REQUEST_URI} cache([0-9]+)-(.*)\.swf(.*)$
  3. RewriteRule ^cache([0-9]+)-(.*)\.swf(.*)$ $2\.swf [L]

Only when you change the VERSION variable (pass it with flashVars) the movie will be reload, otherwise it will be loaded from the browser cache.
 

You can make cacheable a file downloaded through php:

PHP:
  1. header('Last-Modified: '.date( "D, j M Y G:i:s \G\M\T", filemtime($filename) ));

Be sure to set the correct content type:

PHP:
  1. $filename= "clip.swf";
  2. $fp = @fopen($filename,"r");
  3. if($fp){
  4.     header('Last-Modified: '.date( "D, j M Y G:i:s \G\M\T", filemtime($filename) ));
  5.     header('Content-Length: '.filesize($filename));
  6.     header('Connection: close');
  7.     header('Content-Type: application/x-shockwave-flash');
  8.  
  9.     while (!feof($fp)){
  10.         echo(fgets($fp, 4096));
  11.         ob_flush();
  12.     }
  13.     fclose($fp);
  14. }
  15. else
  16. {
  17.     header("HTTP/1.0 404 Not Found");
  18. }

Without Last-Modified or ETag headers flash doesn't cache the files.

Strange Flash cache behaviour and attachMovieAnywhere solution

Monday, September 11th, 2006

Some days ago I've read about an old problem:
if I load a swf with some identifiers, I can't "attachMovie" them anywhere, but only in the loaded movie:

Actionscript:
  1. //If you do:
  2. myClip.loadMovie("libraryfile.swf");
  3. //then you can attach movie only in this scope: "myClip":
  4. myClip.attachMovie('clip1', 'foo', myClip.getNextHighestDepth());
  5.  
  6. //this doesn't works:
  7. _root.attachMovie('clip1', 'foo', _root.getNextHighestDepth());

This can be really a problem if you decide to move some assets to external files too late in the development, probably you'll have to rewrite substantial part of the application or it can be just impossible.

The simplest way to load an external resource and still be able to attach movies everywhere is to "Import for runtime sharing" it, but in this way you can't control via actionscript when to load or change what file to load (for example, to change the theme).

The solution:

Since I've noted some strange behaviour loading files in the flash ide, I've opened my trusty Ethereal sniffer and I've found something interesting:
When flash load a clip and cache it, it will not try to reload it until the page is refreshed.
What does it mean?

Actionscript:
  1. var mcLoader:MovieClipLoader = new MovieClipLoader();
  2. //This send to server: GET /libraryfile.swf HTTP/1.1
  3. mcLoader.loadClip("libraryfile.swf", target);
  4.  
  5. var mcLoader2:MovieClipLoader = new MovieClipLoader();
  6. //This don't send nothing, No bandwidth waste :)
  7. mcLoader2.loadClip("libraryfile.swf", target2);

In the above example, after the first load, every time I'll load "libraryfile.swf" in the movie, flash will take it from the memory and not from the server.
So I can load it everywhere I need it without using any bandwidth. In this way I can attach the loaded resources everywhere in the movie.
The next time the page is loaded, flash will ask the server for the file only the first time.

This can be a problem when we want to check if an swf was modified, in this case we have to put a ? in the filename to be sure the file will be reloaded:

Actionscript:
  1. //This is _always_ reloaded:
  2. clipName = "clip.swf?"+ Math.random();

AttachMovieAnywhere:

This simple function can be useful to attach a loaded movieclip anywhere:

Actionscript:
  1. MovieClip.prototype.attachMovieAnywhere = function(file:String, idName:String, newName:String, depth:Number, initObject:Object ) {
  2.         if(depth == undefined) depth = getNextHighestDepth();
  3.     var parent:MovieClip = this;
  4.     var container:MovieClip = this.createEmptyMovieClip(newName, depth);
  5.     var mcLoader:MovieClipLoader = new MovieClipLoader();
  6.     var listener:Object = new Object();
  7.     listener.onLoadInit = function (mc) {
  8.         mc.attachMovie(idName, newName, mc.getNextHighestDepth());
  9.         parent[newName] = parent[newName][newName];
  10.     }
  11.     mcLoader.addListener(listener);
  12.     mcLoader.loadClip(file, container);
  13. }

The usage is simple:

Actionscript:
  1. var container:MovieClip = this.createEmptyMovieClip("container", getNextHighestDepth());
  2. container.attachMovieAnywhere('foo.swf', 'clip', 'foo');
  3. //One frame later:
  4. container.foo._x = 100;

The main difference from attachMovie is that the attached movieclip will not be avaible until the next frame.

Conclusions:

It is a bug? I don't think, this isn't much different form how a browser works: after the first occurrence of <img src="img.jpg"/>, it will not try to reload "img.jpg" if another <img src="img.jpg"/> is found.

So why I haven't found it before? :)
Maybe because I have always thought that "loadClip" would have loaded file, maybe receiving a "HTTP1/1 304 Not Modified" reply, instead of silently take the cached one, who knows!

I'm sure there are plenty of experienced flash developers out there that already know this, but I've found many questions about this problem and I hope this can be useful to someone :)

 

To be sure that this stuff works I've made a test for it, it was useful to me to better understand how the flash cache mechanism works and to test it on many platform.
Feel free to leave a comment if something doesn't works.
(It is sufficient to view this post to participate, the results will be stored for statistic purpose only)

Object Explorer extension

Saturday, July 22nd, 2006

Ok, I've finished the object/class viewer and I've named it Object Explorer.
You can find the Object Explorer project page here or download the extension for the flash ide here.

For everyone interested in making his own extension: useful link on making flash extension.

Reference Explorer

Sunday, July 16th, 2006

Page outdated, for the new version of this application visit: Object Explorer

Ok, the exams are gone, and I'm ready to came back to my projects!

Finally, I've (almost) completed a reference explorer for flash: this application show the object tree in a swf, it can be useful while debugging and it can help find circular references:
in Flash up to 7 circular references doesn't allow objects to be deallocated by the garbage collector. A nice explanation of the problem can be found in this Grant Skinner's blog entry.

Although this issue doesn't exist for the new Flash 8 garbage collector, it is still present in Flash Lite 2.x.
A reference explorer can also help refactoring or be useful to visually debug your flash projects and to explore object dependencies, in future I could extend it to show information useful for debugging like object variables and class hierarchies.

Usage:

  • Download it and click on main.html
  • Type the name of the swf you want to load, you can see the movie in a window
  • When you are ready click "Analyze" to show the object diagram
  • Red objects contain a circular reference, the name of the variable holding that reference is showed in a box
  • After each object name you can see the class name

 

Download source and swf:
ReferenceExplorer.zip

Try it online with a test swf: (or your own if you set proper cross domain policies)
Reference Explorer

 

Reference Explorer at work:

 

Some links on garbage collection in Flash Lite:
Flash Lite memory management (LiveDocs)
Comparison between Java ME and Flash Lite
Flash Lite memory management

Must-read for AS3 developer

Tuesday, July 11th, 2006

André Michelle in his blog point to a great article about AS3 internals by Gary Grossman, the creator of Action Script.

Flash 8 Image recognition

Monday, June 26th, 2006

Recently I've implemented two common algorithms for skeletonization (a common technique in the image recognition area, used for example for text recognition): Zhang-Suen and Hilditch. Although very limited and slow, i think flash can be used for simple image processing, like image-driven search, simple object recognition and image enhancement.

Swf (best in projector): elaborazione.swf

Source: elaborazione.fla