在上一节中对Android中的13种类型的Drawable的类型进行了讲解,有没有应用到自己的项目当中呢?而 探讨的是Bitmap(位图)的使用,而在开始本节的内容之前先来区分几个名词的概念

  • Drawable通用的图形对象,用于装载常用格式的图像,既可以是PNG,JPG这样的图像,也是前面学的那13种Drawable类型的可视化对象!可以理解成个用来放画的——画框
  • Bitmap(位图)可以把他看作个画架,先把画放到上面,然后可以进行处理,比如获取图像文件信息,做旋转切割,放大缩小等操作!
  • Canvas(画布)如其名,画布,可以在上面作画(绘制), 既可以用Paint(画笔),来画各种形状或者写字,又可以用Path(路径)来绘制多个点,然后连接成各种图形!
  • Matrix(矩阵)用于图形特效处理的,颜色矩阵(ColorMatrix),还有使用Matrix进行图像的平移,缩放,旋转,倾斜等!

而上述的这些都是Android中的底层图形类android.graphics给提供的接口! 话不多说开始本节内容!PS官方文档Bitmap


1.了解Bitmap,BitmapFactory,BitmapFacotry.Options

如题,本来可以直接说着三个东东的关系的,但是就是要傲娇,就要看代码!若 打开Bitmap类的源码, 会看到Bitmap的构造方法上有这样一段东东

大概想说的就是Bitmap的构造方法是私有的,外面不能实例化,只能通过JNI实例化! 肯定也会给提供个接口给来创建Bitmap的,而这个接口类就是BitmapFactory!来来来,打开BitmapFactory类,点下左边的Structure可以看到BitmapFactory给提供了这些方法,大部分都是decodeXxx,通过各种形式来创建Bitmap的!

接着又发现了,每一种方法,都会有个Options类型的参数,点进去看看于是乎发现了这货是个静态内部类:BitmapFacotry.Options!而他是用来设置decode时的选项的!

对这里的某些参数的值进行设置,比如inJustDecodeBounds设置为true避免OOM(内存溢出),什么,不知道OOM,没事,等下一点点跟 说清楚!最后回到的Bitmap! Bitmap中的方法比较多,就不一一进行讲解了,从中挑几个用得较多的来讲解!中文文档Android中文API(136) —— Bitmap


2.Bitmap常用方法

普通方法

  • public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream)将位图的压缩到指定的OutputStream,可以理解成将Bitmap保存到文件中!format格式,PNG,JPG等;quality压缩质量,0-100,0表示最低画质压缩,100最大质量(PNG无损,会忽略品质设定)stream输出流返回值代表是否成功压缩到指定流!
  • void recycle()回收位图占用的内存空间,把位图标记为Dead
  • boolean isRecycled()判断位图内存是否已释放
  • int getWidth()获取位图的宽度
  • int getHeight()获取位图的高度
  • boolean isMutable()图片是否可修改
  • int getScaledWidth(Canvas canvas)获取指定密度转换后的图像的宽度
  • int getScaledHeight(Canvas canvas)获取指定密度转换后的图像的高度

静态方法

  • Bitmap createBitmap(Bitmap src)以src为原图生成不可变得新图像
  • Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter)以src为原图,创建新的图像,指定新图像的高宽以及是否变
  • Bitmap createBitmap(int width, int height, Config config)创建指定格式、大小的位图
  • Bitmap createBitmap(Bitmap source, int x, int y, int width, intheight)以source为原图,创建新的图片,指定起始坐标以及新图像的高宽
  • public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter)

BitmapFactory.Option可设置参数

  • boolean inJustDecodeBounds——若设置为true,不获取图片,不分配内存,但会返回图片的高宽度信息
  • int inSampleSize——图片缩放的倍数 若设为4,则宽和高都为原来的1/4,则图是原来的1/16
  • int outWidth——获取图片的宽度值
  • int outHeight——获取图片的高度值
  • int inDensity——用于位图的像素压缩比
  • int inTargetDensity——用于目标位图的像素压缩比(要生成的位图)
  • boolean inScaled——设置为true时进行图片压缩,从inDensity到inTargetDensity

好吧,就贴这么多吧,要用自己查文档~


3.获取Bitmap位图

