Android的图形与图像处理之一 使用简单图片&绘图

本文详细介绍了Android应用开发中利用Canvas、Paint等API进行绘图及Canvas提供的绘图方法,包括坐标变换、绘制路径、Path类、PathEffect类以及如何在路径上绘制文本。同时,文章阐述了如何实现游戏动画,包括事件监听、状态数据管理及使用Timer控制动画变化。特别强调了双缓冲技术在保留用户绘制内容时的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

R.drawable.file_name是一个int常量,若想获取实际的Drawable对象,可调用Resource的getDrawable(int id)获取


Bitmap与BitmapFactory
BitmapDrawable里封装的图片就是一个Bitmap对象,封装方法如下:
BitmapDrawable drawable = new BitmapDrawable(bitmap);
如果要获取BitmapDrawable所包装的Bitmap对象,则可调用BitmapDrawable的getBitmap()方法,示例如下:
Bitmap bitmap = drawable.getBitmap();
Bitmap还提供了一些静态方法来创建新的Bitmap对象,如下:
createBitmap(Bitmap source, int x, int y, int width, int height)
从源位图source的指定坐标开始,从中挖取width*height的一块来创建新Bitmap
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
对源位图进行缩放,缩放成(dstWidth*dstHeight)的新位图
createBitmap(int width, int height, Bitmap.Config config)
创建一个宽width、高height的新位图
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
从源位图挖取一块指定宽高创建Bitmap对象,并按Matrix指定的规则变换
BitmapFactory包含大量方法
decodeByteArray(byte[] data, int offset, int length)
从指定字节数组的offset开始,将长度为length的字节数据解析成Bitmap对象
decodeFile(String pathName)
从pathName指定的文件中解析创建Bitmap对象
decodeFileDescriptor(FileDescriptor fd)
用于从FileDescriptor对应的文件
decodeResource(Resources res, int id)
根据给定资源ID从指定资源解析、创建
decodeStream(InputStream is)
从指定流中解析、创建
通常做法是把图片放在/res/drawabe-hdpi目录下,程序通过ID来获取对象。如果系统不停的去解析、创建Bitmap对象,可能由于前面创建Bitmap所占内存还没有回收,而导致程序发生OutOfMemory错误,为此设计了如下方法:
boolean isRecycled():返回是否已被回收
void recycle():强制一个Bitmap对象以及回收自己


绘图
Canvas、Paint
Android的绘图继承View组件,并重写它的onDraw(Canvas canvas)方法
API Canvas代表依附于指定View画布,它有如下方法:
除了上述方法外,Canvas还提供如下方法进行坐标变换:
rotate(float degrees,float px, float py)
对Canvas执行旋转变换
scale(float sx, float sy, float sy,float px, float py)
对Canvas执行缩放变换
skew(float sx, float sy)
对Canvas执行倾斜变换
translate(float dx, float dy)
移动Canvas。向右移动dx距离(dx为负则向左),向下移动dy距离(dy为负则向上)
Canvas提供上面的方法还涉及一个API:Paint,Paint代表了Canvas上的画笔,用于设置绘制风格
Paint常用方法:
setARGB(int a, int r, int g, int b)setColor(int color)
设置颜色
setAlpha(int a)
设置透明度
setAntiAlias(boolean aa)
设置是否抗锯齿
setColor(int color)

setPathEffect(PathEffect effect)
设置绘制路径时的路径效果
setShader(Shader shader)
设置画笔的填充效果
setShadowLayer(float radius, float dx, float dy, int color)
设置阴影
setStrokeWidth(float width)
设置画笔的笔触宽度
setStrikeJoin(Paint.Join join)
设置画笔转弯处的连接风格
setStyle(Paint.Style style)
设置Paint的填充风格
setTextAlign(Paint.Align align)
设置绘制文本时文字的对齐方式
setTextSize(float textSize)
大小
Canvas提供的绘制方法中还有一个API:Path,Path代表任意多条直线连接而成的任意图形,当Canvas根据Path绘制图形,它可以绘制出任意形状。还可以自定义一个View组件,重写它的onDraw(Canvas)方法。
Canvas不仅可以绘制简单图形,还可以直接将一个Bitmap绘制到画布上,这是极大的分工方便
下面详解Path类
Android还为路径绘制提供了PathEffect来定义绘制效果,PathEffect包含如下子类:
  • ComposePathEffect
  • CornerPathEffect
  • DashPathEffect
  • DiscretePathEffect
  • PathDashPathEffect
  • SumPathEffect
示例代码:
main.xml
public class PathTest extends ActionBarActivity {

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(
new MyView(this));
    }
   
class MyView extends View
    {
   
float phase;
    PathEffect[]
effects = new PathEffect[7];
   
int[] colors;
   
private Paint paint;
    Path
path;
   
public MyView(Context context)
    {
   
super(context);
   
paint = new Paint();
   
paint.setStyle(Paint.Style.STROKE);
   
paint.setStrokeWidth(4);
   
path = new Path();
   
path.moveTo(0,0);
   
for(int i =1; i<= 15; i++)
    {
   
path.lineTo(i*20, (float)Math.random()*60);
    }
   
colors = new int[]{Color.BLACK,Color.BLUE, Color.CYAN
    , Color.
GREEN, Color.MAGENTA, Color.RED, Color.YELLOW};
    }
   
@Override
   
protected void onDraw(Canvas canvas)
    {
    canvas.drawColor(Color.
WHITE);
   
effects[0]= null;
   
effects[1] = new CornerPathEffect(10);
   
effects[2] = new DiscretePathEffect(3.0f, 5.0f);
   
effects[3] = new DashPathEffect(new float[]{20,10,5,10}, phase);
    Path p =
new Path();
    p.addRect(0,0,8,8,Path.Direction.
CCW);
   
effects[4] = new PathDashPathEffect(p,12,phase,
    PathDashPathEffect.Style.
ROTATE);
   
effects[5] = new ComposePathEffect(effects[2],effects[4]);
   
effects[6] = new SumPathEffect(effects[4],effects[3]);
    canvas.translate(8, 8);
   
for(int i = 0; i<effects.length; i++)
    {
   
paint.setPathEffect(effects[i]);
   
paint.setColor(colors[i]);
    canvas.drawPath(
path,paint);
    canvas.translate(0, 60);
    }
   
phase += 1;
    invalidate();
    }
    }
}
此外,Android的Canvas还提供了一个drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)方法,该方法可以沿着Path绘制文本。
示例代码如下:
main.xml
public class PathTest extends ActionBarActivity {

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(
new TextView(this));
//        setContentView(new MyView(this));
    }
   
class TextView extends View
    {
   
final String DRAW_STR = "android java";
    Path[]
paths = new Path[3];
    Paint
paint;
   
public TextView(Context context)
    {
   
super(context);
   
paths[0] = new Path();
   
paths[0].moveTo(0, 0);
   
for(int i = 1; i<= 7;i++)
    {
   
paths[0].lineTo(i * 30, (float) Math.random() * 30);
    }
   
paths[1] = new Path();
    RectF rectF =
new RectF(0,0,200,120);
   
paths[1].addOval(rectF,Path.Direction.CCW);
   
paths[2] = new Path();
   
paths[2].addArc(rectF, 60, 180);
   
paint = new Paint();
   
paint.setAntiAlias(true);
   
paint.setColor(Color.CYAN);
   
paint.setStrokeWidth(1);
    }
   
@Override
   
protected void onDraw(Canvas canvas)
    {
    canvas.drawColor(Color.
WHITE);
    canvas.translate(40, 40);
   
paint.setTextAlign(Paint.Align.RIGHT);
   
paint.setTextSize(20);
   
paint.setStyle(Paint.Style.STROKE);
    canvas.drawPath(
paths[0], paint);
   
paint.setStyle(Paint.Style.FILL);
    canvas.drawTextOnPath(
DRAW_STR, paths[0],-8,20,paint);
    canvas.translate(0, 60);
   
paint.setStyle(Paint.Style.STROKE);
    canvas.drawPath(
paths[1], paint);
   
paint.setStyle(Paint.Style.FILL);
    canvas.drawTextOnPath(
DRAW_STR, paths[1], -20, 20, paint);
    canvas.translate(0, 120);
   
paint.setStyle(Paint.Style.STROKE);
    canvas.drawPath(
paths[2], paint);
   
paint.setStyle(Paint.Style.FILL);
    canvas.drawTextOnPath(
DRAW_STR, paths[2], -10, 20, paint);
    }
    }
}


绘制游戏动画
动画其实就是不断地重复调用View组件的onDraw(Canvas canvas)方法
如果要View上绘制的图形发生部分改变,就需要程序采用变量来“记住”这些状态数据;
如果需要游戏动画随着用户操作而改变,就需要为用户动作编写事件监听器;
如果需要游戏动画自动改变,就需要使用Timer控制状态数据修改;

绘图中,为了保留用户之间绘制的内容,程序需要借助“双缓冲”技术。
(双缓冲:当程序需要在指定View上进行绘制时,程序并不直接绘制到该View组件上,而是先绘制到一个内存中的Bitmap上,等到内存中的Bitmap绘制好之后,再一次性将Bitmap绘制到View组件上)
### Android 平台上图形图像处理技术 #### 1. 基础概念 在 Android 开发中,`Canvas` 和 `Paint` 是核心组件之一,用于实现各种绘图功能。`Canvas` 提供了一个虚拟的画布,开发者可以在其上绘制几何形状、文本以及位图等内容;而 `Paint` 则类似于现实世界的画笔,它决定了绘制的内容的具体样式和属性。 - **Canvas 的作用** `Canvas` 类提供了多种方法来完成不同的绘制操作,例如绘制圆圈 (`drawCircle`)、矩形 (`drawRect`)、弧线 (`drawArc`) 等[^2]。 - **Paint 的作用** `Paint` 类负责定义绘制时使用的颜色、线条宽度、透明度以及其他视觉效果。通过调整这些参数,可以控制最终呈现的效果[^5]。 #### 2. 几何图形绘制 利用 `Canvas` 可以轻松地绘制常见的二维几何图形: ```java public class CustomView extends View { public CustomView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.BLUE); // 设置蓝色作为填充色 // 绘制一个圆形 canvas.drawCircle(100, 100, 50, paint); // 修改画笔颜色并绘制一条直线 paint.setColor(Color.GREEN); canvas.drawLine(0, 0, 200, 200, paint); // 使用红色绘制一个矩形 paint.setColor(Color.RED); canvas.drawRect(new RectF(50, 50, 150, 150), paint); } } ``` 上述代码展示了如何在一个自定义视图中分别绘制圆形、直线和矩形[^4]。 #### 3. 文本绘制 除了几何图形外,还可以借助 `Canvas.drawText()` 方法向界面添加文字内容。下面是一个简单例子: ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize(30f); textPaint.setColor(Color.BLACK); String message = &quot;Hello Android!&quot;; float xPosition = getWidth() / 2; float yPosition = getHeight() / 2; canvas.drawText(message, xPosition, yPosition, textPaint); } ``` 这段代码实现了居中文本显示,并设置了字体大小和其他外观特性[^3]。 #### 4. 图像处理 对于更复杂的场景比如加载外部图片资源或者对现有图片施加变换,则需要用到 Bitmap 对象配合 Matrix 进行矩阵运算。以下是一段关于旋转图片的例子: ```java Matrix matrix = new Matrix(); matrix.postRotate(90); Bitmap originalImage = BitmapFactory.decodeResource(getResources(), R.drawable.sample_image); Bitmap rotatedImage = Bitmap.createBitmap(originalImage , 0, 0, originalImage.getWidth(), originalImage.getHeight(), matrix, true); canvas.drawBitmap(rotatedImage, 0, 0, null); ``` 这里先构建了一个表示顺时针方向转动九十度角变化规则的对象实例化过程之后再调用 createBitmap 创建新的经过转换后的版本最后将其渲染到屏幕上[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值