我们都知道一个App的成败,首先取决于是否具有优秀的UI,而除了交互功能之外还需要丰富的图片背景和动画去支撑。在开发中我们应用到的图片不仅仅包括.png、.gif、.9.png、.jpg和各种Drawable系对象,还包括位图Bitmap,而且图片的处理也经常是影响着一个程序的高效性和健壮性。
一、Bitmap概述
Bitmap代表一张位图,扩展名可以是.bmp或者.dib。位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2、4、8、16、24和32位色彩。例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/8=3072KB,虽然位图文件图像效果好,但是非压缩格式的,需要占用较大存储空间,不利于在网络上传送Android系统当中,Bitmap是图像处理最重要的中转类之一。用它可以获取图像文件信息,借助Matrix进行图像剪切、旋转、缩放等操作,再以指定格式保存图像文件。
二、构造Bitmap对象
通常我们构造一个类的对象,都是可以通过其对应的构造方法。然而Bitmap是采用了工厂的设计模式,所以一般不会直接调用构造方法。
1、通过Bitmap的静态方法static Bitmap createBitmap()系
方法名(只列出部分方法) | 用法说明 |
---|---|
createBitmap(Bitmap src) | 复制位图 |
createBitmap(Bitmap src,int x ,int y,int w,int h) | 从源位图src的指定坐标(x,y)开始,截取宽w,高h的部分,用于创建新的位图对象 |
createScaledBitmap(Bitmap src,int w ,int h,boolean filter) | 对源位图src缩放成宽为w,高为h的新位图 |
createBitmap(int w ,int h,Bitmap.Config config) | 创建一个宽w,高h的新位图(config为位图的内部配置枚举类) |
createBitmap(Bitmap src,int x ,int y,int w,int h,Matrix m,boolean filter) | 从源位图src的指定坐标(x,y)开始,截取宽w,高h的部分,按照Matrix变换创建新的位图对象 |
2、通过BitmapFactory工厂类的static Bitmap decodeXxx()系
方法名(只列出部分方法) | 参数及解释 |
---|---|
decodeByteArray(byte[] data, int offset, int length) | 从指定字节数组的offset位置开始,将长度为length的数据解析成位图 |
decodeFile(String pathName) | 从pathName对应的文件解析成的位图对象 |
decodeFileDescriptor(FileDescriptor fd) | 从FileDescriptor中解析成的位图对象 |
decodeResource(Resource res,int id) | 根据给定的资源Id解析成位图 |
decodeStream(InputStream in) | 把输入流解析成位图 |
三、Bitmap相关类之Path、Matrix
1、Path类的应用
有使用PS经验的都知道”路径”这么一个概念,可以把几个点连成一条“路径”,Android里的Path也是如此。在实际应用中我们可以调用Canvas的drawPath方法即可绘制图形,为了实现丰富的绘制效果,Android还定义了一个PathEffect系列类(ComposePathEffect, CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect)
1.1、Path类的构造方法
Path(); Path(Path src);
1.2、Path类的一些常用方法
部分方法 | 用法说明 |
---|---|
public void addArc (RectF oval, float startAngle, float sweepAngle) | 绘制弧形路径 |
public void addCircle (float x, float y, float radius, Path.Direction dir) | 绘制圆形路径 |
public void addOval (RectF oval, Path.Direction dir) | 绘制椭圆路径 |
public void lineTo (float x, float y) | 把(x,y)连接到一起成为一条折线 |
public void moveTo (float x, float y) |
1.3、Path的实际应用
绘制跟随路径显示的字符串
package com.crazymo.graphicsdemo; public class MyPathView extends View { final String STR_TITLE="跟随路径显示的字符串"; Path[] paths=new Path[3]; Paint paint; public MyPathView(Context ctx){ super(ctx); paths[0]=new Path(); paths[0].moveTo(0,0); for(int i=1;i<7;i++){ //随机生成7个点的Y坐标并将他们炼成一条路径 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.GREEN); 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(STR_TITLE, paths[0], -8, 20, paint);//沿着路径绘制文字 //画布下移120 canvas.translate(0,60); paint.setStyle(Paint.Style.STROKE); canvas.drawPath(paths[1], paint); paint.setStyle(Paint.Style.FILL); canvas.drawTextOnPath(STR_TITLE, 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(STR_TITLE,paths[2],-10,20,paint); } }
2、使用Matrix控制图片和View的平移、旋转、缩放等。
2.1、构造Matrix对象
public Matrix(); public Matrix(Matrix src);
2.2、Matrix一些常用的方法
部分方法 | 用法说明 |
---|---|
public void setTranslate(float dx, float dy) | 绘制弧形路径 |
public void setSkew(float kx, float ky, float px, float py) | 控制Matrix以(px,py)为轴心进行倾斜,kx,ky为X,Y方向上的倾斜距离 |
public void setSkew(float px, float py) | kx,ky为X,Y方向上的倾斜距离 |
public void setRotate(float degree) | 控制Matrix旋转degree度 |
public void setRotate(float degree,float px,float py) | 控制Matrix以轴心(px,py)旋转degree度 |
setScale(float sx, float sy, float px, float py) | 控制Matrix以(px,py)为轴心缩放,sx,sy为X,Y方向上的缩放距离 |
void setScale(float sx, float sy) |
2.3、Marix的简单应用
自定义一个使用Matrix的View
/** * Created by cmo on 16-4-1. */ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; public class CostomView extends View { private Bitmap mBitmap; private Matrix matrix; public CostomView(Context context) { super(context); matrix = new Matrix(); } public CostomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); matrix = new Matrix(); } public CostomView(Context context, AttributeSet attrs) { super(context, attrs); matrix = new Matrix(); } public Bitmap getmBitmap() { return mBitmap; } public void setmBitmap(Bitmap mBitmap) { this.mBitmap = mBitmap; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mBitmap != null) { canvas.drawBitmap(mBitmap, matrix, null); } } public void rotate(float degree) { if (mBitmap != null) { matrix.preRotate(degree, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); invalidate(); } } //平移 public void translate(float dx, float dy) { if (mBitmap != null) { matrix.postTranslate(dx, dy); invalidate(); } } //缩放 public void scale(float sx, float sy) { if (mBitmap != null) { matrix.postScale(sx, sy); invalidate(); } } //镜像(相当于是照镜子里的自己) public void mirror() { if (mBitmap != null) { matrix.postScale(-1, 1); matrix.postTranslate(mBitmap.getWidth(), 0); invalidate(); } } //倒影 public void shadow() { if (mBitmap != null) { matrix.postScale(1, -1); matrix.postTranslate(0, mBitmap.getHeight()); invalidate(); } } public void skew(float kx, float ky){ if (mBitmap != null) { matrix.postSkew(kx, ky); invalidate(); } } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.crazymo.matrixdemo.CostomView android:id="@+id/costomview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_translate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="平移"/> <Button android:id="@+id/btn_scale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="缩放"/> <Button android:id="@+id/btn_rotate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="旋转"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_skew" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="倾斜"/> <Button android:id="@+id/btn_mirro" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="镜像"/> <Button android:id="@+id/btn_shadow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="倒影"/> </LinearLayout> </LinearLayout>
package com.crazymo.matrixdemo; /** * Created by cmo on 16-4-1. */ public class CostViewActivity extends Activity { private CostomView mCostomView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_cotomview); mCostomView = (CostomView) findViewById(R.id.costomview); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bcg); mCostomView.setmBitmap(bitmap); ((Button) findViewById(R.id.btn_rotate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.rotate(15); } }); ((Button) findViewById(R.id.btn_scale)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.scale(1.8f, 1.8f); } }); ((Button) findViewById(R.id.btn_translate)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.translate(100, 100); } }); ((Button) findViewById(R.id.btn_skew)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.skew(-0.3f, 0.3f); } }); ((Button) findViewById(R.id.btn_mirro)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.mirror(); } }); ((Button) findViewById(R.id.btn_shadow)) .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCostomView.shadow(); } }); } }
四、Bitmap的简单应用
1、从资源文件中获取Bitmap
Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.bcg);
2、从SD卡里获取Bitmap
String SDCarePath=Environment.getExternalStorageDirectory().toString(); String filePath=SDCarePath+"/"+"demo.jpg"; Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePath, null);
InputStream inputStream=getBitmapInputStreamFromSDCard("demo.jpg"); Bitmap rawBitmap2 = BitmapFactory.decodeStream(inputStream);
3、设置图片的圆角,返回设置后的Bitmap
public Bitmap toRoundCorner(Bitmap bitmap, int pixels) { Bitmap roundCornerBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(roundCornerBitmap); int color = 0xff424242;// int color = 0xff424242; Paint paint = new Paint(); paint.setColor(color); // 防止锯齿 paint.setAntiAlias(true); Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); RectF rectF = new RectF(rect); float roundPx = pixels; // 相当于清屏 canvas.drawARGB(0, 0, 0, 0); // 先画了一个带圆角的矩形 canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); // 再把原来的bitmap画到现在的bitmap!!!注意这个理解 canvas.drawBitmap(bitmap, rect, rect, paint); return roundCornerBitmap; }
4、将图片高宽和的大小kB压缩
//得到图片原始的高宽 int rawHeight = rawBitmap.getHeight(); int rawWidth = rawBitmap.getWidth(); // 设定图片新的高宽 int newHeight = 500; int newWidth = 500; // 计算缩放因子 float heightScale = ((float) newHeight) / rawHeight; float widthScale = ((float) newWidth) / rawWidth; // 新建立矩阵 Matrix matrix = new Matrix(); matrix.postScale(heightScale, widthScale); // 设置图片的旋转角度 // matrix.postRotate(-30); // 设置图片的倾斜 // matrix.postSkew(0.1f, 0.1f); // 将图片大小压缩 // 压缩后图片的宽和高以及kB大小均会变化 Bitmap newBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawWidth,rawWidth, matrix, true);
5、将Bitmap转换为Drawable Drawable转Bitmap
Drawable newBitmapDrawable = new BitmapDrawable(Bitmap); //如果要获取BitMapDrawable中所包装的BitMap对象,可以用getBitMap()方法; Bitmap bitmap = newBitmapDrawable.getBitmap();