Visit our archive

Saving images from Flash is something that has been around for a while, thanks to the JPGEncoder and PNGEncoder in Mike Chamber’s as3corelib code library. We have been doing this for years, it is nothing new with Flash / ActionScript 3. Just the same, it never hurts to share some code and help someone out that may not have done this before or would like to have a utility class to handle the work for them.

So why would you ever need to save an image from Flash to a server? Why not just get the user to download the image? Well, you can do that too! But in this tutorial, we are going to focus on saving a JPG and/or PNG file to a server from our Flash movie. The methods shown here can prove quite useful when it comes to users wanting to share personalized images from their experience on your site.

To get you started we will introduce the classes being used, and then we will get into our utility class that you are free to use/modify to your liking. As mentioned above, the main two classes that we are going to rely on here are the JPGEncoder and the PNGEncoder, they can be downloaded as part of the as3corelib from GitHub (it used to be on a Google Code SVN but recently moved to GitHub, so update your links).

As always, we are going to copy the entire library into our application so that we never have to worry about a version conflict if the library is ever updated. Now go in and create a new Flash movie and draw some random stuff on the stage so that it is not just white because we are going to be saving an image of your stage to your server.

Now that you have some content on the stage, either jump into your document class or go to the ActionScript window in the Flash IDE. First, we are going to write the code to save a JPG file to the server. Take a look at the code below, we will explain what is happening after.

var SERVICE_PATH:String = "serverpath/saveimage.php";

// create a BitmapData object and draw the stage to it
var bmpd:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
bmpd.draw(stage);

// set the save quality of the JPG (0-100)
var saveQuality:Number = 80;

// create an instace of the JPGEncoder
var jpgEncoder:JPGEncoder = new JPGEncoder(saveQuality);

// use the JPGEncoder to generate a ByteArray from the stage BitmapData object
var imageFile:ByteArray = jpgEncoder.encode(image);
// create a filename 
var imageFileName:String = "testjpg.jpg";

// create a URL loader to send the data to the server
var loader:URLLoader = new URLLoader();

var url:String = SERVICE_PATH + "?name=" + imageFileName;

var req:URLRequest = new URLRequest(url);

// make sure the server knows it is getting an image
req.requestHeaders =  new Array(new URLRequestHeader("Content-Type", "image/jpeg"));

loader.dataFormat = URLLoaderDataFormat.BINARY;

req.contentType = "image/jpeg";

req.method = URLRequestMethod.POST;

req.data = imageFile;

// send the file			
loader.load(req);

With that AS3 code, you are able to take any BitmapData object, encode it and send it to a PHP script to handle the actual saving (or displaying) of the image. The code creates the BitmapData object and draws and image of the stage to the object. We then create an instance of the encoder and set the quality we would like to save at. The instance of the encoder is used to convert the BitmapData information into a ByteArray that can be sent to the server. Finally, we create a URLLoader object and a URLRequest. We need to set some variables here so that the server can recognize the information we are sending it, nothing big just contentType for the header of the request and we assign the ByteArray to the data property of the URLRequest. Finally, we “load” the request.

Now, where did that go? If you notice, there is a capitalized variable there, SERVICE_PATH, that we set at the top of our file. This variable is a constant that holds the location of the php file that we are sending this information to for processing. You should change that variable to point to where your PHP file is going to live.

Speaking of PHP, we haven’t built that file yet. So we are going to have to do that next in order for this flash movie to actually do something other than spit out io errors.

The PHP code is quite simple to save a file. It will check to make sure that the correct data has been set from the URLRequest, write a file and spit out some JSON results. Lets have a look:

 "true", "file" => $fileName );
	echo json_encode($arr);

}  else {

	$arr = array ( "success" => "false", "error" => "Header data set incorrectly" );
	echo json_encode($arr);
}
?>

If you are unfamiliar with PHP, this may be gibberish to you, but thats okay. The basic things to note are that it checks to see if the information is set for both a filename and the actual file data. The file data is sent as $GLOBALS["HTTP_RAW_POST_DATA"], and we sent the filename in a GET variable through the ActionScript code. If the data is not present, the script with spit out a little JSON object explaining the issue and setting success to false. This can be used later by your Flash application to verify a response from the server when saving the file.

Once the data is verified, we assign those two properties to variables, and create the file using the filename and file content. The script then prints out a little bit of JSON to let you know that the image was successfully created and what filename was used.

We specify the file name in the script because often, you might want to ensure that the user has created a unique image, so you would most likely prepend a timestamp to the filename. The printed JSON can then be ready by your Flash movie and you can do as you wish (share the image, display it, etc). Below are some additions that can be made to the filename in order to ensure that it is safe and unique.

// make sure the file is safe to save on the server
function sanitize($string, $force_lowercase = true, $anal = false) {
    $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
                   "}", "\", "|", ";", ":", """, "'", "‘", "’", "“", "”", "–", "—",
                   "—", "–", ",", "<", ".", ">", "/", "?");
    $clean = trim(str_replace($strip, "", strip_tags($string)));
    $clean = preg_replace('/s+/', "-", $clean);
    $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
    return ($force_lowercase) ?
        (function_exists('mb_strtolower')) ?
            mb_strtolower($clean, 'UTF-8') :
            strtolower($clean) :
        $clean;
}

then you are able to go back to the original code and replace

$fileName = $_GET['name'];

with

// get a timestamp from the server
$uniqueStamp = date(U);
// prepend the timestamp to the filename and sanitize it
$fileName = sanitize($uniqueStamp . $fileName);

