当前位置:文档之家› Android 图形图像编程

Android 图形图像编程

Android 图形图像编程
Android 图形图像编程

第一卷Android 基础图形图像编程

1 基础概念和数据结构

1.1颜色表示

1.1.1 RGB表示法

RGB颜色表示法是一种基于三基色原理的色彩表示方法。所谓三基色原理是指绝大部分颜色都可以用R(红),G(绿),B(蓝)三种基本颜色按照一定的比例混合得到。目前的绝大部分电子设备都是采用RBG来表示颜色的。因此,Android系统中也是用RGB来表示颜色。

根据每一中颜色表示的数据长度不同,Android中常用的RGB像素格式主要有:

ARGB8888:用4个字节表示一种颜色。其中最高8位表示和背景色的混合系数。剩下三个字节分别表示一种颜色。所以一共可以表示:256x256x256种颜色。

RGB888: 用三个自己表示一种颜色。和ARGB的区别仅在于没有透明系数。

RGB565: 用两个自己表示一种颜色。一共可以表示32x64x32种颜色。

在后文可以看到,当我们加载图像时,就需要指定图像的像素格式。

1.1.2 HSI表示法

HSI色彩空间是一种比较符合人的视觉系统的感知彩色的方式,以色调、饱和度和强度三种基本特征量来感知颜色。

色调H(Hue):表示不同的颜色,如红色、绿色、蓝色等。它也可表示一定范围的颜色,如暖色、冷色等。

饱和度S(Saturation):表示颜色的纯度。饱和度越大,颜色看起来就会越鲜艳,反之亦然。

强度I(Intensity):对应成像亮度和图像灰度,是颜色的明亮程度。

HSI 表示方法在数字图像处理软件中应用比较广泛。

1.1.3 YUV表示法

YUV是一种广泛应用于电视,广播,视频领域的颜色表示方法。

其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

在Android的多媒体模块中,视频解码器的输出格式就是YUV。

1.2像素

像素是数字图像的最基本单位,一个像素对应着一个点。通常我们说一个手机的分辨率是1024x768,就是说在长轴方向有1024个像素,而在短轴方向上有768个像素。一个像素表示一个颜色值,在Android中主要使用RGB表示法。1.1.1节中描述了android中最常用的几种像素表示格式。

Andorid系统为了便于开发者实现在不同设备上一致性较好的应用程序,定义了一些相关的基本概念并建议开发者在开发过程中使用,现简述如下:

pixel:像素,是一个逻辑单位。一个像素可以认为就是一个点。

dp/dip:物理长度单位。一个dp等于160分之一英寸。而一英寸等于2.54厘米。就是说1dp = 0.00625 inch = 0.015875 cm。

dpi:像素密度,是英文dot per inch的缩写,翻译过来就是一英寸多少个点。显然,越精细的屏幕,dpi就越高,显示效果就越好。

dp 和pixel 的换算关系为:

px =dp * (dpi/160).

dp=(px*160)/dpi.

ppi:像素密度,是英文pixel per inch的缩写,翻译过来就是一英寸多少像素。和dpi 是一个含义。ppi常用于显示领域。

屏幕尺寸:指屏幕的大小,通常说一个手机是4.3寸的,就是指屏幕尺寸为4.3英寸。注意,这个4.3指的是手机屏幕对角线的长度。家里的电视说多少寸的,和这个是一个原理,也是对角线的长度。

分辨率:我们说一个手机的分辨率是854x480,首先是以像素作为单位的。也就是说这个手机的长边能显示854个点,短边能显示480个点。但是这个854x480的手机到底是几寸的,还要看屏幕显示密度,也就是dpi/ppi。分辨率和显示密度共同决定了手机的屏幕尺寸。

1.3 位图

计算机上表示图像的方法主要有两种:位图(又称点阵图,光栅图)和矢量图。

矢量图指用一系列的线段和曲线描述的图像。常见的矢量图格式有Adobe Illustrator 的*.AI、*.EPS和SVG、AutoCAD的*.dwg和dxf、Corel DRAW的*.cdr、windows 标准图元文件*.wmf和增强型图元文件*.emf等等。矢量图的优点是缩放无质量损失,存储空间小,便于转换成位图等优点。

位图是用大量的点阵来描述图像。每个点表示一种颜色,称为一个像素。常见的位图格式有:*.bmp、*.pcx、*.gif、*.jpg、*.tif、*.pcd、*.psd、*.cpt。Android系统中目前主要使用位图进行各种显示。

1.4 画布(Canvas)

顾名思义,画布就是作画的地方。Android中的3D图形引擎是通过OpenGL ES实现的。而2D图形引擎就是通过Canvas封装的一系列的接口实现的。

画布实现的基本功能有:基本图形的绘制,如:直线,曲线,点等等,位图的显示,画布剪裁,画布的几何变换,用来实现移动,缩放,旋转等功能。

要在Android系统中使用画布作画,需要具备四个基本要素:

(1) 一个位图,用来最终保存在画布上绘制的内容。

(2) 一张画布,用来进行绘制操作。

(3) 基本绘制元素,就是想要往画布上绘制的内容。

(4)画笔,用来定义绘制图形的颜色,线型等基本内容。

画布对应了android.graphics 包中的Canvas类。

1.5 Drawable

drawable 是android系统中被定义为仅用于显示的视觉元素。通常用于控件的背景图片或者作为图标。通常在XML文件中定义。

drawabled对应了android.graphics中的Drawable类。Drawable有很多子类分别实现不同的显示功能,后文会详细描述。

2. 基本形状的绘制

本章主要描述两个基本问题:

(1) 如何使用画布绘制。

(2) 如何绘制基本的直线和曲线。

2.1 在画布上绘图

通常使用画布有两种情况,一种是通过继承android的view自定义自己的控件。这种情况下Canvas已经创建好,用户只需要在上边绘制即可,而绘制的结果会直接显示出来。

还有一种情况是用户需要创建自己的画布,绘制并保存,通常会将绘制的结果保存为位图。下面分别讨论这两种情况。

2.1.1 绘图基础

首先通过一个例子展示最基本的绘图接口的使用。

示例一种自定义了一个View并在其区域中显示了数条直线:

示例代码如下:

package com.example.androidgraphicsprogramm;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.os.Bundle;

import android.view.View;

public class CanvasBasic extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(new SampleView(this));

}

private static class SampleView extends View {

private Paint mPaint;

public SampleView(Context context) {

super(context);

setFocusable(true);

mPaint = new Paint();

}

@Override protected void onDraw(Canvas canvas) {

canvas.drawColor(Color.WHITE);

drawLine_1(canvas);

}

//

protected void drawLine_1(Canvas canvas) {

int xstart = 20;

int ystart = 100;

int linelen = 400;

//mPaint.setAntiAlias(true); // 设置反锯齿

mPaint.setStrokeWidth(6); // 线宽6个像素

mPaint.setColor(0xffff0000); // 线的颜色为红色

mPaint.setTextSize(50);

mPaint.setStyle(Paint.Style.STROKE);

canvas.drawText("线宽为6,红色,字号50", xstart , ystart, mPaint); ystart += 20;

canvas.drawLine(xstart, ystart, linelen + xstart , ystart, mPaint); ystart += 20;

RectF r = new RectF();

r.left = xstart;

r.top = ystart + 10;

r.right = r.left + linelen/2;

r.bottom = r.top + linelen/2;

canvas.drawRect(r, mPaint);

/////////////////////////////////////////////////////////////////////////// /

mPaint.setStrokeWidth(10); // 线宽10个像素

mPaint.setColor(0xff00ff00); // 线的颜色为绿色

mPaint.setTextSize(40);

mPaint.setStyle(Paint.Style.FILL);

ystart += (50 + linelen/2);

canvas.drawText("线宽为10,绿色,字号40", xstart , ystart, mPaint); ystart += 20;

canvas.drawLine(xstart, ystart, linelen + xstart , ystart, mPaint); ystart += 20;

r.left = xstart;

r.top = ystart + 10;

r.right = r.left + linelen/2;

r.bottom = r.top + linelen/2;

canvas.drawRect(r, mPaint);

/////////////////////////////////////////////////////////////////////////// //

mPaint.setStrokeWidth(10); // 线宽10个像素

mPaint.setARGB(100, 0, 255, 0); // 线的颜色为绿色

mPaint.setTextSize(40);

mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

ystart += (50 + linelen/2);

canvas.drawText("线宽为10,绿色,半透明", xstart , ystart, mPaint);

ystart += 20;

canvas.drawLine(xstart, ystart, linelen + xstart , ystart, mPaint); ystart += 20;

r.left = xstart;

r.top = ystart + 10;

r.right = r.left + linelen/2;

r.bottom = r.top + linelen/2;

canvas.drawRect(r, mPaint);

}

}

}

运行效果如图2-1所示。

下面对其中涉及到的类和函数进行详细说明,文本显示相关接口会在后面章节单独描述,这里不

做说明:

2.1.1.1 Paint 类

1. setStrokeWidth(float width)。设置边框的线宽。参数为宽度值,以像素为单位。对比效果图可以看出,线宽就是图中的直线或者矩形边框的宽度,以像素为单位。红色直线和矩形的宽度为6像素。而第二三条绿色直线的宽度为10像素。从图中也可以明显看出绿色直线比红色直线宽。

2.setColor(int color)。设置绘画对象的颜色。图中线条和矩形都颜色都由此函数指定。

参数颜色的格式为(16进制):0x (Alpha)ff (R)ff (G)ff (B)ff。参数可以用如下几种方式获得:

(1) Color 类提供的颜色常量。Android 通过android.graphics.Color提供了一个Color应用类,定义了一些颜色常量和获得颜色的函数。如Color.WHITE 代表白色。如果我们想将画笔颜色设为白色,就可以这样调用:setColor(Color.WHITE);

(2) Color 类提供的静态函数:

Color.rgb(int r,int g,int b), 根据分量r,g,b的值指定颜色。请注意,这里r,g,b 取值范围[0,255]。

Color.argb(int a,int r,int g,int b), 根据分量a,r,g,b的值指定颜色。这里a,r,g,b取值范围[0,255]。

3. setAlpha(int a)。设置绘画对象的透明度。等同于:

setColor((a<<24) & getColor())。a为透明度值,应取值为[0,255]。

4. setARGB(int a,int r,int g,int b)。设置绘画对象的颜色和透明度。等同于“

setColor((a<<24) & (r<<16) & (g<<8) & b)。a,r,g,b取值范围[0,255]。

5. setStyle(Paint.Style style)。设置填充的类型,目前参数取值为系统提供的三个枚举值,分别为:

Paint.Style.STROKE:只绘制边框。效果如第一个红色矩形框所示。边框线的宽度为setStrokeWidth指定的像素值。

Paint.Style.FILL:绘制实心区域。效果如第二个绿色实心矩形所示。矩形的宽和高有传入参数中的RectF对象决定。

Paint.Style.FILL_AND_STROKE:绘制边框和实心区域。效果如第三个绿色半透明实心区域所示。因此,此处的矩形宽度应该为RectF中设定的宽度+2*(setStrokeWidth指定的宽度)。细心的读者也可以从图上看出来,最后一个矩形要比第二个矩形大一点点。

Paint的style值如果未设置的话,缺省为FILL。

2.1.1.2 Canvas 类

Canvas 类提供了一系列基本图形的绘制接口,包括点,直线,圆,矩形,贝塞尔曲线等等。除此之外Canvas还提供了其他的相对复杂的功能,包括:画布的几何变换,裁剪,绘制位图,绘制文本等等。本章只介绍基本图形的绘制,其他内容会在后续部分逐步介绍。

首先介绍下画布的坐标系。以左上角为原点,横向为x方向,纵向为y方向,如下图所

