Last Instinct

Using the fast asynchronous Alchemy JPEG encoder in Flash

by on Apr.14, 2010, under Graphics and effects

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
	clearInterval(progressMonitor);
};

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.

:, , , ,

20 Comments for this entry

  • James

    Great tutorial – thanks… though I am having problems getting the complete function to fire. I can get around this by firing it myself when the progress interval notices it’s at 100%.

    • Klas Lundberg

      I had some problems with that as well if I remember correctly. I think the solution was to make sure that the function is assigned to a variable and make sure the variable is available where you call the encodeAsync function.

      var myCallBack:Function = function(){ /* whatever */ };

      I hope this helps. Otherwise, look into the example fla file.

  • Robol

    Can this packed class be used In an AIR application?
    I am trying to do this, but I have not success yet :(

  • Robol

    I mean, Can this be used class file (as) not in a fla file.

  • Steven

    This is great, but I am having a problem. It works great the first time, but if i try to encode another image it gives me this error:

    “RangeError: Error #1506: The specified range is invalid.
    at cmodule.jpegencoder::FSM_imalloc$/start()
    at cmodule.jpegencoder::FSM_pubrealloc/work()
    at cmodule.jpegencoder::CRunner/work()
    at ()
    at flash.utils::Timer/_timerDispatch()
    at flash.utils::Timer/tick()”

    not sure whats up with that.
    Anybody know anything about this?

    oh and @Robol, it can be used in a AIR application and in a class because that is what I am doing

    • Klas Lundberg

      Great that you tried it with AIR! I guess the encoder really comes useful there.

      I found the solution (or the cause really) for your timer-problem. It happens when the imgData:ByteArray is empty (or null). Make sure that you have data in the ByteArray you want to encode, and hopefully the problem goes away. Let me know how it works out for you. =)

  • Johanna

    Om du gillar både designen och färgsättningen måste det ju vara fel någon annanstans? =) Eller kanske inte, men kom gärna med input om du tycker jag borde kika på att ändra, har stirrat mig blind på den där sidan nu. Och det tekniska är ju inte mitt forte alls…
    Men kul att höra att jag inte är helt fel ute i fråga om smak iaf!

  • Ryan

    Is there a way to have the encoded jpeg in 300 dpi? Thanks for any help.

  • Johanna

    Jag håller med dig, både vad gäller vatten och windows 7. Fick så vansinnesont i huvudet i söndags, trodde på allvar att hjärnan var på väg ut genom öronen. Så fick bli inställd kväll, och borde nog kolla upp vad som strular med mitt huvud, lite för ofta för att vara ok. Kul i onsdags? Vår aw varade i 6,5 timmar, märkligt nog hade jag inte ont i huvudet dagen efter. Kanske dricker för lite alkohol?

  • Aaron Hardy

    Steven, do something like this:

    if (!lib)
    {
    var libInit:CLibInit = new cmodule.jpegencoder.CLibInit();
    lib = libInit.init();
    }

    so the library only gets initialized once. It’s when it gets initialized more than once that it chokes.

  • Mike

    absolutely fabulous! great explanation; worked from the start for me.
    do you by any chance know of a php script I could locate that would allow me to send the encoded jpeg to a particular web host and/or to a particular email address?
    thanks again!

  • Mike

    I used Aaron’s script above but changed the particulars to match your code if anyone newer to AS3 than I needs it broken down further:

    import cmodule.jpegencoder.CLibInit;
    var jpeglib:Object;
    var jpeginit:CLibInit = new CLibInit();
    if (! jpeglib) {
    jpeglib=jpeginit.init();
    }

    seems to be working fine…

  • Mike

    I have searched far and wide and can’t find any place that leads to a good php script for sending encoded jpegs to an email address or to a server. anyone else have any luck out there?
    thanks…

    • Klas Lundberg

      I have actually have a nice php function for mailing. It’s based on something I found a couple of years ago and then modified to support utf8, html and attachments. I’ll put up a post about it this weekend.

  • Mike

    exxxxxcellent!!!!!
    ‘bated breath…
    thanks, Klas!

  • Mike

    visited your website. really cool!

  • Mike

    decided to use a simple php to send link to image on server. thanks anyway…

  • Aaron Hardy

    Anyone have a swc with with a jpegencoder that doesn’t leak memory like a 90-year-old? If so, I could really go for one. Feel free to send it over to aaronius9er at that one email service that starts with a g and ends in mail. Gracias!

1 Trackback or Pingback for this entry

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...