Tech
Modifying a Gramophone/Phonograph to work with an iPod
How I modified a replica gramophone so I could plug in a standard music player.
One-Time Image
Visual encryption of images using the principle of the one-time pad.
Finding the Dimensions of the Player in Flash
Ways to determine the size at which your flash movie is playing back when embedded in a web page.
Finding the Dimensions of the Player in Flash
From an object-oriented standpoint, Flash is an excellent exemplar of structuring code to have high cohesion and low coupling - it encourages the creation of stand-alone objects (movie-clips, buttons etc) which include all of their functionality - these objects can then be included in a larger project where they can be created, destroyed, scaled and otherwise operated upon and altered.
Sometimes, however, the low degree of coupling means it's very hard for a movie clip to acquire information it needs. The example I ran into was determining the dimensions of the player, and I'm writing this to communicate the problem, and the solutions I found to it.
By default, when an .swf file is opened, whether in the stand-alone player, or embedded in a webpage, it scales the content to fit the player while maintain the aspect ratio of the original file. However, by setting the scaleMode property of the Stage, this can be changed from the default value of showAll: using noBorder scales the movie to the player maintaining the aspect ratio, but eliminating borders at the cost of possibly cropping the movie, exactFit scales both dimensions of the movie to fit the player dimensions, ignoring the aspect ratio, and noScale shows the movie at its original size, no matter the dimensions of the player.
Why would you want to know?
In most cases, this is fine - Flash itself knows the dimensions of the player, and applies the appropriate scaling. However, in some situations we may not want to settle for any of the default - we want to apply our own scaling. The most obvious reason is if we want some items to scale with the stage, and others not to - for example, consider developing an embedded movie player. We might want to be able to embed it in a variety of different sizes to play different sized movie clips, but on the other hand we want the size of the control panel to remain the same - there's no reason the play button should be twice as large when we're watching a 640x480 clip than when we're watching one at 320x240.
So, we want some (probably most) of the objects in the movie to scale, but not all. We could do thisby knowing the dimensions at which we're playing the movie, and then using those to manually rescale some of the components. I'm going to focus on the first part here (getting the dimensions), since it's the tricky bit.
Getting the dimensions
Unfortunately, if you try all the obvious things, you'll find they don't work - getting the dimensions of the Stage, for instance, will just give you the dimensions of the original movie, not the dimensions it's been scaled to. The Stage also has a useful-looking onResize event you can add a listener to catch, but it only applies to noScale, and we want our movie to scale (some of it, at least). I present two solutions: the simple, robust method, and the cool, overcomplicated method.
The straightforward method is simply to pass the values for height and width in when you embed the player via FlashVars:
<param name="movie" value="movie_player.swf">
<param name=FlashVars value="pWidth=640&pHeight=480">
<embed src="movie_player.swf"
FlashVars="pWidth=640&pHeight=480"
width="640" height="480">
</embed>
</object>
Now you can access the new global variables pWidth and pHeight inside the program which'll give you the dimensions at which the movie's being played.
That's the simple way, but I still wanted to find a way to do it 'properly', without relying on external help - after all, the Flash plugin knows the values, so surely there's some way to access them internally?
Actually, there is, though it's somewhat roundabout. As mentioned previously, when the Stage.scaleMode is set to noScale and the dimensions of the player change, an onResize event is broadcast which gives the new height and width. In order to get this call when we start the flash movie, we first set the scaleMode to exactFit (or whichever of the other scaling modes you want). In your actionscript, then add a call to change the scaleMode to noScale:
Now, as soon as the movie loads the scale mode will change, and if the dimensions of the player aren't the same as the Stage, an onResize event will be generated. Add a listener to catch it, and in the function add code to change the scaleMode back to your original setting, as well as storing the height and width of the player in global variables:
stageListener.onResize = function()
{
pHeight = Stage.height;
pWidth = Stage.width;
Stage.scaleMode = "exactFit";
}
Stage.addListener(stageListener);
By placing the call to reset the scaleMode inside the listener we eliminate any chance of a race condition; any call to resize components should also be placed here to ensure we have the player height and width before we call the functions. It's also important to note that your components should, by default, be sized correctly for the default Stage dimensions, as in the event that the size of the player matches that of the Stage (eg, the movie is embedded at the same dimensions as the Stage) no onResize callback will be generated.
Using the dimensions
Once you have the dimensions of the player, you can use them to rescale any components you want to appear the same size no matter at what size the .swf file is being played. Doing this is relatively straightforward: you just need to set the dimensions of the components to their original sized multiplied by a scale factor. Functions like these will calculate these adjusted length when you give the original lengths:
{
return (originalHeight*(Stage.height/pHeight));
}
function getScaledWidth(originalWidth)
{
return (originalWidth*(Stage.width/pWidth));
}
In most cases you'll also need to change the _x and _y values of the components; I find it's easiest to resize all the components first, and then directly use their adjusted widths and heights to reposition them as necessary.
Where possible, it's best to encapsulate the components you don't want to scale into as few movie clips as possible to reduce the amount of resizing and repositioning code you need to write, as it's generally pretty tedious, and may need to be updated if you make layout changes at a later date.
Conclusion
Using these methods, you should be able to build flash applications which can be embedded at any size, intelligently redistributing their layout to look as good as possible. It has some limitations (for instance, if you embed the .swf file with its width being a percentage of the page, the first method won't work at all, while the second will correctly scale things initially, but won't make any changes if the user resizes their browser window), and most flash developers are probably happy with the default behaviours anyway, but this should help out anyone with this particular problem.