Bitmap in android a tutorial ?

What is bitmap ?

A bitmap is an object , which is an instance of the Bitmap Class. This class represents a 2d coordinate system . The coordinate system move to the right on the x axis , and to the bottom on the y axis .

Each point in the coordinate system is called a pixel . A pixel is formed of bits , and bits represent the color of this pixel. A pixel can be formed of 8 , or 16 or 24 bits … The x axis represents the width , and the y axis represent the height .

Everything that is drawn in android is a Bitmap. We can create a Bitmap instance , either by using the Bitmap class which has methods that allow us to manipulate pixels in the 2d coordinate system , or we can can create a Bitmap from an image or a file or a resource by using the BitmapFactory class

What is canvas ?

A canvas is an object which is an instance of the class Canvas . A canvas is used to draw on a bitmap , it has methods to draw shapes on a bitmap . Such as drawing a text , a line , a rectangle or a circle .. We can style the shapes created by the canvas by using a paint object .

What is paint ?

A paint object is an instance of the Paint class . it is used to style a shape drawn by a canvas . We can set the stroke , the fill color .. of the drawn shape using the paint object.

Create a bitmap by using Bitmap class

The Bitmap class has many methods that allow us to create an instance of a Bitmap by using java . These methods will allow us to set the width , height , density , and number of pixels of a Bitmap .

Bitmap.createBitmap(int width, int height, Bitmap.Config config)

This method will take as parameters the width and height of the bitmap in pixels. It also takes the configuration for this Bitmap. The configuration specify the number of bits that each pixel in the bitmap will have. For example , we can specify that a pixel will take 32 bits (ARGB_8888) , as such each red , green , blue color will take 8 bits , and the alpha channel will take 8 bits .

package com.twiserandom.bitmap_canvas_paint;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {

    BCPIView bcpiView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);

        /*
            BCPIView ,  is an imageView that contains a bitmap created programmatically
         */
        bcpiView = new BCPIView(this);
        /*
          set bcpiView width and height to match parent
         */
        ll.addView(bcpiView , new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.MATCH_PARENT));

        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
    }

    // Bitmap Canvas Paint Image View
    class BCPIView extends android.support.v7.widget.AppCompatImageView {

        Paint paint ;
        Canvas canvas;

        public BCPIView(Context context) {
            super(context);

            /* create the paint object*/
            paint = new Paint();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            /*
            Create a bitmap
                width is equal to the imageView width
                height is equal to the imageView Height

                each pixel is formed of 4 bytes
                    each color will have 8 bits
                    alpha channel will have 8 bits
            */
            Bitmap bitmap =  Bitmap.createBitmap(getWidth() , getHeight() , Bitmap.Config.ARGB_8888);
            //set the background color of the bitmap to RED
            bitmap.eraseColor(Color.RED);
            //associate the canvas created with this bitmap
            canvas = new Canvas(bitmap);
            //set the color of the paint object to GREEN
            paint.setColor(Color.GREEN);
            // draw a rectangle inside the bitmap
            // it is positioned from left top 20
            // to the width , height - 20
            canvas.drawRect(20.0f , 20.0f,getWidth() - 20.0f , getHeight() -20.0f , paint);

            //set the bitmap as the imageView drawable
            setImageBitmap(bitmap);

        }
    }
}

package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {

    /*Create a 32 bit int color*/
    @ColorInt
    public static final int COLOR_PALEGOLDENROD = 0xFFEEE8AA;

    ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);

        /*create an imageView*/
        iv = new ImageView(this);
        /*Set the layoutparam of the imageView
         *   width : match parent
         *   height: match parent
         */
        ll.addView(iv, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        /*
            create bitmap with 900px width , and height of 900px
         */
        Bitmap bm = Bitmap.createBitmap(900, 900, Bitmap.Config.ARGB_8888);
        bm.eraseColor(COLOR_PALEGOLDENROD);

        /*set the imageview bitmap*/
        iv.setImageBitmap(bm);
        /*The bitmap is centered inside the imageView
         * No scaling is performed
         * */
        iv.setScaleType(ImageView.ScaleType.CENTER);


        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
    }


}

Bitmap.createBitmap(Bitmap src)

we can use this method to get a copy of a Bitmap that is already created .

  • If the source Bitmap is immutable return the source Bitmap
  • if it is mutable , create a copy of the src Bitmap , and return it .