That is all there is to it for saving a JPG from Flash/ActionScript 3 to PHP. Next we will show you a class that we built to make life a little bit easier and the code more modular. You will still need the as3corelib library, the following class just packages up what we did above and adds the ability to save a PNG as well.

package com.cultcreative.utils
{
	import com.adobe.images.JPGEncoder;

	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.utils.ByteArray;
	import com.adobe.images.PNGEncoder;
	import com.adobe.serialization.json.JSON;
	import flash.events.IEventDispatcher;

	public class SaveImage extends EventDispatcher
	{

		public static var SERVICE_PATH:String = "http://www.fbstorage.com/zts/lib/php/saveimage.php";
		public static var PNG_SAVE_SUCCESS:String = "pngSaved";
		public static var JPG_SAVE_SUCCESS:String = "jpgSaved";
		public static var PNG_SAVE_ERROR:String = "pngError";
		public static var JPG_SAVE_ERROR:String = "jpgError";

		public function SaveImage(target:IEventDispatcher = null):void { super(target); }

		public function savePNG(image:BitmapData, filename:String):void
		{
			var imageFile:ByteArray = (PNGEncoder.encode(image));
			var imageFileName:String = filename + ".png";

			var loader:URLLoader = new URLLoader();
			var url:String = SERVICE_PATH + "?name=" + imageFileName;

			var req:URLRequest = new URLRequest(url);
			req.requestHeaders =  new Array(new URLRequestHeader("Content-Type", "image/png"));
			loader.dataFormat = URLLoaderDataFormat.BINARY;
			req.contentType = "image/png";
			req.method = URLRequestMethod.POST;
			req.data = imageFile;
			loader.addEventListener(Event.COMPLETE, onCompletePNG);
			loader.load(req);

		}

		private function onCompletePNG(e:Event):void {

			trace(e.target.data);

			var result:Object = JSON.decode(e.target.data);
			if (result.success == "true") {
				dispatchEvent(new Event(SaveImage.PNG_SAVE_SUCCESS));
			} else {
				dispatchEvent(new Event(SaveImage.PNG_SAVE_ERROR));
			}

		}

		public function saveJPG(image:BitmapData, filename:String, quality:Number = 90):void
		{
			var imageFile:ByteArray = (new JPGEncoder(quality)).encode(image);
			var imageFileName:String = filename + ".jpg";

			var loader:URLLoader = new URLLoader();
			var url:String = SERVICE_PATH + "?name=" + imageFileName;

			var req:URLRequest = new URLRequest(url);
			req.requestHeaders =  new Array(new URLRequestHeader("Content-Type", "image/jpeg"));

			loader.dataFormat = URLLoaderDataFormat.BINARY;
			req.contentType = "image/jpeg";
			req.method = URLRequestMethod.POST;
			req.data = imageFile;
			loader.addEventListener(Event.COMPLETE, onCompleteJPG);
			loader.load(req);

		}

		private function onCompleteJPG(e:Event):void {
			trace(e.target.data);
			var result:Object = JSON.decode(e.target.data);
			if (result.success == "true") {
				dispatchEvent(new Event(SaveImage.JPG_SAVE_SUCCESS));
			} else {
				dispatchEvent(new Event(SaveImage.JPG_SAVE_ERROR));
			}
		}

	}
}

You can then use this code by creating an instance of the SaveImage class and calling the functions. ie:

// add listeners and save a jpg at 80 quality
saveImage.addEventListener(SaveImage.JPG_SAVE_SUCCESS, onSaveSuccess);
saveImage.addEventListener(SaveImage.JPG_SAVE_ERROR, onSaveError);
saveImage.saveJPG(bmpd, "testjpg", 80);

// add listeners and save a png
saveImage.addEventListener(SaveImage.PNG_SAVE_SUCCESS, onSaveSuccess);
saveImage.addEventListener(SaveImage.PNG_SAVE_ERROR, onSaveError);
saveImage.savePNG(bmpd, "testpng");

private function onSaveSuccess(e:Event):void {
	trace("IMAGE SAVED SUCCESSFULLY");
}

private function onSaveError(e:Event):void {
	trace("ERROR SAVING IMAGE");
}

That is just a quick sample, when you save a file you will most likely want a little bit more access to the return data from the class. But, hopefully we were able to shed some light on how to save images from Flash/AS3 to your server.

stumbleupon Saving Images from Flash to a PHP Servershare save 171 16 Saving Images from Flash to a PHP Server
  • Ved Dec 16, 2011

    Life saver! Thanks!

  • Susannah Jan 14, 2012

    These tpocis are so confusing but this helped me get the job done.

  • Manpreet Patil May 17, 2012

    Thanks a lot…. :)

  • giambo Jul 6, 2012

    You’re my hero :)

  • RiaanP Sep 4, 2012

    This is legendary guys, thanks a lot for posting this. It almost worked off the bat for me but I had problems with the JSON class as supplied on Github. I eventually opted for just echoeing strings back to Flash instead of the more elegant JSON.

    Also, I had to escape some characters in your sanitisation function. Notably the backslash and the double quotes on line 5.

  • Hector Oct 28, 2012

    please show all the saveimage.php file, the posted code look no complete please help

  • pip9ball Jan 8, 2013

    saveimage.php code excerpt is not complete. Can you please provide a link to download?

    Thx,

    Pip

  • Trisha Feb 1, 2013

    Excellent tutorial indeed, however, the problem is PHP file. Being an AS developer, i have no knowledge about PHP. That would be great to see the full working PHP.

    Thanks

  • Diego Feb 1, 2013

    Hi, please check the part that creates the php code, its broken i think.

    Thanks

  • Name (Required)

  • Email (Required, but not published)

  • Url (Optional)

  • Comment (Required)

*

*