More on saving images out of Flash

I posted previously on generating a bitmap image of a MovieClip and writing it from Flash to a remote server. However, that previous post was a very early. Now that I’ve implemented the process within an actual project scenario, I’ll follow up here with some revised code that streamlines the task with greater efficiency.

1) Server-side. First thing first: you’ll need a PHP script (or other server-side flavor) to receive binary image data and write it to a file. This revised PHP script is even simpler than before; just save this to a PHP file and place it on a PHP enabled server:

<?php
    $file = $_GET['file'];
    $fp = fopen( $file, 'wb' );
    fwrite( $fp, $GLOBALS[ 'HTTP_RAW_POST_DATA' ] );
    fclose( $fp );
    echo $file;
?>

2) Image encoders. Next, you’ll need the Adobe AS3 corelib which has a collection of classes for JPG and PNG image encoding. Download and extract the corelib’s source library into your main class library. The following image service classes will build upon these image encoders.

3) Image services. Assemble the following three classes into a library. These classes will take care of capturing a DisplayObject’s image and then sending it to your server to be saved. Note: you’ll need to update the ImageCaptureService class member “serverPath” to point to your image service PHP file (from step #1).

3.a) Save this class as: com/gmacwilliam/images/ImageCaptureService.as

package com.gmacwilliam.images
{
    import flash.events.EventDispatcher;
    import flash.events.Event;
    import flash.utils.ByteArray;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.net.URLVariables;

    public class ImageCaptureService extends EventDispatcher
    {
        public static const FILE_WRITE_COMPLETE_EVENT:String = "ImageFileWriteComplete";
        // UPDATE THIS...
        public static var servicePath:String = "http://www.yourServerHere.com/save_image.php";

        public function ImageCaptureService():void
        {
            super();
        }

        /* write
         * @desc: Writes image data to file.
         * @param: image data byte array.
         * @param: path/name of file to write.
         */

        protected function write(img:ByteArray, filename:String):void
        {
            // configure data to send
            var req:URLRequest = new URLRequest(ImageCaptureService.servicePath +"?file="+ filename);
            req.contentType = "application/octet-stream";
            req.method = URLRequestMethod.POST;
            req.data = img;

            // send data to file service
            var write:URLLoader = new URLLoader();
            write.addEventListener(Event.COMPLETE, this.onWriteComplete);
            write.load(req);
        }

        private function onWriteComplete(evt:Event):void
        {
            // cleanup write operation
            var write:URLLoader = evt.target as URLLoader;
            write.removeEventListener(Event.COMPLETE, this.onWriteComplete);
            dispatchEvent(new Event(ImageCaptureService.FILE_WRITE_COMPLETE_EVENT));
        }
    }
}

3.b) Save this class as: com/gmacwilliam/images/JPGCapture.as

package com.gmacwilliam.images
{
    import flash.display.DisplayObject;
    import flash.display.BitmapData;
    import com.adobe.images.JPGEncoder;

    public final class JPGCapture extends ImageCaptureService
    {
        public function JPGCapture(clip:DisplayObject, filePath:String="", quality:int=50):void
        {
            super();
            var jpg:JPGEncoder = new JPGEncoder(quality);
            var bmp:BitmapData = new BitmapData(clip.width, clip.height, false, 0xFFFFFF);
            bmp.draw(clip);
            write(jpg.encode(bmp), filePath);
        }
    }
}

3.c) Save this class as: com/gmacwilliam/images/PNGCapture.as

package com.gmacwilliam.images
{
    import flash.display.DisplayObject;
    import flash.display.BitmapData;
    import com.adobe.images.PNGEncoder;

    public final class PNGCapture extends ImageCaptureService
    {
        public function PNGCapture(clip:DisplayObject, filePath:String=""):void
        {
            super();
            var bmp:BitmapData = new BitmapData(clip.width, clip.height, true, 0x00000000);
            bmp.draw(clip);
            write(PNGEncoder.encode(bmp), filePath);
        }
    }
}

4) Instantiation. These services are extremely easy to use… Just instantiate them with a reference to a DisplayObject and a server path at which to write the image file. Also, the JPGCapture class will accept an optional quality setting (a number between 0 and 100).

var saveJPG:JPGCapture = new JPGCapture(myDisplayObject, "images/flashimg.jpg", 85);
var savePNG:PNGCapture = new PNGCapture(myDisplayObject, "images/flashimg.png");

You can listen to boh object for an “ImageCaptureService.FILE_WRITE_COMPLETE_EVENT” event to know when the image data has finished getting sent to the server.

While these image services are very similar to the ones in my last post, there has been an important change: they now send both binary and text data to the server in a single server call, rather than breaking the two formats out into seperate calls. This was achieved by dropping the text data (the filename) into GET variables so that POST could be allocated entirely to binary image data.

Advertisements

6 comments so far

  1. HREO on

    thx for u good post
    http://www.4roz.com
    فور روز

  2. Ogawa Ken on

    Nice Job!

    Just a little help with the event.
    Is this right?

    savePNG.addEventListener(ImageCaptureService.FILE_WRITE_COMPLETE_EVENT, onCompleted);
    function onCompleted(event:ImageCaptureService):void{
    trace(“Completed”);
    }

    it gives me an error:
    TypeError: Error #1034: Type Coercion failed: cannot convert flash.events::Event@110fb101 to com.gmacwilliam.images.ImageCaptureService.
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at com.gmacwilliam.images::ImageCaptureService/onWriteComplete()
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at flash.net::URLLoader/onComplete()

    Thank you!

    • bigmac on

      You’ve incorrectly specified the param object type on your event handler. All event handlers must receive an Event object as their sole parameter. In this case, if you were to look at the type of the event target (the object that dispatched the event), you’d see that the event CAME from a ImageCaptureService. However, the input on the handler is still an Event object. So, you need to update your handler as follows:

      function onCompleted(event:Event):void {
      trace(“completed”);
      }

  3. […] answer came from one of my own past blog posts about writing images out of flash. The post covers a script I had written to use the Adobe corelib’s PNG encoder to capture a […]

  4. ratdoghippy on

    can you send the image via email if so how

    • bigmac on

      You’d need to do all of this from your server. Flash would just generate the binary image data which it sends to the server. Once the server receives the data, the server would need to write the image to a file, plug that image into an email template, then send the email off. So, Flash really doesn’t play a role in this process other than getting the ball rolling.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: