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:
- The image is decoded into a bitmap which means it uses much more memory than the compressed JPEG version.
- 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:
- Figure out the width and height that gets the image small enough to fit on the screen, but also maintains its aspect ratio.
- Draw the data from the
Loaderto a new
BitmapDataobject and using a
Matrixobject 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:
- 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.
- Read the bytes of the image into a
- Load the bytes into a
- Figure out the correct scale factor which will allow the image to fit on the screen, but still maintain its aspect ratio.
- Create a new
BitmapDataobject with the correct dimensions.
- Draw the image into the
BitmapDataobject and scale it down to the correct size.
Ok, enough talk. Here’s the code: