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.
Donny
April 14, 2010 — 08:51
Thanks !!
James
April 16, 2010 — 04:28
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
April 16, 2010 — 11:56
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
April 18, 2010 — 09:00
Can this packed class be used In an AIR application?
I am trying to do this, but I have not success yet
Robol
April 18, 2010 — 09:25
I mean, Can this be used class file (as) not in a fla file.
Steven
April 19, 2010 — 18:42
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
April 19, 2010 — 23:35
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
April 21, 2010 — 10:44
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
April 28, 2010 — 06:53
Is there a way to have the encoded jpeg in 300 dpi? Thanks for any help.
Johanna
May 14, 2010 — 21:37
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
June 1, 2010 — 21:28
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.
Klas Lundberg
June 2, 2010 — 01:21
Thanks for the tip Aaron!
Mike
June 8, 2010 — 16:45
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
June 8, 2010 — 17:08
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
June 11, 2010 — 05:24
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
June 11, 2010 — 09:02
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
June 12, 2010 — 17:51
exxxxxcellent!!!!!
‘bated breath…
thanks, Klas!
Mike
June 14, 2010 — 23:14
visited your website. really cool!
Mike
June 18, 2010 — 07:20
decided to use a simple php to send link to image on server. thanks anyway…
Aaron Hardy
June 29, 2010 — 23:22
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!