http://www.developer.com/ws/android/programming/Working-with-Images-in-Googles-Android-3748281-3.htm

Back to article

Working with Images in Your Android App Development


January 9, 2012

The Android platform continues to enjoy increasing popularity among software developers. It started in late 2007 with two multi-million-dollar design contests that attracted thousands of talented developers from all over the world, and several of them made tech news headlines because of their innovative ideas. Many interesting concepts have been introduced in this platform since, but at the beginning some developers thought it would be nothing but a combination of Linux and Java along with Google APIs.

While focusing on image-related work on Android, this article should give you an idea of how easy it is to work with Android and how powerful this platform is. Click here to download the source files for the working sample project I'll refer to in this tutorial.

 


Visit the Android Dev Center

 

What Do You Need to Start?

At the moment, the best resource for Android developers is Google's own developer.android.com/ site. It has all the necessary development tools, plug-ins, and sample code you need. Simply follow the step-by-step instructions for installation. It does not make much sense for me to repeat here. The site also contains information about how to register and publish your application on Google's Android Market.

In addition to the online documentation, you can look for technical help by participating in the Android community forums. If you are a complete novice, use the free development tool Eclipse because it integrates better with the Android SDK as well as providing debugging software and emulators. There are other ways of building projects through command-line or batch scripts, but using Eclipse should be the easiest way to start, according to many fellow developers' experience.

Android APIs for Processing Images

Android's APIs cover lots of great features, including:

  • SQLite for structured data storage: You can embed a tiny database with your application without much effort.
  • Graphics library support: Optimized 2D graphics library and 3D graphics based on the embedded version of OpenGL ES.
  • Integrated Web browser support: You can easily integrate a Web view inside your software.
  • Media support: This supports common audio, video, and still-image formats, as well as text-to-speech (TTS) and voice recognition with a very straightforward interface.
  • Google APIs: Mapping capability allows third-party code to display and control a Google Map.
  • Hardware-dependent support: There are many APIs for NFC, telephony, Bluetooth, 3G, WiFi, camera, location-based services (via GPS and so forth), compass, and accelerometer.

Out of the large collection of APIs, you'll mainly look at those under the following two packages (as explained in the online description):

  • android.graphics: This package provides low-level graphics tools such as canvases, color filters, points, and rectangles that let you handle drawing to the screen directly.
  • android.graphics.drawable: This package provides classes to manage a variety of visual elements that are intended for display only, such as bitmaps and gradients.

Images are bitmaps, so you'll rely heavily on the APIs under android.graphics.Bitmap.

Android File I/O and Supported Image Formats

Android supports several common still-image formats such as PNG, JPG and GIF. In the example, you will use the JPG format. If you consider using the transparency feature for the image, the PNG format would be a better choice.

To read an image file that is packaged with your software, you should put it under the res/drawable folder relative to your software's root. After the image is in the folder, a resource ID will be generated automatically when you recompile the package. For example, you have the image file called pic1.jpg. It will become accessible programmatically through its resource ID R.drawable.pic1. You can see that the image file extension has been stripped off and the upper case R represents the overall resource file, R.java. R.java is generated automatically and should not be edited unless you have a pretty good understanding of how resources are structured in this file.

Here is a code snippet showing how you can refer to an image through its resource ID.

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic1);
int mPhotoWidth = mBitmap.getWidth();
int mPhotoHeight = mBitmap.getHeight();

To read or write an image file without specifying the folder structure, find it under /data/data/YourPackageName/files/ on the emulator. For example, you will create the package name for the example in this tutorial as package cliu.TutorialOnImages. Therefore, if you create a new image file at runtime, it will be under the /data/data/cliu.TutorialOnImages/files/ folder.

Please note that each Android application will start with its own user and group ID, so some file folders are not accessible through your software unless they are specifically set to do so. Here is the code for when you want to output a bitmap onto a file called output.jpg with a quality measure of 75% of the original image.

In our example, the result is saved onto an SD card. Android requires special permission for this purpose. In the manifest file, you will need to add the following line:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Here is how we make sure our folder exists:

String dirname = Environment.getExternalStorageDirectory() + "/tutorialonimages/";
File sddir = new File(dirname);
if (!sddir.mkdirs()) {
    if (sddir.exists()) {
    } else {
        Toast.makeText(TutorialOnImages.this, "Folder error", Toast.LENGTH_SHORT).show();
        return;
    }
}

Finally, we can save the resulting image onto the SD card under our folder.

try {
    FileOutputStream fos = new FileOutputStream(dirname + "output.jpg");
    mBitmap.compress(CompressFormat.JPEG, 75, fos);

    fos.flush();
    fos.close();
} catch (Exception e) {
    Log.e("MyLog", e.toString());
}

Image View, Colors, and Transparency in Android

Each Android application should have a screen layout. It can be created dynamically inside the software (used in our implementation), or it can be specified through an external XML file as in the example below. The default is main.xml. To contain an image, you use a View class called ImageView. Here is what the content of the main.xml file looks like:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/
   apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >

<ImageView id="@+id/picview"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   />

</LinearLayout>

Just as the image file can be accessed through a resource ID, main.xml will have a resource ID called R.layout.main automatically generated in the global resource file R.java after compilation. Figure 1 shows the initial view when the application first starts on the emulator.

Android Image Processing

Figure 1: Software First Starts On The Emulator

Each image pixel is represented as a 4-byte integer. The highest byte is for the alpha channel; in other words, the opacity/transparency control. A value of 255 means the pixel is completely opaque; 0 means it is entirely transparent. The next byte is for the red channel; 255 represents a fully saturated red. Similarly, the next two bytes are for the green and blue channels, respectively.

Manipulating Image Pixels in Android

Now, you can proceed to work on individual pixels. GetPixels in the android.graphics.Bitmap API is used to load the pixels into an integer array. In this example, you are tinting each image pixel by an angle in degrees. After the process, all pixels are made sure to fall within the byte range from 0 to 255. SetPixels in the android.graphics.Bitmap API is used to load the integer array onto an image. Before overwriting a bitmap image, it is always a good practice to release the old bitmap by using Bitmap.recycle().

The last step is to update the screen through the ImageView variable mIV. Here is the code segment for performing the tinting process.

int[] pix = new int[mPhotoWidth * mPhotoHeight];
mBitmap.getPixels(pix, 0, mPhotoWidth, 0, 0, mPhotoWidth, mPhotoHeight);
	        
double angle = (3.14159d * (double)deg) / 180.0d;	        
int S = (int)(256.0d * Math.sin(angle));	        
int C = (int)(256.0d * Math.cos(angle));

int r, g, b, index;
int RY, BY, RYY, GYY, BYY, R, G, B, Y;

for (int y = 0; y < mPhotoHeight; y++) {    
    for (int x = 0; x < mPhotoWidth; x++) {
        index = y * mPhotoWidth + x;
        r = (pix[index] >> 16) & 0xff;
        g = (pix[index] >> 8) & 0xff;
        b = pix[index] & 0xff;	    	    	
        RY = (70 * r - 59 * g - 11 * b) / 100;
        BY = (-30 * r - 59 * g + 89 * b) / 100;
        Y = (30 * r + 59 * g + 11 * b) / 100;
        RYY = (S * BY + C * RY) / 256;
        BYY = (C * BY - S * RY) / 256;
        GYY = (-51 * RYY - 19 * BYY) / 100;
        R = Y + RYY;
        R = (R < 0) ? 0 : ((R > 255) ? 255 : R);
        G = Y + GYY;
        G = (G < 0) ? 0 : ((G > 255) ? 255 : G);
        B = Y + BYY;
        B = (B < 0) ? 0 : ((B > 255) ? 255 : B);
        pix[index] = 0xff000000 | (R << 16) | (G << 8) | B;
    }
}

Bitmap bm = Bitmap.createBitmap(mPhotoWidth, mPhotoHeight, Bitmap.Config.ARGB_8888);
bm.setPixels(pix, 0, mPhotoWidth, 0, 0, mPhotoWidth, mPhotoHeight); 	

if (null != mBitmap) {
    mBitmap.recycle();
}
mBitmap = bm;

// Put the updated bitmap into the main view
mIV.setImageBitmap(mBitmap);	
mIV.invalidate();

pix = null;

Figure 2 shows the result after a user touches the screen.

Android Image Processing

Figure 2: Result After Touching the Screen

 

 

Putting All the Pieces Together

The previous sections explained how to import and export an image file, create a view for it, and process each pixel in the image. One thing you should add is a simple user interaction so that a sequence of events can happen in response to the user's input. OnTouchEvent() allows you to handle the screen touches that are key to the modern devices. The software is set to wait for the end of the screen touch event. When the touch is released, the picture will be tinted by a color angle of 60 degrees and its result will be saved onto an external storage file.

public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {	
    case MotionEvent.ACTION_UP:
        // Perform the tinting operation
        TintThePicture(60);

        // Display a short message on screen
        Toast.makeText(TutorialOnImages.this, "Picture was tinted", Toast.LENGTH_SHORT).show();

        // Save the result
        SaveThePicture();	
			
        return (true);
    case MotionEvent.ACTION_DOWN:
        break;
    }

    return super.onTouchEvent(event);
}

Some Advice for Android Image Processing

Before you jump into image Android image processing, here are some pointers to keep in mind:

  • If it takes too long to process all the image pixels (approximately five seconds), you could get a popup dialog called Application Not Responding or ANR. You should create a child thread and do the complicated calculation there. That should keep the main thread running without interruption.
  • If the child thread needs to change the main view (called UI thread), you should use a message handler in the main thread to listen for the notification from the child thread and then update the view accordingly. A child thread cannot modify the view in the main UI thread directly.
  • Some enhancements can be made. For example, it can be modified to read the image file from browsing the folders or from a URL. Image animation can be done carefully through multi-threading and message handling along with rectangle clipping to produce smooth transition effects.

Conclusion

Hopefully, the information provided here has given you a rough idea of how Android image processing works. I hope you develop a neat image application for the Android platform with your own unique style. From Eclipse, you can create a new Android project by selecting "Creating project from existing source" and browse to the folder where the sample project is decompressed to.

References

  1. Download and save the entire software project
  2. Android Developers at: http://developer.android.com/
  3. Rafael C. Gonzalez and Richard E. Woods, Digital Image Processing, Addison-Wesley Publishing, 1994

About the Author

Chunyen Liu has been a software professional for many years. Some of his applications were among winners at programming contests administered by SUN, ACM and IBM. He has also co-authored U.S. patents, written articles, and reviewed books for various publishers. He holds advanced degrees in Computer Science and has written numerous hobby apps at Androidlet and The J Maker. On the non-technical side, he is a tournament-ranked table tennis player, certified umpire, and certified coach of USA Table Tennis.

Sitemap | Contact Us