package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {

    /*Create a 32 bit int color*/
    @ColorInt
    public static final int COLOR_FUCHSIA = 0xFFFF00FF;

    ImageView ivOne , ivTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);

        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));

        /*
            create bitmap with 200px width , and height of 100px
         */
        Bitmap bm = Bitmap.createBitmap(200, 100, Bitmap.Config.ARGB_8888);
        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();
        paint.setColor(COLOR_FUCHSIA);
        /* Draw a rectangle on the bitmap*/
        cv.drawRect(0,0,200,100,paint);


        Bitmap bmSrc= Bitmap.createBitmap(bm);


        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);

        /*
            set the bitmaps on the image views
         */
        ivOne.setImageBitmap(bm);
        ivTwo.setImageBitmap(bmSrc);

        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
    }


}

Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height)

This method allow us to create a copy of a Bitmap .

  • x,y are the coordinate of the first pixel in the source
  • width is the number of pixel in the source, must be less or equal to sourceWidth-x
  • height is the number of row in the source, must be less than sourceHeight-y

if x,y is 0 , 0 , and width and height equals the source bitmap width and height , and the source bitmap is immutable , return the source bitmap itself , else , return a copy of the source bitmap (x,y) , with the given width and height .

package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {

    /*Create a 32 bit int color*/
    @ColorInt
    public static final int COLOR_FUCHSIA = 0xFFFF00FF;

    ImageView ivOne , ivTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);

        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));

        /*
            create bitmap with 200px width , and height of 100px
         */
        Bitmap bm = Bitmap.createBitmap(200, 100, Bitmap.Config.ARGB_8888);
        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();
        paint.setColor(COLOR_FUCHSIA);
        /* Draw a rectangle on the bitmap*/
        cv.drawRect(0,0,200,100,paint);

        /*
        crete a copy of the bitmap
            from x,y
            with width and height

        * */
        Bitmap bm_Src_X_Y_W_H= Bitmap.createBitmap(bm,30,40,100,50);
        bm_Src_X_Y_W_H.eraseColor(0xFF123456);

        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);

        /*
            set the bitmaps on the image views
         */
        ivOne.setImageBitmap(bm);
        ivTwo.setImageBitmap(bm_Src_X_Y_W_H);

        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
    }


}

Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter)

create a new Bitmap , from a source bitmap .

  • x,y are the coordinate of the first pixel in the source
  • width is the number of pixel in the source, must be less or equal to sourceWidth-x
  • height is the number o row in the source, must be less or equal to sourceHeight-y
  • m , is the transformation matrix . It contains, the operations that we can perform on a bitmap :
    • translation : will translate a bitmap from old origin (0,0) , to new origin . This doesn’t work while creating a bitmap from another bitmap
    • scaling
    • skewing
    • rotation
    • if we want to perform just one operation , we can create a new matrix , and use the set methods, like setScale , setSkew ..
    • if we want to perform multiple operations , we can create a new matrix , and use the pre and post methods . pre means the operation will be performed first , post means the operation will be performed after.
  • filter , if set to true , will use sampling on the image, usually this will make the quality of the image better , and smoother .

If the source x,y is 0,0 , and if the width and height is equal to the source width and height , and if the transformation matrix is the identity matrix , so if there is no transformation done , and if the source is immutable return the bitmap itself. Else , create a copy of the bitmap from the source (x,y), with the given width and height ,and transformation and filtering applied .

Translate

the translate methods

setTranslate
preTranslate
postTranslate

doesn’t work when create a bitmap from another one .

package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {


    ImageView ivOne , ivTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);

        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));

        /*
            create bitmap with 700px width , and height of 200px
            set its color to greenish
         */
        Bitmap bm = Bitmap.createBitmap(700, 200, Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);


        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();

        // draw a rectangle
        paint.setColor(0xFFFF00FF);
        cv.drawRect(0,0,200,100,paint);

        //draw a second rectangle
        paint.setColor(0xFF654321);
        cv.drawRect(50,50,250,150,paint);

        //draw a third rectangle
        paint.setColor(0xFF231645);
        cv.drawRect(30,30,230,130,paint);




        /*
        create a copy of the bitmap
            x:0 , y : 0
            width : 700
            height: 200
            setTranslate : 100 , 100
        * */
        Matrix m = new Matrix();
        m.setTranslate(100,100);
        Bitmap bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 700,200,m, true);


        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);

        /*
            set the bitmaps on the image views
         */
        ivOne.setImageBitmap(bm);
        ivTwo.setImageBitmap(bm_Src_X_Y_W_H_M_F);

        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);

    }


}