从资源中获取位图的方式有两种通过BitmapDrawable或者BitmapFactory,下面演示下首先得获得这个

BitmapDrawable方法

可以创建个构造个BitmapDrawable对象,比如通过流构建BitmapDrawable

BitmapDrawable bmpMeizi = new BitmapDrawable(getAssets().open("pic_meizi.jpg"));
Bitmap mBitmap = bmpMeizi.getBitmap();
img_bg.setImageBitmap(mBitmap);

BitmapFactory方法

都是静态方法,直接调,可以通过资源ID、路径、文件、数据流等方式来获取位图!

//通过资源ID
private Bitmap getBitmapFromResource(Resources res, int resId) {
      return BitmapFactory.decodeResource(res, resId);
}
//文件
private Bitmap getBitmapFromFile(String pathName) {
      return BitmapFactory.decodeFile(pathName);
}
//字节数组
public Bitmap Bytes2Bimap(byte[] b) {
    if (b.length != 0) {
        return BitmapFactory.decodeByteArray(b, 0, b.length);
    } else {
        return null;
    }
}
//输入流
private Bitmap getBitmapFromStream(InputStream inputStream) {
      return BitmapFactory.decodeStream(inputStream);
}

4.获取Bitmap的相关信息

这个,只要获取了Bitmap对象,就可以调用相关方法来获取对应的参数了,getByteCount获得大小,getHeight和getWidth这些~这里就不写了,自己查文档!


5.抠图片上的某一角下来

有时,可能 想把图片上的某一角扣下来,直接通过Bitmap的createBitmap()扣下来即可参数依次为处理的bitmap对象,起始x,y坐标,以及截取的宽高

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200);
img_bg = (ImageView) findViewById(R.id.img_bg);
img_bg.setImageBitmap(bitmap2);

运行效果图

原图

切下来的一角


6.对Bitmap进行缩放

这里不用Matrix来对Bitmap,而是直接使用Bitmap给提供的createScaledBitmap来实现,参数依次是处理的bitmap对象,缩放后的宽高,


7.使用Bitmap进行截屏

运行效果图

实现代码

public class MainActivity extends AppCompatActivity {
    static ByteArrayOutputStream byteOut = null;
    private Bitmap bitmap = null;
    private Button btn_cut;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_cut = (Button) findViewById(R.id.btn_cut);
        btn_cut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                captureScreen();
            }
        });
    }
    public void captureScreen() {
        Runnable action = new Runnable() {
            @Override
            public void run() {
                final View contentView = getWindow().getDecorView();
                try{
                    Log.e("HEHE",contentView.getHeight()+":"+contentView.getWidth());
                    bitmap = Bitmap.createBitmap(contentView.getWidth(),
                            contentView.getHeight(), Bitmap.Config.ARGB_4444);
                    contentView.draw(new Canvas(bitmap));
                    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOut);
                    savePic(bitmap, "sdcard/short.png");
                }catch (Exception e){e.printStackTrace();}
                finally {
                    try{
                        if (null != byteOut)
                            byteOut.close();
                        if (null != bitmap && !bitmap.isRecycled()) {
//                            bitmap.recycle();
                            bitmap = null;
                        }
                    }catch (IOException e){e.printStackTrace();}
                }
            }
        };
        try {
            action.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void savePic(Bitmap b, String strFileName) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(strFileName);
            if (null != fos) {
                boolean success= b.compress(Bitmap.CompressFormat.PNG, 100, fos);
                fos.flush();
                fos.close();
                if(success)
                    Toast.makeText(MainActivity.this, "截屏成功", Toast.LENGTH_SHORT).show();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码分析

代码 final View contentView = getWindow().getDecorView();这句代码是获取当前XML根节点的View!然后设置截屏的大小,调用下contentView.draw(new Canvas(bitmap)); 然后bitmap转换成流,接着写入SD卡,没了~当然从结果也可以看出,截图截取的是改APP的内容而已!若要截全屏,自行谷歌~!


本节小结

讲解下Bitmap,BitmapFactory和他的静态内部类Options,以及BitmapDrawable的基本使用,其实Bitmap知道怎么创建就 他的扩展 是通过Matrix和Canvas来实现的,Bitmap,更多的时候关注的是OOM问题,下节就来学习下如何避免Bitmap的OOM问题!