JPEG Async Encoder class meets merging multi-BitmapData

I often use PNG/JPEG Encoding in Flash and during my projects I faced some problems with this classes.
The main problem is speed and CPU usage when encoding large BitmapData objects. First I decided to rewrite PNG Encoder class provided by Tinic Uro and optimized by Aral but we cant make it encoding data asynchronous because it is using built in ByteArray compress method to GZIP image data. When encoder calls this method on large data Flash Player completely freezes. It can take up to 15 seconds to compress data. And you can do nothing all this time but waiting. May be there is an alternate way to compress ByteArray but I didnt find any.

So I turned to JPEG Encoder class provided by Adobe. After some research I found a solution for Async Encoding. As far as it was designed for Flex I rewrite the class merging everything in one file. Now it is all in one solution. You can encode BitmapData and ByteArray objects Async listening for Progress and Complete Events or encode data through one method call.
I’ve also added method for merging several BitmapData objects in to one JPEG image. This method is very useful when you need to generate large image but can’t do it because of the Flash built in BitmapData size restrictions.
I’m using this class in my Flickr Mosaic engine to encode result mosaic image. See it in action merging several BitmapData objects into one JPEG file.

Class itself could be seen in my Google Code repository within Flickr Mosaic sources.

See some usage examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import ru.inspirit.utils.JPGEncoder;
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.utils.ByteArray;
 
var bmp1:BitmapData = new BitmapData(640, 400, false, 0xFF0000);
var bmp2:BitmapData = new BitmapData(640, 400, false, 0x00FF00);
var bmp3:BitmapData = new BitmapData(640, 400, false, 0x0000FF);
var bmp4:BitmapData = new BitmapData(640, 400, false, 0xFFFF00);
 
var je:JPGEncoder = new JPGEncoder(90);
je.addEventListener(ProgressEvent.PROGRESS, onEncodingProgress);
je.addEventListener(Event.COMPLETE, onEncodingComplete);
 
// Encoding several BitmapData objects into one image
// You should provide 'square' of Bitmaps in 2 dimensional array
je.encodeMultiToOne([
				[bmp1, bmp2],
				[bmp3, bmp4]
				]);
 
// Simple encode
/*
var ImageByteArray:ByteArray = je.encode(bmp1); 
*/
 
// Async encode
// You should provide listeners (see above) to handle data ready event
/*
je.encodeAsync(bmp1);
*/
 
private function onEncodingComplete(e:Event):void 
{
	// Async Encoding Complete
	var ImageByteArray:ByteArray = je.ImageData;
}
 
private function onEncodingProgress(e:ProgressEvent):void 
{
	trace('ENCODING PROGRESS: ' + Math.round(e.bytesLoaded/e.bytesTotal * 100) + '%');
}

10 Responses to “JPEG Async Encoder class meets merging multi-BitmapData”


  1. 1 alex

    great! thanks! I got similar headache before. now it seems that i have solution…

  2. 2 Guti

    Also I have seen your Random class in Google Code (http://code.google.com/p/in-spirit/source/browse/trunk/projects/FlickrMosaic/src/ru/inspirit/utils/Random.as).
    Maybe my fastRandom implementation, which is about 3 times faster than the built-in could help.
    Reach it at my blog http://guti.bitacoras.com/index.php?entry=entry071211-225114 or translated to english as http://translate.google.com/translate?u=http://guti.bitacoras.com/index.php?entry=entry071211-225114&langpair=es%7Cen&hl=es

  3. 3 squirtgun

    Is there anything like this for the PNG encoder? Also, there is some great work being done over at http://www.bytearray.org/?p=775 to optimize the JPEG encoder using flash player 10 vector class instead of normal arrays. The speed increase is huge. Both of these combined would be great!

  4. 4 Eugene

    @squirtgun this encoder is specialy designed to work in Flash 9 and higher and the one from bytearray is for Flash 10 only. So you decide wich one you need.

  5. 5 Dan

    Very nice script. I am using this to try and merge a bunch of different bitmapdata objects. When the total merged size is ~8000pixels it works fine, but as soon as I step up to 9000 it runs fast and stuff but the resulting merged image is just white with random black spaces, nothing at all like what i receive at 8000px. Any idea why this is happening and/or if it can be fixed/worked around? I think AS has a ceiling of like 8kx8k pixels but im trying this at 8kx100px and 9kx100px – any ideas or is this just a limit that can’t be worked around?

    Thanks!
    Dan

  6. 6 kode80

    Nice one Eugene this is exactly what I was looking for!

  7. 7 Nicolas Markovic

    Thank you Eugene !!!! you rock !

  8. 8 fater

    The JPGEncoder is buggy, because if i want to post/save jpgstream, the image file is corrupt (async and normal encode too)

    When i use com.adobe.images.JPGEncoder it’s fine.

    as3 post
    var header:URLRequestHeader = new URLRequestHeader (“Content-type”, “application/octet-stream”);
    var jpgURLRequest:URLRequest = new URLRequest (jpgSaveURL);
    jpgURLRequest.requestHeaders.push(header);
    jpgURLRequest.method = URLRequestMethod.POST;
    jpgURLRequest.data = jpgStream;

    var jpgURLLoader:URLLoader = new URLLoader();
    jpgURLLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
    jpgURLLoader.load( jpgURLRequest );

    php
    $img = $GLOBALS["HTTP_RAW_POST_DATA"];
    $handle = fopen($fullFilePath,”w”);
    fwrite($handle,$img);
    fclose($handle);

  1. 1 Merging BitmapData objects to single JPEG file | astatic notes
  2. 2 Oh My Bosh! Design Your Very Own Chris Bosh Paper-Robo in Augmented Reality – Adding Interactivity to Your AR Apps - Sunil’s Blog

Leave a Reply