Android图像处理

《Android群英传》第六章读书笔记

Posted by wushiqian on October 5, 2018

Android图像处理

《android群英传》第六章读书笔记

1.屏幕尺寸的信息:

屏幕参数有屏幕大小即屏幕对角线的长度,用“寸”来表示、分辨率、PPI即每英寸像素,它由对角线的像素点除以屏幕大小获得。 系统屏幕密度如下

  • ldpi—120—240X320分辨率
  • mdpi—160—320X480分辨率
  • hdpi—240—480X800分辨率
  • xhdpi—320—720X1280分辨率
  • xxhdpi—480—1080X1920分辨率

2.单位转换工具类

实现dip转换为px,sp转换pd,px转换为dip

/**
   * dip转换px
   *
   * @param context 上下文
   * @param dpValue dip值
   * @return px值
   */
  public static int dip2px(Context context, float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
  }

  /**
   * sp转pd
   *
   * @param context 上下文
   * @param spValue sp值
   * @return px值
   */
  public static int sp2px(Context context, float spValue) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue,
        context.getResources().getDisplayMetrics());
  }

  /**
   * px转换dip
   *
   * @param context 上下文
   * @param pxValue px值
   * @return dip值
   */
  public static int px2dip(Context context, float pxValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
  }

3.2D绘图基础:

Paint类的一些属性和对应的功能:

  • setAntiAlias(); //设置画笔的锯齿效果
  • setColor(); //设置画笔的颜色
  • setARGB(); //设置画笔的A,R,G,B的值
  • setAlpha(); //设置画笔的Alpha值
  • setTextSize(); //设置字体的尺寸
  • setStyle(); //设置画笔的风格(空心或者实心)
  • setStrokeWidth(); //设置空心边框的宽度

Canvas类主要的绘画功能:

  • canvas.drawPoint(x,y,paint);//绘制点
  • canvas.drawLine(startX,startY,endX,endY,paint);//绘制直线
  • canvas.drawRect(left,top,right,bottom,paint);//绘制矩形
  • canvas.drawRoundRect(left,top,right,bottom,radiusX,radiusY,paint);//绘制圆角矩形
  • canvas.drawCircle(circleX,circleY,radius,paint);//绘制圆
  • canvas.drawOval(left,top,right,bottom,paint);//通过椭圆的外接矩形来绘制椭圆
  • canvas.drawText(text,startX,startY,paint);//绘制文字
  • canvas.drawPosText(text,new float[]{x1,y1,…,xn,yn},paint);//指定位置绘制文本
//绘制多条直线
float[] pts={
startX1,startY1,endX1,endY1
......
startXn,startYn,endXn,endYn}
canvas.drawLines(pts,paint);
//绘制路径
Path path=new Path();
path.moveTo(50,50);
path.lineTo(100,100);
path.lineTo(300,50);
canvas.drawPath(path,paint)
//绘制弧形或扇形
canvas.drawArc(left,top,right,bottom,startAngle,sweepAngle,useCenter,paint);

这里 useCenter 传入true 则绘制扇形 反之绘制弧形

4.Android的Xml绘图:

Bitmap:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
  android:src="@drawable/ic_launcher"/>

这样就能直接将图片转成bitmap在程序中使用了 Shape:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="line|oval|ring|rectangle">
  <!--默认为rectangle-->
  <corners
      android:bottomLeftRadius="integer"
      android:bottomRightRadius="integer"
      android:radius="integer"
      android:topLeftRadius="integer"
      android:topRightRadius="integer" />
  <!--当shape为rectangle时才有,radius默认为1dp-->

  <gradient
      android:angle="integer"
      android:centerColor="color"
      android:centerX="integer"
      android:centerY="integer"
      android:endColor="color"
      android:gradientRadius="integer"
      android:startColor="color"
      android:type="linear|radial|sweep"
      android:useLevel="boolean" />

  <padding
      android:bottom="integer"
      android:left="integer"
      android:right="integer"
      android:top="integer" />

  <size
      android:width="integer"
      android:height="integer" />
  <!--指定大小,一般用在imageview配合scaleType使用-->

  <solid android:color="color" />
  <!--填充颜色-->
  <stroke
      android:width="integer"
      android:color="color"
      android:dashGap="integer"
      android:dashWidth="integer" />
  <!--边框,dashGap为虚线间隔宽度,dashWidth为虚线宽度-->
</shape>

Layer:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@mipmap/ic_launcher" />
  <item
      android:drawable="@mipmap/ic_launcher"
      android:left="10dp"
      android:top="10dp" />
  <item
      android:drawable="@mipmap/ic_launcher"
      android:left="20dp"
      android:top="20dp" />
</layer-list>

Selector: 通常用于view的触摸反馈

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true">
      <shape android:shape="rectangle">
          <solid android:color="#334444" />
      </shape>
  </item>
  <item android:state_pressed="false">
      <shape android:shape="rectangle">
          <solid android:color="#444444" />
      </shape>
  </item>
</selector>

5.Android绘图技巧:

  • canvas.save():保存之前在画布上的操作,之后的操作就像是在新的图层操作一样。
  • canvas.restore():可以理解为Photoshop中合并图层的操作,作用是将save后的图层与之前的图层合并。
  • canvas.translate():将画布进行平移。
  • canvas.rotate():将画布进行旋转。这两个方法都是用来简化绘图而创建的。
  • canvas.saveLayer():创建一个图层,并将他加入一个图层的栈,通过调用restore或者restoreToCount使其出栈,出栈后会把图像绘制到上层canvas上。
  • canvas.saveLayerAlpha():同上,区别是可以设置图层的透明度