示:

(0,0) x

y

所有函数调用的参数都是参照此坐标系设定的。

2.1.2 自定义画布绘制

自定义画布的绘图过程和2.1.1相同,不多做描述。不同之处在于,最后的结果不是绘制到系统提供的画布上,而是绘制到一张位图上。

这里主要给出如何创建画布的过程:

首先创建一张位图:

Bitmap bitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);

然后根据此位图创建画布:

Canvas canvas = new Canvas(bitmap);

即可在此画图上绘制了:

// 在x,y坐标点出绘制点。

canvas.drawPoint(x,y,paint);

2.2 基本形状的绘制

这些基本的图形函数主要在Canvas类中定义,用户可以直接通过一个canvas对象调用这些函数绘制图形。

2.2.1 点

Canvas类中定义了三个画点的函数,分别是:

public void drawPoint (float x, float y, Paint paint), 在坐标点(x,y)处绘制点。点的颜色和大

小有paint参数限定。

其中,Paint setColor 函数定义了点的颜色。setStrokeWidth(float width) 函数定义了点的大小。此处请注意:drawPoint绘制的点其实是一个正方形。正方形的中心点在(x,y),而正方形的边长则是由setStrokeWidth的参数width确定。稍后的例子将会说明这一点。

public void drawPoints (float[] pts, Paint paint),依次绘制有pts数组定义的多个点。其中,pts数组定义了多个点,每两个两个值分别代表一个点,依次为(x,y)。

public void drawPoints (float[] pts, int offset, int count, Paint paint),功能同上。只是并不绘制pts数组中的所有点,而是绘制从offset开始,共计count个值,这里请注意,count是针对pts下标而言,数组中的两个数值才能定义一个点,因此,此处的count值应该为2的倍数。

2.2.2 直线

Canvas中绘制直线的接口也有三个,分别是:

drawLine(float startX, float startY, float stopX, float stopY, Paint paint),绘制一条起点为(startX,startY),终点为(stopX,stopY)的直线。直线的颜色,宽度,线型的特征有paint参数指定。

drawLines(float[] pts, Paint paint)。绘制多条线段。线段的端点在pts数组中定义。此处请注意:pts中定义的线段是不连续的。例如:pts数组共有12个成员,也就是描述了6个点。记为A,B,C,D,E,F,那么调用drawLines的结果得到的只是三条线段AB,CD和EF,而BC和DE之间是没有线段相连的。

drawLines(float[] pts, int offset, int count, Paint paint)。功能同上。只是并不绘制pts数组中的所有点,而是绘制从offset开始的共计count的数值定义的多条线段。注意,因为一条线段需要两个点才能确定,所以此处count值应该为4的倍数。

2.2.3 矩形

Canvas中绘制矩形的接口有四个,分别是:

drawRect(float left, float top, float right, float bottom, Paint paint)。绘制有left,top,right和bottom定义四条边的矩形。

drawRect(RectF rect, Paint paint)。绘制由rect定义的矩形。

drawRect(Rect rect, Paint paint)。绘制由rect定义的矩形。

drawRoundRect(RectF rect, float rx, float ry, Paint paint)。绘制圆角矩形。rx,ry定义弧度在x,y方向的半径。

2.2.4 曲线

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)。定义了一个以oval为外接矩形的椭圆。startAngle为开始角度,sweepAngle为圆弧的角度,这两个参数的单位都是角度,取值为[0,360]。userCenter为ture时,画出的不是一个弧形而是一个扇形。

public void drawCircle (float cx, float cy, float radius, Paint paint) 定义了一个以(cx,cy)为圆心,radius为半径的圆。

drawOval (RectF oval, Paint paint) 定义了一个以oval为外接矩形的椭圆。

2.2.5 基本图形示例

运行效果如下图:

2-2 基本图形的绘制

代码如下:

public class LineArc extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(new SampleView(this));

}

private static class SampleView extends View { private Paint mPaint;

public SampleView(Context context) {

super(context);

setFocusable(true);

mPaint = new Paint();

}

@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE);

drawPoints_1(canvas);

drawPoints_2(canvas);

drawLines_1(canvas);

drawLines_2(canvas);

drawArc_1(canvas);

drawArc_2(canvas);

}

protected void drawPoints_1(Canvas canvas) { Paint paint = mPaint;

int startx = 100;

int starty = 100;

int pixwidth = 30;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(pixwidth);

float[] Pts = new float[2];

Pts[0] = startx;

Pts[1] = startx;

canvas.drawPoints(Pts, paint);

paint.setColor(Color.RED);

RectF r = new RectF();

r.left = 2*startx;

r.top = starty - pixwidth/2;

r.right = r.left + pixwidth;

r.bottom = r.top + pixwidth;

paint.setStyle(Paint.Style.FILL);

canvas.drawRect(r, paint);

}

protected void drawPoints_2(Canvas canvas) { Paint paint = mPaint;

int linecount = 8;

float[] Pts = new float[linecount];

Pts[0] = 100;

Pts[1] = 100;

Pts[2] = 300;

Pts[3] = 100;

Pts[4] = 100;

Pts[5] = 200;

Pts[6] = 300;

Pts[7] = 200;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(30);

canvas.save();

canvas.translate(0, 100);

canvas.drawPoints(Pts, paint);

canvas.restore();

canvas.save();

canvas.translate(300, 100);

paint.setColor(Color.RED);

canvas.drawPoints(Pts,0,4,paint);

canvas.restore();

}

protected void drawLines_1(Canvas canvas) {

Paint paint = mPaint;

float[] Pts = new float[linecount]; Pts[0] = 100;

Pts[1] = 100;

Pts[2] = 300;

Pts[3] = 100;

Pts[4] = 100;

Pts[5] = 200;

Pts[6] = 300;

Pts[7] = 200;

Pts[8] = 100;

Pts[9] = 100;

Pts[10] = 100;

Pts[11] = 200;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(2);

canvas.save();

canvas.translate(0, 300);

canvas.drawLines(Pts, paint);

canvas.restore();

canvas.save();

canvas.translate(300, 300);

canvas.drawLines(Pts,0,8,paint);

canvas.restore();

}

protected void drawLines_2(Canvas canvas) {

Paint paint = mPaint;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(10);

mPaint.setStyle(Paint.Style.STROKE);

paint.setStrokeCap(Paint.Cap.ROUND);

int startX = 100;

int endX = 500;

int endY = 0;

canvas.save();

canvas.translate(0, 600);

canvas.drawLine(startX,startY,endX,endY,paint);

canvas.restore();

startY +=30;

endY += 30;

canvas.save();

canvas.translate(0, 600);

Path path = new Path();

path.reset();

path.moveTo(startX,startY);

path.lineTo(endX, endY);

canvas.drawPath(path, paint);

canvas.restore();

}

protected void drawArc_1(Canvas canvas) {

Paint paint = mPaint;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(10);

mPaint.setStyle(Paint.Style.STROKE);

int xstart = 30;

int ystart = 30;

int width = 300;

int height = 200;

RectF rect = new RectF();

rect.left = xstart;

rect.top = ystart;

rect.right = xstart + width;

rect.bottom = ystart + height;

canvas.save();

canvas.translate(0, 600);

canvas.drawArc(rect,0,180,true, paint);

canvas.restore();

canvas.save();

canvas.translate(350, 600);

paint.setColor(Color.RED);

canvas.drawArc(rect,0,180,false, paint);

canvas.restore();

}

protected void drawArc_2(Canvas canvas) {

Paint paint = mPaint;

paint.setColor(Color.BLUE);

paint.setStrokeWidth(10);

mPaint.setStyle(Paint.Style.STROKE);

int xstart = 30;

int ystart = 30;

int width = 300;

int height = 200;

RectF rect = new RectF();

rect.left = xstart;

rect.top = ystart;

rect.right = xstart + width;

rect.bottom = ystart + height;

canvas.save();

canvas.translate(0, 850);

canvas.drawOval(rect, paint);

canvas.restore();

canvas.save();

canvas.translate(350, 850);

paint.setColor(Color.RED);

canvas.drawCircle(100, 100, 80, paint);

canvas.restore();

}

}

}

