Archive for December, 2010

The Importance of Scaling Images on Mobile Devices

When we launched Adobe AIR for Android, I created an application called AIRBench to help us measure the performance of AIR on all the different Android devices out there. Not only did AIRBench tell us which phones run AIR the best, but it also brought to my attention the importance of scaling images before displaying them on mobile devices.

One test we saw consistently fail on Droid devices (only the first Droid — none of the others) was the CameraUI test. The CameraUI test simply lets users take a picture, then places the image on the display list. It’s very simple and straightforward, however we saw numerous failures. After looking into it, we discovered that the issue isn’t actually a bug in AIR, but rather it’s the result of the application running out of memory.

The test uses the Spark Image component to display the image. When the code hands the Image component the file URL of picture that was just taken, two important things happen:

  1. The image is decoded into a bitmap which means it uses much more memory than the compressed JPEG version.
  2. The image is visually scaled down to fit on the screen. I say "visually scaled" because it only looks to be smaller, but the entire uncompressed bitmap is still in memory.

Because the Droid has a pretty high resolution camera (5 megapixels), but a relatively small amount of RAM (256 MB as opposed to the 512 MB of the Droid 2), it’s not hard to get an application to run out of memory by displaying uncompressed bitmaps if there are other applications running at the same time.

Although I’ve never seen this happen on any other device (since most other Android phones that AIR supports have more than 256MB of RAM), it’s still a good idea to really scale your images before displaying them. By "really scale", I mean the following:

  1. Figure out the width and height that gets the image small enough to fit on the screen, but also maintains its aspect ratio.
  2. Draw the data from the Loader to a new BitmapData object and using a Matrix object to actually scale the image down (meaning most of the data is removed).

I did some tests and found that by properly scaling an image before putting it on the display list (in this case, handing it to the Spark Image component), you can easily display images from either the CameraUI or the CameraRoll on the Droid with no issues whatsoever. A little bit of profiling revealed that scaling images properly uses only a few hundred kilobytes as opposed to between 20 and 30 megabytes (depending on the image size).

The sample code below illustrates how to do the following:

  1. Use either the CameraUI (if it’s supported), or a native file browser (for desktop testing) to let the user take a picture or choose an image.
  2. Read the bytes of the image into a ByteArray.
  3. Load the bytes into a Loader.
  4. Figure out the correct scale factor which will allow the image to fit on the screen, but still maintain its aspect ratio.
  5. Create a new BitmapData object with the correct dimensions.
  6. Draw the image into the BitmapData object and scale it down to the correct size.

Ok, enough talk. Here’s the code:

Continue reading…

Playing Games Against Users With Different Devices

One of the things I really love about mobile devices is that they have become very capable gaming platforms — so capable, in fact, that I think they seriously threaten dedicated hand-held gaming platforms like the PSP and Nintendo DS. And since our devices are easily connected, playing games against friends is usually just a matter of jumping on the same local network.

But the problem is fragmentation. Some of my friends have iPhones and some have Android devices which can make it difficult or impossible to play games against each other. But not so with games written with AIR. Last week, I decided to see how hard it would be to add network play to iReverse in order to enable two people to play against either other over a local network no matter what kind of device the two players have (iOS, Android, laptop, etc.). As it turns out, it was less than a day of work. Here’s a demo:

The key to game instances discovering each other on the network and passing data back and forth is RTMFP. The code is extremely simple to write, and no server of any kind is required. I haven’t updated the release versions of iReverse yet (I’ve been on the road a lot lately), but I should have them out before Christmas. In the meantime, you can see how it all works by checking out the code.