Deconstruction and reconstruction of a ByteArray

December 2nd, 2008 by Unknown Morphician

Many times you may come up with tasks that seem pretty straight forward but involve a bit of researching. In a recent project, I needed to find a way pass a dynamically generated image from one flex application (swf) to another. My senior developer suggested that I pass the ByteArray data of the image via local connection. But there is one small problem. There is a size limit for local connection, 40K. So the original data needs to be cut into smaller pieces, sent via LC and then reconstructed into the complete image data. (Note: LC = Local Connection)

I would suggest creating a unique local connection name between your applications (swfs). Check out Joey’s blog on this task - unique local connection names. In this project summary, I will not reference a unique connection name.

Here is the set up… In the first swf, I’ve set up a LC object (transSendLC) and an image object (imgOriginal). The second app (swf) somewhat mimics the first app (swf). The only difference is that I created a custom class, inheriting from LC. I’ve added a method for receiving the ByteArray and a Bitmap object. The bitmap object can be used to bind to the Image source. Note: You don’t need to create a custom class. I found that it made sense for my particular flex project.

Within my first app (swf), I have supplied an image (imgOriginal). Now with I need to chop up the data and send it to the second app (swf).


Example Code:
...
var width:Number = imgOriginal.width
var height:Number = imgOriginal.height;
var bytes:ByteArray =
   imgOriginal.bitmapData.getPixels(new Rectangle(0, 0, width, height))

var tempByteArray:ByteArray;

// limit byteArray to 40K - localconnection limit
var byteLimit:uint = uint(40000);

