Android App: Image Histogram Generator
Thursday, October 6th, 2011It’s time for another new Android app! My first photography app was for astrophotography. This time I wrote one that generates histograms of pretty much any sized jpeg, gif. png, or bmp you can throw at it.
You can see the app here on the Android Marketplace.
Here is the promo video I made for it:
http://www.youtube.com/watch?v=UCrZBGLw7I8
So let’s talk about how it was made. It took probably around a week and a half of full-time effort (pretty expensive in “developer dollars”). The app used a few new techniques and a lot of math I wasn’t unfamiliar with, which was part of the time consuming nature of the app.
Many of the nights I was awake till around 4am, but that was partly due to being one of those passionate hobby style projects. The first thing I thought to myself after thinking up the idea was “Oh, that would be COOL… and I could write it like this…” One of the best “empowered programmer” feelings we can get.
How the main screen works:
This was the easier of the two activities to write. It basically takes some simple user input and passes a complete path and filename to the next activity. The more difficult thing was the code that manages the directory browsing. The Android method for dealing with lists is much too complex for something that should be simple. In the Windows/C#/VB world a list control can be easily managed, but in android they throw in things like adapters and needing things set in a specific way making it difficult to use and understand. Besides managing the list, there is some use of the File object that is key in dealing with the file system.
The histogram screen:
This activity was much more complex and went throw 3 iterations. First I just tried to load and process the image without care for user experience (meaning the app will hold up the UI thread while it is processing). I also wrote the processing code to go through the entire list with getPixel(), which is the slowest method of reading bitmap data available.
All of the graphical aspects were stored in a second class that extends a View. The biggest time consumer to me was the math I was drawing a blank at for displaying the histogram in a given section of the screen. Why would graphWidth * histogramData[i] / MaximumValue be such a difficult thing for me to figure out I’ll never know… The view also handles touch events as I designed the histograms to expand to full-screen landscape when pressed. That required some code that checks where the finger presses and seeing if it was inside any of the small histograms (when the 4 graphs are on one screen).
After I had the program working, I focused my attention on making it faster and responsive to user-input at all times. The first thing I found out when trying the app on my development phones was that the app was hitting a memory usage limit with some images that didn’t happen in the emulator. I went back to the image loading and processing code and managed to do some pre-scaling functionality. It uses the BitmapFactory option like inSampleSize with some calculations to scale before loading the pixel data.
Besides the loading step, I changed the pixel access code to use Bitmap.getPixels(), which was probably part of my memory use issue. This is a lot faster than using the getPixel() function for every single pixel in an image.
The final bit (confusing) step was getting asynchronous loading and processing to avoid holding up the UI thread. I had used cut-and-dry threading with Java/Android before, but I wanted to get a shot at using a class from extending AsyncTask. It took quite a while to figure out. Basically move everything you can into the task class and avoid touching anything that is part of the UI thread in doInBackground(). I also made a goofy mistake of calling doInBackground() instead of execute(), wondering for a while why the task didn’t work properly…
In the app I have an XML layout for the loading “screen” that is basically two progress controls and a button to call the AsyncTask cancel. When processing if finished, the UI thread function in the AsyncTask called onPostExecute() gets called, allowing me to programmatically flip out the layout with a simple code one that gets an instance of custom view class I made.
That’s about it! I hope you found my description interesting. I’ll continue doing these timeline based blow-by-blow programming articles on my apps as they are pretty fun.