3. 路径(Path)与剪裁(Clipping)

路径是封装了多条几何轮廓的组合。其中可以包含线段,圆,椭圆,二次和三次的贝塞尔曲线。路径的主要应用场景有:绘制复杂的轮廓,也可以通过这些路径进行剪裁,或者在路径上显示文字。

3.1 路径(Path)

3.1.1 绘制复杂轮廓

使用路径可以轻易的生成一段复杂的曲线,因为Path类提供了丰富的函数来实现此功能。下面罗列并简要解释下这些函数。

public void addArc(RectF oval, float startAngle, float sweepAngle)。向路径中添加椭圆弧,此椭圆弧的位置由外接矩形oval定义。startAngle定义开始的角度。sweepAngle定义弧线扫描过的角度。

public void addCircle(float x, float y, float radius, Path.Direction dir)。向路径中添加圆。(x,y)定义圆心的位置。raidus定义圆的半径。dir定义了圆加入路径时的方向。方向由枚举类Path.Direction定义。此参数只用于加入路径的封闭曲线中。

https://www.doczj.com/doc/fb8359119.html,W 逆时针方向。

Path.Direction.CW 顺时针方向。

public void addOval(RectF oval, Path.Direction dir)。向路径中添加椭圆。oval定义了椭圆的位置和大小。Path.Direction 定义了椭圆加入路径时的方向。

public void addPath(Path src, float dx, float dy)。将一段路径加入当前路径。(dx,dy)定义了原路径的偏移量。

public void addPath(Path src)。将src所指路径加入当前路径。

public void addPath (Path src, Matrix matrix)。将src所指路径加入当前路径。用matrix所指矩阵进行变换。(变化应用于src还是添加src后的全路径?)

public void addRect(float left, float top, float right, float bottom, Path.Direction dir)。向路径中添加矩形。

public void addRect(RectF rect, Path.Direction dir)。向路径中添加矩形。

public void addRoundRect(RectF rect, float[] radii, Path.Direction dir)。向路径中添加圆角矩形。radii数组定义圆角矩形的四个圆角的x,y半径。radii长度必须为8。

public void addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)。想路径中添加圆角矩形。rx,ry定义了四个圆角的x,y半径。

public void arcTo(RectF oval, float startAngle, float sweepAngle)。向路径中添加一段椭圆弧。arcTo和addArc的区别在于:

1. 首先,使用addArc可以直接加入一段椭圆弧。而使用arcTo还需要使用moveTo指定当前点的坐标。

2. 对于arcTo来说,如果当前点坐标和欲添加的曲线的起始点不是同一个点的话,还会自动添加一条直线补齐路径。

public void moveTo(float x, float y)。移动当前点到(x,y)。

public void rMoveTo(float dx, float dy)。

public void lineTo(float x, float y)。从当前路径结束点添加一条路径到指定点(x,y)。

public void rLineTo(float dx, float dy)。同LineTo,区别在于LineTo中的(x,y)是对应于坐标原点。而此处(dx,dy)是对应于路径结束点的相对坐标。其他r*函数都类似。

public void quadTo(float x1, float y1, float x2, float y2)。以当前路径结束点为开始点,(x1,y1)为控制点,(x2,y2)为结束点画一条二次贝塞尔曲线。

public void rQuadTo(float dx1, float dy1, float dx2, float dy2)。同quadTo。

public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)。以当前路径结束点为开始点,(x1,y1),(x2,y2)为控制点,(x3,y3)为结束点画一条三次贝塞尔曲线。

public void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)。同cubicTo。

下面是相关示例代码和运行效果截图:

相关主题
文本预览
相关文档 最新文档