PDA

View Full Version : Programming Programs to Write Programs


pingnak
09-23-2008, 10:31 PM
I tend to automate things. Automating automation is no exception to this rule.

If I'm going to have to do it more than once or twice, I tend to jump through some hoops to make sure the machine does it for me.

I'm not just evil enough to run my Actionscript code through a C preprocessor (http://flex2cpp.sourceforge.net/index.html) just so I have my macros and conditional compilation.

No, I'm sick enough that I write programs to to write programs. Have done so for years. No cure for it.

Take this simple little doohicky, a 'slide show' applet. It's part of a larger web site that has a ton of screen captures from games that are cycled when the main application loads them as a preview.

It started off that I'd grab all those pictures, drop them into Flash, and make a little 'movie' out of them. That was too much damned work.

So I wrote a little piece of Flex code, and then I cut it up into pieces.

SlideShow_1.as

/**
* Dumb slide show applet
**/
package
{
import flash.display.*;
import flash.text.*;
import flash.geom.*;
import flash.events.*;
import flash.media.*;
import flash.xml.*;
import flash.utils.*;



SlideShow_2.as

public class SlideShow extends Sprite
{
public const msSlideInterval : int = 2000; // How long between frames
public var timer : Timer; // Slide changing timer
public var aBitmap : Array; // Array of bitmaps to display
public var iFrame : int = -1; // Frame index
public var bmCurr : Bitmap; // Current bitmap

/**
* Do 'standard' two part construction.
* When run alone, 'stage' is set in constructor.
* When run from another swf, 'stage' isn't initially set.
**/
public function SlideShow()
{
new Resource();
addEventListener( Event.ADDED_TO_STAGE, addedToStage );
aBitmap = [];
for each (var img : Class in Resource.aImageClasses )
{
aBitmap.push( new img() );
}
}
public function addedToStage( event : Event ) : void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.HIGH;
timer = new Timer(msSlideInterval);
timer.addEventListener(TimerEvent.TIMER,NextFrame) ;
timer.start();
NextFrame();
}
/**
* Go to next frame of slide show
**/
public function NextFrame( event : Event = null ) : void
{
//trace( "NextFrame" );
if( ++iFrame >= aBitmap.length )
iFrame = 0;
if( null != bmCurr )
removeChild(bmCurr);
bmCurr = aBitmap[iFrame];
addChild(bmCurr);
}
}
}
/*
* Local Resource embed class appended by external script code
*/
class Resource
{


SlideShow_3.as

public static var aImageClasses : Array = [];
public function Resource()
{



SlideShow_4.as

}
}


Then I wrote myself a little script to find all the images in a folder, sort them and insert them into the code. If you note the original, and what's missing from the pieces, this basically measures the first image, makes a [SWF()] metadata to size up the applet, then builds a list of images to import with [Embed()] metadata. It dumps the code into the output .as file, then invokes mxmlc on it.

(Note, you only need the FREE Flex SDK to build it.)

The pieces most of you won't understand are 'sed' and 'identify'.

'Identify' came from ImageMagick. A set of command-line based image manipulation tools. I could do additional things, like resize the images, turn them into one format or another, etc. All I use 'Identify' for is to find out how big the image is, and format out the 'SWF' metadata.

'Sed' (The Stream Editor) is an ancient (1977) Unix/Linux/etc. tool that's probably older than most people reading this. It performs regular expression search/replace on text. It's super handy.

makeslides.sh

#!/bin/bash

if test ! -z "$1" && test -d "$1" ; then

imgdir=$1
if test -z "$2" ; then
swfout=$1.swf
else
swfout=$2
fi
set -o errexit # Stop running the script if an error occurs
set -o nounset # Stop running the script if a variable isn't set
# Find any supported images in the folder
find "$imgdir" \( ! -regex ".*.svn.*" -a \( -iname *.png -o -iname *.jpg -o -iname *.jpeg \) \) > tmp

# echo First part of source code
# SlideShow_1-SlideShow_4 are pieces of one as file that this dumps some
# additional code/data into
cat src/SlideShow_1.as > SlideShow.as

# Sort the file list, then grab the first one, then make 'SWF' metadata
# identify is from ImageMagick - tell script about file format
# sed (Strem Editor) is an ancient unix tool
sort tmp | sed q tmp | sed "s/\(.*\)/\"\1\"/" | xargs -L 1 identify -format "[SWF(width=\"%w\", height=\"%h\",frameRate=\"30\", backgroundColor=\"0x000000\")] // %d/%f" >> SlideShow.as

# echo more of the source code
cat src/SlideShow_2.as >> SlideShow.as

# Build list of Embed metadata items
sort <tmp | sed "s/\(.*\)$/\t[Embed(source=\"\1\")] public static const image/" \
| sed -n -e "/.*/ p;=" \
| sed -e 'N;s/\n//' \
| sed -e "s/$/ : Class;/" >> SlideShow.as

# echo more of the source code
cat src/SlideShow_3.as >> SlideShow.as

# Add the list of Bitmaps we embedded to a list
sed -n "=" <tmp | sed "s/\(.*\)/\t\taImageClasses.push(image\1);/" >> SlideShow.as

# echo last of the source code
cat src/SlideShow_4.as >> SlideShow.as

# Now compile the
mxmlc -compiler.optimize=true SlideShow.as -o "$swfout"

# Clean up tmp file
rm tmp

else
# Parameter was invalid
echo
echo $0 srcDir [tgtSwfName]
echo
echo srcDir: Where to look for swf files
echo tgtSwfName: What to call the swf file
echo "If tgtSwfName isn't specified a swf file named after the folder is made."
echo
echo Generate a slide show swf from a folder full of image files.
echo
exit 1
fi



Here's a version for you pitiful Windoze lusers so you don't feel left out.

makeslides.bat

@echo off

set imgdir=%~f1
set swfout=%~f2

if "%imgdir%" == "" goto help
if "%swfout%" == "" set swfout=%~f1.swf

set SED=tools\sed
set IDENT=tools\identify
rem Find any supported images in the folder
dir /s /b "%imgdir%\*.png" > tmp 2>nul
dir /s /b "%imgdir%\*.jpg" >> tmp 2>nul
dir /s /b "%imgdir%\*.jpeg" >> tmp 2>nul

rem echo First part of source code
rem SlideShow_1-SlideShow_4 are pieces of one as file that this dumps some
rem additional code/data into
type src\SlideShow_1.as > SlideShow.as

rem identify is from ImageMagick - tell script about file format
rem Sort the file list, then grab the first one, then make 'SWF' metadata
sort tmp | %SED% q tmp | %SED% "s/\(.*\)/\"\1\"/" | %SED% "s/^/@%%IDENT%% -format \"[SWF(width=\"%%%%w\", height=\"%%%%h\",frameRate=\"30\", backgroundColor=\"0x000000\")] \/\/ %%%%d\/%%%%f\" /" > tmp.bat
call tmp.bat >> SlideShow.as

rem echo more of the source code
type src\SlideShow_2.as >> SlideShow.as

rem Build list of Embed metadata items
sort <tmp | %SED% "s/\\/\//g" | %SED% "s/\(.*\)$/\t[Embed(source=\"\1\")] public static const image/" | %SED% -n -e "/.*/ p;=" | %SED% -e "N;s/\n//" | %SED% -e "s/$/ : Class;/" >> SlideShow.as

rem echo more of the source code
type src\SlideShow_3.as >> SlideShow.as

rem Add the list of Bitmaps we embedded to a list
%SED% -n "=" <tmp | %SED% "s/\(.*\)/\t\taImageClasses.push(image\1);/" >> SlideShow.as

rem echo last of the source code
type src\SlideShow_4.as >> SlideShow.as

rem Now compile the
mxmlc -compiler.optimize=true SlideShow.as -o "%swfout%"
if errorlevel 1 exit /b 2

rem Clean up tmp file
del tmp tmp.bat

goto end
:help
rem Parameter was invalid
echo.
echo %0 srcDir tgtSwfName
echo.
echo srcDir: Where to look for swf files
echo tgtSwfName: What to call the swf file
echo If tgtSwfName isn't specified a swf file named after the folder is made.
echo.
echo Generate a slide show swf from a folder full of image files.
echo.
:end



Now to make it recursively eat folders and poop out swf files, you need one more script...

allslides.sh

#!/bin/bash

set -o errexit # Stop running the script if an error occurs
set -o nounset # Stop running the script if a variable isn't set

find screenshots/* -type d \( ! -regex ".*.svn.*" \) \
-exec ./makeslides.sh \{\} \;


allslides.bat

rem first sed: Eat paths with .svn in them
dir /b /ad /s screenshots | sed -n "/\.svn/!p" | sed "s/\(.*\)/call makeslides.bat \"\1\"/" > atmp.bat
call atmp.bat
del atmp.bat


Now, if you've skimmed this far, you may be thinking to yourself, "Self, what the heck would I ever do with THIS?"

Well, I'll tell you. With minor modification, the script could do a LOT more than just slurp images into a slide show swf.

You could maintain all of your version-controlled art/sound/video/etc. assets in a directory tree and make this a part of a makefile (or ant, I suppose) script, and it would be able to make one Resource.as file containing all of your resources as static members of some Resource class.

So instead of screwing around in Flash to maintain your resources, embed all of the bits into your source code automagically.

At the very least you should see that when you have a lot of little pieces to manage, writing a simple script to manage them can be a real labor-saver.