if(bytes.length > byteLimit){

   var currentSize:uint = byteLimit;
   var position:uint = 0;
   var totalSize:uint = 0;

   while(totalSize < bytes.length){
      tempByteArray = new ByteArray();
      tempByteArray.length = currentSize;

      // Write bytes from position to current size
      tempByteArray.writeBytes(bytes, position, currentSize);

      //send ByteArray chunk
      transSendLC.send(uniqueLCName, "sendSnapShot",
              tempByteArray, bytes.length, width, height);

      //get current total and get next position
      totalSize = totalSize + tempByteArray.length;
      position = totalSize;

      //set current size based on limit
      currentSize = bytes.length - totalSize;
      if(currentSize >  byteLimit){
         currentSize = byteLimit;
      }
  }
  else{
     //less than limit - send Byte Array
     bytes.writeBytes(tempByteArray, 0, uint(bytes.length));
     imgLCSend.send(uniqueLCName, "sendByteArrayData",
                 tempByteArray, bytes.length, width, height);
  }
...

Next in my second app (swf), I need to build the sendCopy method within my custom object (inheriting from LC). Note: It is assumed that you have logic to connect the shared local connection name, a Bitmap and a ByteArray object in your custom class.


Example Code:
public function sendByteArrayData(bytes:Object, bytesLength:Number,
                              width:Number, height:Number):void {
   var byteArray:ByteArray = bytes as ByteArray;

   //New ByteArray size
   if(byteArraySnapShot == null){
      byteArraySnapShot = new ByteArray();
      byteArraySnapShot.length = bytesLength;
      byteArraySnapShot.position = 0;
   }

   //Write byte array
   byteArraySnapShot.writeBytes(byteArray);

   //Once length/size is filled based on total bytes create bitmap
   if(byteArraySnapShot.bytesAvailable == 0){
      var bitmapDataSnapShot:BitmapData = new BitmapData(width, height);
      byteArraySnapShot.position = 0;
      bitmapDataSnapShot.setPixels(new Rectangle(0, 0, width, height),
            byteArraySnapShot);

      var bitmapSnapShot:Bitmap = new Bitmap(bitmapDataSnapShot);
      snapShotImg = bitmapSnapShot;

      byteArraySnapShot = null;
   }

}


There perhaps a few ways to achieve the functionality. My purpose here is to show the process of reading and writing ByteArray in a real world application set.

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • Fark
  • LinkedIn
  • Live
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Yahoo! Bookmarks
  • RSS
  • email

8 Responses to “Deconstruction and reconstruction of a ByteArray”

  1. GMalartre says:

    Another possible way :

    You could store the data in a LocalSharedObject without splitting it and listen for a change in the other applications.

    Of course it mean some different handling, but in my case the LocalSharedObject is already a prerequist.

  2. ryan says:

    what are the security/domain limitations of a local shared object? i thought that there may be some restriction?

    I had to send bitmapdata from an as2 module to an as3 app and hit the 40k limit let alone the headache that the AV1Movie ‘black box’ class causes (i’m actually glad as2 gets almost zero access to as3)…

    in the end i decided to move the bitmap editing logic from a hidious as2 module into my app and spent the whole night refactoring sloppy code…

    @GMalartre: i am going to try out the shared object hack and see if i can actually build an api around it… it’s bound to come in handy one of these days…

    @Dennis i really like what you did with that bytearray… certainly something to consider using…

    (you might find this funny… that nasty as2 module had a whopping 938 lines of procedural script in a single frame, i almost lost my mind…)

  3. Sam Ahn says:

    When I gave Dennis this task, I did try using SO’s for a little bit. It’s been a while so I’m shooting from the hip, but I remember when I was looking into detecting changes in an SO property it just didn’t feel right. I think it is possible, but you might have to continually check for changes to the property manually which means continualy reading the SO. If there is an elegant solution to using SO’s that’d be good particularly for very large data. Otherwise Dennis’ solution works great … I like how it feels lke asynchronous file i/o. If you couldn’t tell, I’m all about feelings.

  4. Avi Ku says:

    Dennis thanks.
    Is there a working copy of this

  5. Adam says:

    Hi Dennis thank you for this example I was very excited to see that I can send images over netconnection, Ive waited a long time for this. I created a mock up example that in this case doesnt use netconnection just to keep it simple and quicker for testing (though I did setup netconnection and it works, but having same issue with it too).

    What i am attempting to do is to take an animation or in this case video and instead of
    of sending only one image, to send a series of images. in this scenraio I take a
    snapshot of a netstream every few seconds and send to another function in teh same fla
    another function where the pieces are put back together, turned back into a bitmap
    and then display it in a movieclip next to the video object on the stage. i am able
    to do this with one frame successfully, however everytime another snapshot is taken,
    instead of it being the current image played in the video, somehow, it is the same image
    as the first snapshot. The problem escapes me. Any help would be greatly appreaciated.

    on the stage i have a video playing a netstream named vid and the target movieclip named mc2
    positioned right next to it, and a button i click which triggers the myFunction function.

    var w=214;
    var h=214;
    function myFunction():void {
    var bmpData=new BitmapData(w,h,true);
    bmpData.draw(vid);
    var bytes:ByteArray=bmpData.getPixels(new Rectangle(0,0,w,h));
    var tempByteArray:ByteArray;
    var byteLimit:uint=uint(40000);
    if (bytes.length>byteLimit) {
    var currentSize:uint=byteLimit;
    var position:uint=0;
    var totalSize:uint=0;
    while (totalSize byteLimit) {
    currentSize=byteLimit;
    }
    }
    }
    }
    function myLoad(bytes,bytesLength,w,h) {
    var byteArray:ByteArray=bytes as ByteArray;
    byteArraySnapShot = new ByteArray();
    byteArraySnapShot.length=bytesLength;
    byteArraySnapShot.position=0;
    byteArraySnapShot.writeBytes(byteArray);
    if (byteArraySnapShot.bytesAvailable==0) {
    var bitmapDataSnapShot:BitmapData=new BitmapData(w,h);
    byteArraySnapShot.position=0;
    bitmapDataSnapShot.setPixels(new Rectangle(0, 0, w, h),byteArraySnapShot);
    var bitmapSnapShot:Bitmap=new Bitmap(bitmapDataSnapShot);
    var snapShotImg=bitmapSnapShot;
    mc2.addChild(bitmapSnapShot);
    }
    }

  6. Adam says:

    Whoops, looks like something happened to the function text when i posed. I put the code in a pastebin here: http://flash.pastebin.ca/1340937

  7. Adam says:

    sorry sorry sorry… previous code was missing something. updated here: http://pastebin.sekati.com/?id=Anonymous@ad361-d3bbb812-t

  8. Adam says:

    Got it working: http://pastebin.sekati.com/?id=Anonymous@b5981-d3bbb812-t&start=0

    just add a video to the stage (name it vid) and play a netstream file (or live!) and add a movieclip next to it (name it mc2)

    create some kind of interval sequence to trigger the myFunction function and thats that.

    once you see it works swap out myLoad function call for a localconnection call. take the myLoad function and put it in the target localconnection file.

    Thanks again for this the possibilities are endless.

Leave a Reply