Smartphones

Transforming bitmaps via Android's ImageView widget

Learn how to apply an alpha transformation, scale a bitmap, and rotate a bitmap, all using Android's ImageView widget.

The Android platform is all about choices. When it comes to writing Android apps, I can't think of a single scenario where there aren't multiple approaches to achieve the same results. Manipulating bitmaps is no exception. And while there are a number of ways to transform images, I've come across a little "trick" that pays off with a "treat."

In this tutorial, I will demonstrate how to apply an alpha transformation, scale a bitmap, and rotate a bitmap, all using the ImageView widget. More importantly, the technique doesn't require the explicit creation of new bitmaps and thereby avoids some of the messy memory management that frequently goes hand-in-hand with image transformations.

You can follow the step-by-step tutorial that follows or download the entire project and import it directly into Eclipse. Ready to get started?

1. Create a new Android project in Eclipse. Target Android 1.6 or higher. Be sure to rename the startup activity Main.java, and the corresponding layout file to main.xml.

2. Before we can go very far manipulating an image, we need an image to manipulate. In the /res folder create a new directory called drawable. In keeping with the season, this is where I've placed my image, jackolantern.png (Figure A). Figure A

3. Now that we have our bitmap file at our fingertips, it's time to define the layout. In the /res/layout folder, I've modified main.xml to consist of a text view, an image view, and three horizontally placed buttons.

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#000000">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dip"
        android:gravity="center"
        android:textColor="#ff4500"
        android:text="Happy Halloween!"
        android:textStyle="bold"
        android:textSize="18sp"/>

<ImageView
    android:id="@+id/image"
    android:paddingTop="20dip"
    android:paddingBottom="20dip"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:adjustViewBounds="true"
    android:src="@drawable/jackolantern"/>
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center">
    <Button
        android:id="@+id/scale_button"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
       android:text="scale"/>
    <Button
        android:id="@+id/rotate_button"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
        android:text="rotate"/>
    <Button
        android:id="@+id/alpha_button"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
        android:text="alpha"/>
   </LinearLayout>
</LinearLayout>

4. It's time to write a little code. In the /src/Main.java file, we begin by overriding the on create and wiring up our buttons.

Main.java

package com.authorwjf.bitmapmanipulation;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Matrix;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
public class Main extends Activity implements OnClickListener{
       boolean isAlphaOriginalValue = true;
       boolean isRotationOriginalValue = true;
       boolean isScaleOriginalValue = true;
       Matrix mMatrix = new Matrix();
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      findViewById(R.id.alpha_button).setOnClickListener(this);
      findViewById(R.id.rotate_button).setOnClickListener(this);
      findViewById(R.id.scale_button).setOnClickListener(this);
      ((ImageView)findViewById(R.id.image)).setImageMatrix(mMatrix);
      ((ImageView)findViewById(R.id.image)).setScaleType(ScaleType.MATRIX);
}
      @Override
      public void onClick(View v) {
             switch (v.getId()) {
             case R.id.alpha_button:
                    alphaXform();
                    break;
            case R.id.rotate_button:
                   rotateXform();
                   break;
            case R.id.scale_button:
                   scaleXform();
                   break;
            }
     }
}

5. We need to implement all three transformations.

Main.java (continued)

private void alphaXform() {
      if (isAlphaOriginalValue){
              //we can change the alpha via the image view widget
              ((ImageView) findViewById(R.id.image)).setAlpha(100);
      } else {                       ((ImageView)
findViewById(R.id.image)).setAlpha(255);
      }
      isAlphaOriginalValue = !isAlphaOriginalValue;

((ImageView)findViewById(R.id.image)).setImageMatrix(mMatrix);

((ImageView)findViewById(R.id.image)).invalidate();
}
private void rotateXform() {
      int centerX = (int)(((ImageView)findViewById(R.id.image)).getWidth()*.5);
      int centerY = (int)(((ImageView)findViewById(R.id.image)).getHeight()*.5);
      if (isRotationOriginalValue){
             mMatrix.postRotate((float)180,centerX,centerY);
      } else {
             mMatrix.postRotate((float)-180,centerX,centerY);
      }
      isRotationOriginalValue = !isRotationOriginalValue;
      ((ImageView)findViewById(R.id.image)).setImageMatrix(mMatrix);
      ((ImageView)findViewById(R.id.image)).invalidate();
}
private void scaleXform() {
       ImageView iv = (ImageView)findViewById(R.id.image);

LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)

iv.getLayoutParams();
       if (isScaleOriginalValue){
              mMatrix.postScale((float).5, (float).5);
              params.width = (int)(iv.getWidth()*.5);
              params.height = (int)(iv.getHeight()*.5);
       } else {
              mMatrix.postScale((float)2.0, (float)2.0);
              params.width = (int)(iv.getWidth()*2.0);
              params.height = (int)(iv.getHeight()*2.0);
       }
       isScaleOriginalValue = !isScaleOriginalValue;
       iv.setLayoutParams(params);
       ((ImageView)findViewById(R.id.image)).setImageMatrix(mMatrix);
       ((ImageView)findViewById(R.id.image)).invalidate();
}
We should be good to go. You can fire up our digital jack-o-lantern (Figure B) on the emulator or your phone. Figure B

The effects may be applied individually or in conjunction with one another. And as promised we aren't creating a new bitmap each time we perform a transformation; this means less time manually dealing with memory and more time to get into the Halloween spirit. Which reminds me... why didn't the skeleton go to the Halloween party? Because he had no "body" to go with.

Happy Halloween!!!

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

0 comments

Editor's Picks