Table of Contents
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 sourceBitmap
- 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 . TheResource
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); } }