Rotate

the rotate methods ,

setRotate(float degrees)
preRotate(float degrees)
postRotate(float degrees)

will rotate all pixels inside a bitmap clockwise by a given angle . The angle is specified in degree , and the point of rotation is the upper left corner which has a coordinate of (0,0) . The formula for rotation is

x' = x•cos(α) – y•sin(α)
y' = x•sin(α) + y•cos(α)
package com.twiserandom.bitmap_canvas_paint;
 
 
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
 
public class BitmapCanvasPaintActivity extends AppCompatActivity {
 
 
    ImageView ivOne , ivTwo;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
 
        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
 
        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
 
        /*
            create bitmap with 700px width , and height of 200px
            set its color to greenish
         */
        Bitmap bm = Bitmap.createBitmap(700, 200, Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);
 
 
     
        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();
 
        // draw a rectangle
        paint.setColor(0xFFFF00FF);
        cv.drawRect(0,0,200,100,paint);
 
        //draw a second rectangle
        paint.setColor(0xFF654321);
        cv.drawRect(50,50,250,150,paint);
 
        //draw a third rectangle
        paint.setColor(0xFF231645);
        cv.drawRect(30,30,230,130,paint);
 
 
        /*
        create a copy of the bitmap
            x:0 , y : 0
            width : 700
            height: 200
            setRotate : 22
        * */
        Matrix m = new Matrix();
        m.setRotate(22);
        Bitmap bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 700,200,m, true);
 
 
        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
 
        /*
            set the bitmaps on the image views
         */
        ivOne.setImageBitmap(bm);
        ivTwo.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
 
    }
 
 
}

scale

we can use the scale methods

setScale(float sx , float sy)
preScale(float sx, float sy)
postScale(float sx , float sy)

in order to scale the coordinate of an image up or down. The scaling is performed from the upper left corn which has a coordinate (0,0). When scaling up , we are creating new pixels , the new pixels are created by using linear interpolation . When scaling down we are removing pixels using sampling . We can set set the filter option to true in both cases , to create smoother images . If the x and y scale factor are equal , the scaled image will keep its aspect ration . The formula for the scaled pixels is

x' = sx · x
y' = sy · y
package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {


    ImageView ivOne , ivTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);

        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));

        /*
            create bitmap with 700px width , and height of 200px
            set its color to greenish
         */
        Bitmap bm = Bitmap.createBitmap(700, 200, Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);

        
        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();

        // draw a rectangle
        paint.setColor(0xFFFF00FF);
        cv.drawRect(0,0,200,100,paint);

        //draw a second rectangle
        paint.setColor(0xFF654321);
        cv.drawRect(50,50,250,150,paint);

        //draw a third rectangle
        paint.setColor(0xFF231645);
        cv.drawRect(30,30,230,130,paint);




        /*
        crete a copy of the bitmap
            x:0 , y : 0
            width : 700
            height: 200
            setScale : 2
        * */
        Matrix m = new Matrix();
        m.setScale(2,2);
        Bitmap bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 700,200,m, true);


        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);

        /*
            set the bitmaps on the image views
         */
        ivOne.setImageBitmap(bm);
        ivTwo.setImageBitmap(bm_Src_X_Y_W_H_M_F);

        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);

    }


}

skew

skewing will skew all pixels using the following formula

x' = x + sx * y
y' = sy * x + y

A pixel has an (x ; y) coordinate , the new coordinate of the pixel are calculated using the formula (x + sx * y ; sy * x + y) . So x is moved from the y axis by a distance , and y is moved from the x axis by a distance .

The skew methods that we can use are

setSkew(float sx , float sy) 
preSkew(float sx, float sy) 
postSkew(float sx , float sy)
package com.twiserandom.bitmap_canvas_paint;
 
 
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
 
