Tutorials Category

  • Save MovieClip as PNG Example

    A couple of guys on Twitter asked me if I would write-up how I generate PNG files from MovieClips in my SWF, at run-time. So I put this example together and am sharing it here.

    We use this technique in our virtual world WebbliWorld to save a PNG version of the users avatars after they have customised them. But there are all kinds of other reasons you may need this. My example includes two methods: Saving the PNG locally using the local file system, and Saving the PNG to a web server using AMFPHP.

    This technique requires Flash Player 10 and the Adobe AS3 Core Lib.

    Here’s a very simple example (included in the zip download below):

    [swfobj src=”http://sandbox.photonstorm.com/saveAsPNG/SaveAsPNG.swf” width=”640″ height=”480″]

    Essentially it all boils down to this:

    1) When you are ready to save your image, create a Bitmap version of your MovieClip.

    [as]
    private function getMovieClipAsBitmap():Bitmap
    {
    var bounds:Rectangle = theMovieClip.getBounds(theMovieClip);

    //    The * 2 is because we’re scaling the clip up by a factor of two, to result in a larger PNG
    //    If you don’t need this, remove it and comment out the m.scale call below
    var theBitmap:Bitmap = new Bitmap(new BitmapData(bounds.width * 2, bounds.height * 2, true, 0x0));

    var m:Matrix = new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y);

    //    Simply scale the matrix to make a bigger PNG. Here we are doubling it. Comment this out if you don’t need it.
    m.scale(2, 2);

    //    Need to crop the PNG to a given size? Pass it a Rectangle as the 5th parameter to draw()
    //var r:Rectangle = new Rectangle(0, 0, 50, 40);

    theBitmap.bitmapData.draw(theMovieClip, m, null, null, null, true);

    return theBitmap;
    }
    [/as]

    2) Convert this Bitmap to a ByteArray.

    [as]
    private function getMovieClipAsByteArrayPNG():ByteArray
    {
    var data:Bitmap = getMovieClipAsBitmap();

    var ba:ByteArray = PNGEncoder.encode(data.bitmapData);

    return ba;
    }
    [/as]

    3) Send this ByteArray to either the local filesystem, or AMFPHP.

    [as]
    //    Uses FileReference to save the PNG locally to the hard drive (see “saveToServer” for an alternative)
    private function saveLocalPNG(event:MouseEvent):void
    {
    var ba:ByteArray = getMovieClipAsByteArrayPNG();

    file.save(ba, “BirdyNamNam.png”);
    }
    [/as]

    Complete source code is included in the zip file including an AMFPHP PHP script for saving on a web server.

    Hope someone finds this useful.

    Download the Soure Code zip.

  • Creating MovieClips dynamically at run-time using the Linkage Class

    linkageI found myself needing to create a MovieClip dynamically at run-time. But all I had was a string representation of its Class, as set in the Linkage properties for the Symbol. In my situation the string had been stored in an xml file. Now you could use a standard switch/case block to do this, checking the string and creating a new MovieClip as required. But in this case there were hundreds of possible things it could have been, and it seemed a very “hacky” way to do it.

    So how do you go about creating an actual display object from just the Linkage Class value? Thankfully it’s pretty easy, and this new bit of code now sits happily in my “everyday functions” collection!

    Edit: Updated to be a little more robust, and removed an un-needed cast:

    [as]
    public function createMovieClipFromLinkageValue(linkageValue:String):MovieClip
    {
    try
    {
    var libraryReference:Class = getDefinitionByName(linkageValue) as Class;
    }
    catch (error:ReferenceError)
    {
    trace(error);
    }

    if (libraryReference)
    {
    return new libraryReference();
    }

    return new MovieClip;
    }

    var newClip:MovieClip = createMovieClipFromLinkageValue(“playerFishMC”);
    [/as]

    Make sure you have imported flash.utils.getDefinitionByName.

    Simply pass this function the Linkage value as entered in the IDE, and it’ll spit a MovieClip back at you (providing it was a MovieClip in the first place). I’m sure you can see how to extend it to return a Sprite instead, should you require that.