[Android] A summary of image processing APIs in Android
Images are essential for application development. The Android system provides a wide range of image support functions. In addition to the Drawable resource library, we can also use Bitmap and Picture classes to create images, or use the Canvas, Paint, and Path classes to draw satisfactory images. These APIs are especially common when using custom controls. Therefore, I think it is necessary to make a simple summary.
Start with Bitmap and BitmapFactory.
Bitmap and BitmapFactory
BitmapFactory
Bitmap indicates a Bitmap. The encapsulated image in BitmapDrawable is a Bitmap object.
You can call the BitmapDrawable constructor to encapsulate a Bitmap object into a BitmapDrawable object. The method is as follows:
BitmapDrawable drawable = new BitmapDrawable (bitmap );
To obtain Bitmap objects encapsulated in BitmapDrawable, use the following method:
Bitmap bitmap = drawable. getBitmap ();
BitmapFactory provides multiple methods to parse and create Bitmap objects:
DecodeByteArray (byte [] data, int offset, int length): parses bytes of length from the offset bytes into Bitmap objects.
DecodeFile (String pathName): parses a file in a specified path into a Bitmap object.
DecodeFileDescriptor (FileDescriptor fd): parses the file corresponding to FileDescriptor and creates a Bitmap object.
DecodeResource (Resources res, int id): parses a given resource ID into a Bitmap object.
DecodeStream (InputStream is):Parses the specified byte stream into a Bitmap object.
In addition, Android provides Bitmap with two methods to determine whether Bitmap has been recycled and forces Bitmap to recycle itself. Boolean isRecycled () and void recycle () Methods
Canvas
Canvas, which is called "Canvas", is mainly used to draw views. Canvas provides a large number of ways to draw images:
Draw slice:
DrawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint): The first RectF object, which specifies the slice area. The second parameter is the start angle; the third parameter is the rotation angle, clockwise rotation; the fourth parameter is whether to fill, true is filled, false is not filled, that is, an arc; the fifth parameter is the Paint brush object for drawing the image.
RectF: Creates a RectF object through the RectF (float left, float top, float right, float bottom) constructor.
Paint: a Paint brush used to draw all images. We will explain it later.
DrawArc (float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint): This is the left, top, right, the following coordinates are directly input, rather than the RectF object. Other parameters are the same as above.
Draw a circle:
DrawCircle (float cx, float cy, float radius, Paint paint): the first and second parameters refer to the x and y coordinates of the circle, and the third parameter is the radius; the fourth parameter is the Paint object.
Draw a straight line:
DrawLine (float startX, float startY, float stopX, float stopY, Paint paint): two points determine a straight line. The first and second parameters are the coordinates of the starting point; the third and fourth parameters are the coordinates of the ending point, and the fifth parameter is the Paint object.
DrawLines (float [] pts, Paint paint): multiple points determine a straight line. The first parameter is the array of points, and the second parameter is the Paint object.
DrawLines (float [] pts, int offset, int count, Paint paint)
Draw an ellipse:
DrawOval (float left, float top, float right, float bottom, Paint paint): the first four parameters are the coordinates of the left, top, right, and bottom of the ellipse, the fifth is the Paint object.
DrawOval (RectF oval, Paint paint): the first parameter is the RectF object, and the second parameter is the Paint object.
Draw a rectangle:
DrawRect (RectF rect, Paint paint): the first parameter is the RectF object, and the second parameter is the Paint object.
Draw point:
DrawPoint (float x, float y, Paint paint): coordinates of the first and second parameter points, and the third parameter is the Paint object.
Render text:
DrawText (String text, float x, floaty, Paint paint)
DrawText (CharSequence text, int start, int end, float x, float y, Paint paint)
DrawText (char [] text, int index, int count, float x, float y, Paint paint)
DrawText (String text, int start, int end, float x, float y, Paint paint)
Canvas also provides us with many ways to draw other images. We will not list them here. Let's take a look at the Paint brush.
Paint:
Paint is the Paint brush used for drawing. Canvas is like our drawing paper. We need a pen to complete the entire graph. Paint provides us with a lot of settings (Here we only list common methods ):
SetARGB (int a, int r, int g, int B): sets the color of the Paint object. Parameter 1 is the alpha transparent value.
SetAlpha (int a): sets the alpha opacity in the range of 0 ~ 255
SetAntiAlias (boolean aa): whether or not it is anti-sawtooth. This is usually set.
SetColor (int color): Set the Color. Here, the color class defined in Android contains some common Color definitions.
SetTextScaleX (float scaleX): sets the text zoom factor, and 1.0f is the original
SetTextSize (float textSize): Set the font size
SetUnderlineText (booleanunderlineText): Set the underline
SetStrokeCap (Paint. Cap cap): When the Paint brush style is STROKE or FILL_OR_STROKE, set the image style of the brush, such as the circular style Cap. ROUND, or the SQUARE style Cap. SQUARE
SetSrokeJoin (Paint. Join join): sets the combination mode of each graph during painting, such as smooth effect.
Path
Path, track, Path. A Path can be drawn along multiple points. Different images can be drawn based on the Path in the Canvas.
We are using Path to draw a Path. We generally need to use the following methods:
MoveTo (float x, float y): Move to (x, y) coordinate point. When creating a path, the first vertex of the path is usually determined by moveTo (). Otherwise, the default vertex is (0, 0.
LineTo (float x, float y): draws a straight line from the current point to the (x, y) Point. Unlike moveTo (), moveTo () refers to jump to the (x, y) point without drawing a line.
Close (): close the path. For example, we plot a triangle. The three points of the triangle are (0, 0,), (100, 0), and (0,100). We use lineTo to convert (0, 0,), (100, 0) connection, (100, 0), (0,100) connection, this is still a line between (0, 0,), (0,100, in this case, we can directly call the close () method to close the image and form a triangle.
QuadTo (float x1, float y1, float x2, float y2): draws the besell curve, which is controlled by three points: Start Point, end point, and control point. In this method, the first two parameters are the coordinates of the control point, and the last two parameters are the coordinates of the termination point.
In Path, we can draw a Path by clicking or using addXXX (). In Path, we provide many ways to add different paths:
| Method |
Purpose |
| AddArc (RectF oval, float startAngle, float sweepAngle) |
Add an arc track |
| AddCircle (float x, float y, float radius, Path. Direction dir) |
Add a circular track |
| AddOval (float left, float top, float right, float bottom, Path. Direction dir) |
Add an elliptical track |
| AddRect (float left, float top, float right, float bottom, Path. Direction dir) |
Add rectangular trajectory |
| AddRoundRect (float left, float top, float right, float bottom, float rx, float ry, Path. Direction dir) |
Add an elliptical rectangular trajectory |
The following are two simple examples to help you better understand the knowledge points. Of course, at the beginning of this article, we have mentioned that these APIs are common in custom controls. The following also involves some knowledge about custom views. (~!~ If you want to systematically learn about custom views and viewgroups, and write a summary of this article)
The Demo of the custom clock mainly uses the Canvas and painting knowledge. Let's take a look at the Code:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}Only one layout is loaded in the main activity.
Place our custom View in the layout file, which is simple and does not need to be described too much.
Public class MyView extends View {private int width; // set high private int height; // set high private Paint mPaintLine; // define a straight-line Paint brush private Paint mPaintSecondLine; // define a straight-line Paint brush private Paint mPaintInterCircle; // define a circular Paint brush private Paint mPaintOutSideCircle; // define a circular Paint brush private Paint mPaintText; // define a paint brush private Calendar mCalendar for text painting; // create a time class private static final int NEED_INVALIDATE = 0X6666; public MyView (C Ontext context) {super (context);} public MyView (Context context, AttributeSet attrs) {super (context, attrs ); // initialize the Paint brush mPaintLine = new Paint (); mPaintLine. setAntiAlias (true); // eliminate the Sawtooth mPaintLine. setColor (Color. GRAY); // set the paint brush color mPaintLine. setStyle (Paint. style. STROKE); // set it to a hollow mPaintLine. setStrokeWidth (10); // set the width // initialize the second-pin brush mPaintSecondLine = new Paint (); mPaintSecondLine. setAntiAlias (true); // eliminates the Sawtooth m PaintSecondLine. setColor (Color. GRAY); // set the paint brush color mPaintSecondLine. setStyle (Paint. style. STROKE); // set it to a hollow mPaintSecondLine. setStrokeWidth (7); // set the width // initialize the incircle's brush mPaintInterCircle = new Paint (); mPaintInterCircle. setAntiAlias (true); // eliminate the Sawtooth mPaintInterCircle. setColor (Color. BLACK); mPaintInterCircle. setStyle (Paint. style. STROKE); // set it to a hollow mPaintInterCircle. setStrokeWidth (5); // initialize the brush mPaintOutSideCircle of the outer circle = new P Aint (); mPaintOutSideCircle. setAntiAlias (true); // eliminate the Sawtooth mPaintOutSideCircle. setColor (Color. BLACK); mPaintOutSideCircle. setStyle (Paint. style. STROKE); // set it to hollow mPaintOutSideCircle. setStrokeWidth (10); // Paint brush for drawing text mPaintText = new Paint (); mPaintText. setAntiAlias (true); // eliminate the Sawtooth mPaintText. setColor (Color. GRAY); mPaintText. setStyle (Paint. style. STROKE); // set it to hollow mPaintText. setTextAlign (Paint. align. CENTER); mPaintT Ext. setTextSize (40); mPaintText. setStrokeWidth (6); // initialize the Calendar mCalendar = Calendar. getInstance (); // send a Message to the UI main thread Handler handler = new Handler () {@ Override public void handleMessage (Message msg) {super. handleMessage (msg); switch (msg. what) {case NEED_INVALIDATE: // with the new time mCalendar = Calendar. getInstance (); invalidate (); sendEmptyMessageDelayed (NEED_INVALIDATE, 1000); break ;}}; handler. sendEmptyM EssageDelayed (NEED_INVALIDATE, 2000) ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); width = getDefaultSize (rows (), widthMeasureSpec); height = getDefaultSize (rows (), heightMeasureSpec); setMeasuredDimension (width, height ); // set the width and height} @ Override protected void onDraw (Can Vas canvas) {super. onDraw (canvas); // The main thread automatically calls canvas. drawCircle (width/2, height/2,300, mPaintInterCircle); canvas. drawCircle (width/2, height/2,320, mPaintOutSideCircle); for (int I = 1; I <= 12; I ++) {canvas. save (); // save the current canvas. rotate (360/12 * I, width/2, height/2); // rotate the canvas according to the vertex width/2, height/2. drawLine (width/2, height/2-300, width/2, height/2-270, mPaintLine); ca Nvas. drawText (+ I, width/2, height/2-240, mPaintText); canvas. restore (); // return to the Saved state of the save () method} // draw the sub-needle int minute = mCalendar. get (Calendar. MINUTE); float minuteDegree = minute/60f * 360; canvas. save (); canvas. rotate (minuteDegree, width/2, height/2); canvas. drawLine (width/2, height/2-200, width/2, height/2 + 40, mPaintLine); canvas. restore (); // specifies the hour-hand int hour = mCalendar. get (Calenda R. HOUR); float hourDegree = (hour * 60 + minute); // (12f * 60) * 360; canvas. save (); canvas. rotate (hourDegree, width/2, height/2); canvas. drawLine (width/2, height/2-170, width/2, height/2 + 30, mPaintLine); canvas. restore (); // draw seconds int second = mCalendar. get (Calendar. SECOND); float secondDegree = second * 6; // The SECOND is 6 degrees. Canvas. save (); canvas. rotate (secondDegree, width/2, height/2); canvas. drawLine (width/2, height/2-220, width/2, height/2 + 50, mPaintSecondLine); canvas. restore ();}}OnDraw is the main UI thread that constantly calls the re-painting interface. Therefore, we need to use Handler to send a message to the Handler object so that the Handler object redraws the MyView control once every second. Here, the onDraw () method cannot be called, but the invalidate () method is called. The onDraw () method is called in the invalidate () method.
Let's take a look at the effect immediately:
The double buffer is used to implement the graphic board. The main principle of the above knowledge is: when the program needs to draw on the specified View, the program does not directly draw on the View formation, instead, the Bitmap is first drawn to a Bitmap image in the memory. After the Bitmap in the memory is drawn, the Bitmap is drawn to the View at one time. Let's look at the Code directly:
public class MainActivity extends AppCompatActivity { DrawView drawView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout line = new LinearLayout(this); DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); drawView = new DrawView(this, displayMetrics.widthPixels,displayMetrics.heightPixels); line.addView(drawView); setContentView(line); }}The main Activity mainly obtains the width and height of the wearing part. It creates a DrawView and keeps the width and height of the DrawView consistent with that of the Activity. Let's take a look at the code in DrawView:
public class DrawView extends View{ float prex; float prey; private Path path; public Paint paint = null; Bitmap CacheBitmap = null; Canvas CacheCanvas = null; public DrawView(Context context, int widthPixels, int heightPixels) { super(context); CacheBitmap = Bitmap.createBitmap(widthPixels,heightPixels,Bitmap.Config.ARGB_8888); CacheCanvas = new Canvas(); path = new Path(); CacheCanvas.setBitmap(CacheBitmap); paint = new Paint(Paint.DITHER_FLAG); paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); paint.setAntiAlias(true); paint.setDither(true); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(x,y); prex = x; prey = y; break; case MotionEvent.ACTION_MOVE: path.quadTo(prex, prey, x, y); prex = x; prey = y; break; case MotionEvent.ACTION_UP: CacheCanvas.drawPath(path,paint); path.reset(); break; } invalidate(); return true; } @Override public void onDraw(Canvas canvas) { Paint bmPaint = new Paint(); canvas.drawBitmap(CacheBitmap,0,0,bmPaint); canvas.drawPath(path,paint); }}To change the graphics drawn by the view, the program needs to remember some State data: Modify the data in the listener using variables or using event listeners. Regardless of the method used, the VIew component should be notified to re-call the OnDraw () method to re-paint the control each time the graphics status on the View component changes. The invalidate () can be called for notification ().
The running result is as follows: