by Klas Jersevi

Using the fast asynchronous Alchemy JPEG encoder in Flash

If you want to encode JPEG images in AS3 there are a number of encoders to use and obviously there is one that is better than all the rest. Mateusz Małczak has made an excellent JPEG encoder based on the libjpeg C-library compiled into Actionscript using Adobe Alchemy. It not only produces small JPEGs with high quality really fast, but it’s also asyncronous meaning that it doesn’t lock up your application while encoding, like many of the other encoders do. This way you can also monitor the progress of the encoding process while encoding. The disadvantage is that you need an extra click from the user to save the file when the process is complete. This is due to limitations in the security model in the Flash Player, which only allow file saving exactly when you make a click, which doesn’t work with asynchronous scripts. However, this isn’t a big problem if you make a logic design.

Step 1

Start by making a new Flash File (Actionscript 3.0) and save it in a folder of your choice.

Step 2

Download the jpegencoder.swc from segfaultlabs. Just click on the jpegencoder.swc in the folder /libs/.

UPDATE: The library has been updated and is now faster and not leaking memory. Also, you can download it directly on segfaultlabs without going into the source.

Save the file to the folder where you have your .fla file.

Step 3

Open the publish settings in flash and select the flash tab.

To get the SWC library working when you publish your swf you need to do a little magic trick, otherwise you will get the error ReferenceError: Error #1065: Variable MainTimeline is not defined when publishing or testing the SWF. To deal with this error we need to include the required things to use SWC libraries in the SWF.

Check the Export SWC checkbox in the publish settings.

Note: this setting will also produce another SWC file with the same name as your SWF when publishing. This file is not needed when distributing the SWF to the web or similar and can be deleted.

Step 4

Click on Actionscript settings.

Go to the Library path section. Click on Browse to SWC file and locate the jpegencoder.swc and include it.

Click OK to save your library settings.

Voilà! Now you are ready to use the Alchemy JPEG Encoder in your code!

Initializing the library

To initialize the Alchemy JPEG library use the following lines in your actionscript:

import cmodule.jpegencoder.CLibInit;   
/// init alchemy object
var jpeginit:CLibInit = new CLibInit(); // get library
var jpeglib:Object = jpeginit.init(); // initialize library exported class to an object

Starting the encoder

To use the encoder simply call the jpeglib.encodeAsync function and use it with a ByteArray. There is also a non-asyncronous function you can use which is a little bit faster. Even if its faster I recommend using the asynchronous function, since it doesn’t lock up your application while encoding.

// Refer to your own BitmapData object
var imgBitmap:BitmapData = someBitmapDataYouHaveAlreadyCreated;
// Prepare Alchemy objects
var imgData:ByteArray = imgBitmap.getPixels(imgBitmap.rect);;
var imgEncoded:ByteArray = new ByteArray();
imgData.position = 0;
// Function called when completed
var encodeComplete:Function = function() {
    trace("Encoding complete");
// Start JPEG encoder
trace("Start encoding");
var jpegQuality:Number = 80;
jpeglib.encodeAsync(encodeComplete, imgData, imgEncoded, imgBitmap.width, imgBitmap.height, jpegQuality);

Monitor progress

To see the progress of the encoding you need to set up a function that monitors the position of the ByteArray reader in the encoder. This is done by simply using a setInterval function during the encoding. Don’t forget to clear the interval when the encoding is complete.

// Encoding progress monitor function
var encodeProgress:Function = function() {
	// Listen to the position of the data reader
	trace("Encoding progress: " + Math.round(imgData.position/imgData.length*100) + "%");
// Start monitoring the progress of the encoding
var progressMonitor:Number = setInterval(encodeProgress, 20);
// Encoding progress complete function
var encodeComplete:Function = function() {
	trace("Encoding complete");
	// Stop monitoring the progress

Full example

Here is a full example of encoding some graphics into a JPEG while monitoring the progress and then saving it onto the user’s hard drive.

« »