6.Android色彩特效处理:

图像的色调、饱和度、亮度这三个属性在图像处理中使用非常之多,Android封装了一个ColorMatrix类(颜色矩阵),通过改变矩阵值来处理这些属性。

色调:

//第一个参数分别为red、green、blue 第二个参数为要处理的值。
ColorMatrix hueMatrix=new ColorMatrix();
      hueMatrix.setRotate(0, hue);
      hueMatrix.setRotate(1, hue);
      hueMatrix.setRotate(2, hue);

饱和度:

//参数即为饱和度,当饱和度为0时图像就变成灰图像了。
ColorMatrix saturationMatrix=new ColorMatrix();
      saturationMatrix.setSaturation(saturation);

亮度:

//当三原色以相同比例进行混合的时候,就会显示出白色,从而调节亮度。
ColorMatrix lumMatrix=new ColorMatrix();
      lumMatrix.setScale(lum, lum, lum, 1);

让三种效果叠加:

ColorMatrix imageMatrix=new ColorMatrix();
imageMatrix.postConcat(hueMatrix);
imageMatrix.postConcat(saturationMatrix);
imageMatrix.postConcat(lumMatrix);

7.Android图形特效处理:

通过Matrix类来操作图形矩阵的变换

private float[] mImageMatrix=new float[9];
Matrix matrix=new Matrix();
matrix.setValues(mImageMatrix);
//当获得一个变换矩阵以后通过以下代码将一个图像以这个变换矩阵的形式绘制出来
canvas.drawBitmap(mBitmap,matrix,null);

以下是一些变换的方法:

  • setScale(); 缩放变换
  • setSkew(); 错切变换
  • setRotate(); 旋转变换
  • setTranslate(); 平移变换
  • pre()和post() 提供矩阵的前乘和后乘运算

8.Android画笔特效:

  • PorterDuffXfermode: 这里要注意的是,PorterDuffXfermode设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形。比较常用的是DST_IN和SRC_IN模式来实现一个圆角图形。
private Bitmap getRoundPic() {
      //原图
      Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.head1);
      //创建一个和原图一样宽高的图片
      Bitmap out = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
      //构造画布  
      Canvas canvas = new Canvas(out);
      //初始化画笔
      Paint paint = new Paint();
      paint.setAntiAlias(true);
      //绘制形状
      canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, Math.min(bitmap.getWidth() / 2, bitmap.getHeight() / 2), paint);
      //设置paint的xfermode
      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
      //把原图绘制上去
      canvas.drawBitmap(bitmap, 0, 0, paint);
      //返回新创建的bitmap,即圆形图标。
      return out;
  }
  • Shader: Shader也被称之为着色器、渲染器,它用来实现一些列的渐变、渲染的效果。

BitmapShader — 位图Shader LinearGradient — 线性Shader RadialGradient — 光束Shader SweepGradient — 梯度Shader ComposeShader — 混合Shader 除第一个Shader以外 其他Shader都实现了名副其实的渐变。BitmapShader产生的是一个位图,它的作用就是通过Paint对画布进行指定Bitmap的填充,填充有以下几种模式可以选择: CLAMP拉伸 — 拉伸的是图片最后一个像素 不断重复 REPEAT重复 — 横向纵向不断重复 MIRROR镜像 — 横向不断旋转重复,纵向不断旋转重复

9.SurfaceView:

与view的区别:

  • View主要适用于主动更新的情况下,而SurfaceView 主要适用于被动更新,例如频繁的刷新。
  • View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面刷新。
  • View在绘图时没有使用双缓冲机制,而SurfaceView在底层实现机制中就已经实现了双缓冲。 以下是SurfaceView的模板代码:
public class MySurfaceView extends SurfaceView implements Runnable, SurfaceHolder.Callback {
  //SurfaceHolder
  private SurfaceHolder mSurfaceHolder;
  //用于绘图的Canvas
  private Canvas mCanvas;
  //子线程标志位
  private boolean mIsDrawing;

  public MySurfaceView(Context context) {
      super(context);
      init();
  }
  public MySurfaceView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init();
  }
  public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init();
  }
  private void init() {
      mSurfaceHolder = getHolder();
      mSurfaceHolder.addCallback(this);
      setFocusable(true);
      setFocusableInTouchMode(true);
      this.setKeepScreenOn(true);
//        mSurfaceHolder.setFormat(PixelFormat.OPAQUE);
  }
  @Override
  public void surfaceCreated(SurfaceHolder holder) {
      mIsDrawing = true;
      new Thread(this).start();
  }
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  }
  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
      mIsDrawing = false;
  }
  @Override
  public void run() {
      while (mIsDrawing) {
          draw();
      }
  }
  private void draw() {
      try {
          //每次获得的canvas对象都是上次的 因此上次的绘画操作都会保存
          mCanvas = mSurfaceHolder.lockCanvas();
          //draw here
      } catch (Exception e) {

      } finally {
          if (mCanvas != null) {
              mSurfaceHolder.unlockCanvasAndPost(mCanvas);
          }
      }

  }
}