public class BitmapCanvasPaintActivity extends AppCompatActivity {
 
 
    ImageView ivOne , ivTwo , ivThree ,ivFour ,ivFive,ivSix;
    Bitmap bm_Src_X_Y_W_H_M_F;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
 
        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
        ivThree = new ImageView(this);
        ivFour = new ImageView(this);
        ivFive = new ImageView(this);
        ivSix = new ImageView(this);
 
        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *  weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT , 1));
        ll.addView(ivThree, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
        ll.addView(ivFour, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
        ll.addView(ivFive, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
        ll.addView(ivSix, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
 
        /*
            create bitmap with 300px width , and height of 100px
            set its color to greenish
         */
        Bitmap bm = Bitmap.createBitmap(300, 100, Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);
 
 
        /*create a canvas object*/
        Canvas cv = new Canvas(bm);
        /*create a paint object*/
        Paint paint = new Paint();
 
 
        // draw a rectangle
        paint.setColor(0xFFFF00FF);
        cv.drawRect(0,0,50,100,paint);
 
        //draw a circle
        paint.setColor(0xFFFa00AF);
        cv.drawCircle(110,50,50 , paint);
 
        //draw a
        paint.setColor(0xFFFF0012);
        paint.setTextSize(80);
        cv.drawText("FF",170,70, paint);
 
 
        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
        ivThree.setScaleType(ImageView.ScaleType.CENTER);
        ivFour.setScaleType(ImageView.ScaleType.CENTER);
        ivFive.setScaleType(ImageView.ScaleType.CENTER);
        ivSix.setScaleType(ImageView.ScaleType.CENTER);
 
        /*
         set imaveView one bitmap
         */
        ivOne.setImageBitmap(bm);
 
        /*
        create a transformation matrix
         */
        Matrix m = new Matrix();
        /* set the skew factor on the x axis by 0.75*/
        m.setSkew(0.75f,0);
        // create a bitmap from the bm bimtap with the specified transformation matrix
        bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 300,100,m, true);
        // set the bitmap  as a bitmap for the ivTwo
         ivTwo.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
         /*reset the transformation matrix*/
        m.reset();
        /* set the skew factor on the x axis by -0.75*/
        m.setSkew(-0.75f,0);
        // create a bitmap from the bm bimtap with the specified transformation matrix
        bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 300,100,m, true);
        // set the bitmap  as a bitmap for the ivThree
        ivThree.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
        /*reset the transformation matrix*/
        m.reset();
        /* set the skew factor on the y axis by 0.25*/
        m.setSkew(0f,0.25f);
        // create a bitmap from the bm bimtap with the specified transformation matrix
        bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 300,100,m, true);
        // set the bitmap  as a bitmap for the ivFour
        ivFour.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
        /*reset the transformation matrix*/
        m.reset();
        /* set the skew factor on the y axis by -0.25*/
        m.setSkew(0f,-0.25f);
        // create a bitmap from the bm bimtap with the specified transformation matrix
        bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 300,100,m, true);
        // set the bitmap  as a bitmap for the ivFive
        ivFive.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
 
        /*reset the transformation matrix*/
        m.reset();
        /* set the skew factor on the y axis by 0.25 0.25*/
        m.setSkew(0.25f,0.25f);
        // create a bitmap from the bm bimtap with the specified transformation matrix
        bm_Src_X_Y_W_H_M_F = Bitmap.createBitmap(bm , 0,0, 300,100,m, true);
        // set the bitmap  as a bitmap for the ivSix
        ivSix.setImageBitmap(bm_Src_X_Y_W_H_M_F);
 
 
 
 
        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
 
    }
 
 
}

create a density independent bitmap

When we are creating a bitmap with the previous methods , we are specifying the width and height in pixel . Different screens have different densities , as such the width and height specified in pixel , will look different on different screens . we can create a bitmap by using density independent pixel , like this the bitmap will look similar on screens with different densities .

package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {


    ImageView ivOne , ivTwo  ;
    Canvas cv;
    Paint paint;
    Bitmap bm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);

        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);



        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *   weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT  , 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT  , 1));

        /*
            create bitmap with 200px width , and height of 200px
            set its color to greenish
         */

        bm = Bitmap.createBitmap((int)(200 ), (int)(200 ), Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);
        ivOne.setImageBitmap(bm);

        /*
        create a bitmap with 200dpi height , and 200dpi height
        set it s color to greenish
        * */
        DisplayMetrics dm = getResources().getDisplayMetrics();
        float density = dm.density;
        bm = Bitmap.createBitmap((int)(200 * density), (int)(200 * density), Bitmap.Config.ARGB_8888);
        bm.eraseColor(0xFF276153);
        ivTwo.setImageBitmap(bm);




        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);

    }


}

Create a bitmap using BitmapFactory

The BitmapFactory method allow us to create a Bitmap from a an array of bytes , or from a file or from a resource , or from an input stream.

BitmapFactory.decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)

The decodeByteArray methods allow us to decode a Bitmap from a byte array . It takes as parameters :

  • the byte array , that we want to decode into a Bitmap
  • the offset which is where we want to start decoding.
  • the length , which is the number of bytes that we want to decode
  • the opts which is an instance of the Options class , and it is used to set the options that we want to use when decoding the byte array. If we pass null , it is as if we have create an instance of the Options class and passed it , so it is as if we have passed the default Option parameter . Some of the options that we can set are :
    • inSampleSize , which is used to sample the image. We can useit , if we want to create a smaller image , so to sample down this image . the sampling parameter is specified in multiples of two , so 2 , 4 .. and the resulting size will be divided by this multiple of two . so if the original image is 20 by 50 , and sampling is two , the resulting image is 10 by 25.
    • inMutable : if we want the returned Bitmap to be mutable , we can set this option to True.
    • inDensity : is used to specify the density of the image in the byte array .
    • inScaled : if set to true , android will scale the decoded image from the inDensity , to the screen Density where the application is running . so The decoded Bitmap might be scaled up or down.
package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class BitmapCanvasPaintActivity extends AppCompatActivity {


    ImageView ivOne, ivTwo, ivThree;
    BitmapFactory.Options bmfOptions;
    Bitmap bm;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create three imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
        ivThree = new ImageView(this);

        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
        ivThree.setScaleType(ImageView.ScaleType.CENTER);




        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *   weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivThree, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));


        //decode a base 64 encoded image into bytes
        // the original image is 500px by 500px
        byte[] bytes = Base64.decode("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", Base64.DEFAULT);

        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // decode a bitmap using decodeByteArray default Options
        Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bmfOptions);
        // set the decoded bitmap to the ivOne
        ivOne.setImageBitmap(bm);

        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // sample the image down by a factor of 4
        bmfOptions.inSampleSize = 4;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bmfOptions);
        // set the decoded bitmap to the ivTwo
        ivTwo.setImageBitmap(bm);


        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // set the original image density
        bmfOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
        bmfOptions.inScaled = true;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bmfOptions);
        // set the decoded bitmap to the ivThree
        ivThree.setImageBitmap(bm);





        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);

    }


}

BitmapFactory.decodeFile(String pathName, Options opts)

We can use this method in order to decode a Bitmap which is stored inside a file . The file location is specified as a string . This method takes two parameters

  • pathName : a string specifying the file location
  • opts : the option when decoding the file
package com.twiserandom.bitmap_canvas_paint;
 
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
 
public class BitmapCanvasPaintActivity extends AppCompatActivity {
 
 
    ImageView ivOne, ivTwo, ivThree;
    BitmapFactory.Options bmfOptions;
    Bitmap bm;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
 
        /*create three imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
        ivThree = new ImageView(this);
 
        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
        ivThree.setScaleType(ImageView.ScaleType.CENTER);
 
 
 
        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *   weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivThree, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
 
 
        //get the image path , the image is stored in the download folder
        // its name is image.png
        String imagePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/image.png";
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // decode a bitmap using decodeFile default Options
        Bitmap bm = BitmapFactory.decodeFile(imagePath, bmfOptions);
        // set the decoded bitmap to the ivOne
        ivOne.setImageBitmap(bm);
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // sample the image down by a factor of 4
        bmfOptions.inSampleSize = 4;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeFile(imagePath, bmfOptions);
        // set the decoded bitmap to the ivTwo
        ivTwo.setImageBitmap(bm);
 
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // set the original image density
        bmfOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
        bmfOptions.inScaled = true;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeFile(imagePath, bmfOptions);
        // set the decoded bitmap to the ivThree
        ivThree.setImageBitmap(bm);
 
 
 
 
 
        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
 
    }
 
 
}

Bitmap.decodeResource(Resources res, int id, BitmapFactory.Options opts)

we can use this method in order to decode a Bitmap which is stored inside the res folder . The res folder , is used to store bitmaps , animation , mipmap , drawables , images , assets ..

This methods takes as parameters :

  • The res : this is an instance of the Resource class . The Resource class is used to access the resources of our application . it has some methods which allow us to get resources such as the color , the drawable .. using the resource Id
  • The resource id , is the id of the bitmap that we want to access
  • The options : that are used to decode our image .
package com.twiserandom.bitmap_canvas_paint;
 
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
 
public class BitmapCanvasPaintActivity extends AppCompatActivity {
 
 
    ImageView ivOne, ivTwo, ivThree;
    BitmapFactory.Options bmfOptions;
    Bitmap bm;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
 
        /*create three imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
        ivThree = new ImageView(this);
 
        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
        ivThree.setScaleType(ImageView.ScaleType.CENTER);
 
 
 
        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *   weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivThree, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
 
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        bmfOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
        // decode a bitmap using decodeByteArray default Options
        // the default in destiny of the bitmap is DENSITY_MEDIUM
        // which is 160 dpi , because we have placed the image in the
        // default drawable folder
        bm = BitmapFactory.decodeResource(getResources(), R.drawable.image);
        // set the decoded bitmap to the ivOne
        ivOne.setImageBitmap(bm);
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // sample the image down by a factor of 4
        bmfOptions.inSampleSize = 4;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeResource(getResources(), R.drawable.image, bmfOptions);
        // set the decoded bitmap to the ivTwo
        ivTwo.setImageBitmap(bm);
 
 
        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // set the original image density
        // to be euqal to the density  of the
        // emulator  , which is 420 , so
        // there will be no scaling up
        // since the inDensity is equal to the in Target Density
        bmfOptions.inDensity = DisplayMetrics.DENSITY_420;
        bmfOptions.inScaled = true;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeResource(getResources(), R.drawable.image, bmfOptions);
        // set the decoded bitmap to the ivThree
        ivThree.setImageBitmap(bm);
 
 
 
 
 
        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);
 
    }
 
 
}

Bitmap.decodeStream(InputStream is, Rect outPadding,Options opts)

We can use this method if we want to decode an input stream into a Bitmap. An input stream is an abstraction which allow us to get access to a file or to the web or to any other resource .

This method takes us parameters :

  • is : the input stream , which can be a file stream for example
  • outPadding , we can just pass null
  • opts : the options for decoding the Bitmap
package com.twiserandom.bitmap_canvas_paint;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class BitmapCanvasPaintActivity extends AppCompatActivity {


    ImageView ivOne, ivTwo, ivThree;
    BitmapFactory.Options bmfOptions;
    Bitmap bm;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /*
            create a linear layout with vertical orientation
         */
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        /*create two imageViews*/
        ivOne = new ImageView(this);
        ivTwo = new ImageView(this);
        ivThree = new ImageView(this);

        /*
            set scale type of the imageViews to center
               No scaling is performed on the bitmap
               bitmap is just centered
         */
        ivOne.setScaleType(ImageView.ScaleType.CENTER);
        ivTwo.setScaleType(ImageView.ScaleType.CENTER);
        ivThree.setScaleType(ImageView.ScaleType.CENTER);



        /*Set the layoutparam of the imageViews
         *   width : match parent
         *   height: wrap content
         *   weight : 1
         */
        ll.addView(ivOne, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivTwo, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
        ll.addView(ivThree, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));


        //get the image path , the image is stored in the download folder
        // its name is image.png
        String imagePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/image.png";


        //create an bitmap from a FileInputStream
        try {
            bm = BitmapFactory.decodeStream(new FileInputStream(imagePath) , null , null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // set the decoded bitmap to the ivOne
        ivOne.setImageBitmap(bm);

        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // sample the image down by a factor of 4
        bmfOptions.inSampleSize = 4;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        //create an bitmap from a FileInputStream
        try {
            bm = BitmapFactory.decodeStream(new FileInputStream(imagePath), null, bmfOptions);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // set the decoded bitmap to the ivTwo
        ivTwo.setImageBitmap(bm);


        //create a bitmap factory options
        bmfOptions = new BitmapFactory.Options();
        // set the original density of the image
        // to be 160 , the image will be scaled
        // the the desnity of the target screen
        bmfOptions.inDensity = DisplayMetrics.DENSITY_MEDIUM;
        bmfOptions.inScaled = true;
        //set the decoded Bitmap to be mutable
        bmfOptions.inMutable = true;
        bm = BitmapFactory.decodeResource(getResources(), R.drawable.image, bmfOptions);
        // set the decoded bitmap to the ivThree
        ivThree.setImageBitmap(bm);





        /*
            set the activity content view
            to ll : linearlayout
            it will take the full width and height by default
        */
        setContentView(ll);

    }


}