关于 分别对应下面两个方法 我们知道 一般情况下,我们不会使用 我们不妨来计算一下,如果一张和手机屏幕大小一样的Bitmap图片,采用ARGB_8888格式存储需要多大的内存! 按照1024*768的屏幕大小来计算,每个像素需要32位也就是4个字节, 一张手机屏幕大小的Bitmap图片竟然要24M? 那就不奇怪我的app为什么一直闪退了,只不过用for循环创建了几十个用在滑动列表里面。 所以我们必须要对图片进行压缩呀,压缩格式使用枚举类Bitmap.CompressFormat中,有以下三种: Bitmap.CompressFormat.JPEG:采用 Bitmap.CompressFormat.PNG:采用 Bitmap.CompressFormat.WEBP: 想要创建一个 介绍几个重要的成员变量 inJustDecodeBounds: inSampleSize:这个字段表示采样率,打个比方说,设置为4,则是从原本图片的四个像素中取一个像素作为结果返回。其余的都被丢弃。可见,采样率越大,图片越小,失真越严重。 如何计算采样率呢?看一下这段代码你就会明白 为了更清楚的介绍下面的知识,先补充几点: inScald:这个参数表示,在可以缩放时,是否对当前文件进行放缩,如果设置为false就不放缩。设置为true,则会根据文件夹分辨率和屏幕分辨率进行动态缩放。 inPreferredConfig:这个参数是用来设置像素的存储格式的。 关于Options就介绍这几个关键的字段,下面进入重头戏,创建Bitmap。 BitmapFactory提供了多种创建bitmap的静态方法 平时用这些函数都是糊里糊涂的,今天整理了一遍发现其实有规律可寻,也更加清楚了。 1.加载图像可以使用 1.我们在创建一个 2.我们自定义空间所显示的 3. 个人认为, 1.我们可以对位图进行压缩,压缩手段有 以前使用bitmap全靠cv,现在掌握了这么多知识,bitmap随便用都不会出现问题,妈妈再也不用担心我内存溢出,太棒了! 看官别走,我有一个资源学习群要推荐给你,它是白嫖党的乐园,小白的天堂!深度解剖Bitmap
一.Bitmap的相关使用
Bitmap
,之前以为它和Drawable
差不多,就是一种图片,直到泪水打湿了我胸前的红领巾,我决定整理一波关于Bitmap
的姿势!
Bitmap
相关的使用主要有两种:
ImageView
设置背景 imageView.setImageBitmap(Bitmap bm); Canvas canvas = new Canvas(Bitmap bm)
二.Bitmap的格式
Bitmap
是位图,是由像素点组成的,这就涉及到两个问题,
2.1 存储格式
Bitmap
有四种存储方式,对应Bitmap.Config
中的四个常量
ALPHA_8
,他只存储透明度,没啥用处。对于ARGB_4444
,它的画质又太感人了,ARGB_8888
画质高但是占内存,RGB_565
还行,就是不可以设置透明度。
注意以下三点即可:
ARGB_8888
格式存储Bitmap
ARGB_4444
画面惨不忍睹,被弃用RGB_565
,比ARGB_8888
节省一半的内存开销2.2 压缩格式
result = 1024*768*32B=25165824B=24MB
JPEG
压缩算法,是一种有损压缩格式,会在压缩过程中改变图像原本质量,画质越差,对原来的图片质量损伤越大,但是得到的文件比较小,而且JPEG
不支持透明度,当遇到透明度像素时,会以黑色背景填充。PNG
算法,是一种支持透明度的无损压缩格式。WEBP
是一种同时提供了有损压缩和无损压缩的图片文件格式,在14<=api<=17时,WEBP
是一种有损压缩格式,而且不支持透明度,在api18以后WEBP
是一种无损压缩格式,而且支持透明度,有损压缩时,在质量相同的情况下,WEBP
格式的图片体积比JPEG
小40%,但是编码时间比JPEG
长8倍。在无损压缩时,无损的WEBP
图片比PNG
压缩小26%,但是WEBP的压缩时间是PNG
格式压缩时间的5倍。三.Bitmap创建方法
3.1 Bitmap.Options
Bitmap
有很多种方法,其中很多方法都要求传入一个Bitmap.Options
,它是什么呢,有什么作用呢?
这个参数的作用非常大,他可以设置Bitmap的采样率,通过改变图片的宽度高度和缩放比例等,以达到减少图片像素数的目的,一言以蔽之,通过设置这个参数我们可以很好的控制显示和使用Bitmap
。实际开发过程中,可以灵活设置该值,以降低OOM
发生的概率。
boolean
类型,设为true
时,无需要把图片加载入内存就可以获取图片的高度,宽度和图片的MIME
类型。
高度通过options.outWidth
获取 宽度通过options.outHeight
获取
MIME
通过options.outMineType
获取 public int getSampleSize(BitmapFactory.Options options , int dstWidth,int dstHeight){ //dstWidth:表示目前ImageView的宽度 //dstHeight:表示目标ImageView的高度 //option中获取bitmap图片的信息 int rawWidth = options.outWidth; int rawHeight = options.outHeight; int sampleSize=1; if(rawWidth>dstWidth||rawHeight>dstHeight){ float ratioHeight = (float) (rawHeight/dstHeight); float ratioWidth = (float) (rawWidth/dstWidth); sampleSize = (int) Math.min(rawHeight, ratioWidth); } return sampleSize; }
3.2 BitmapFactory
//从资源文件中通过id加载bitmap //Resources res:资源文件,可以context.getResources()获得 //id:资源文件的id,如R.drawable.xxx public static Bitmap decodeResources(Resources res,int id) //第二种只是第一种的重载方法,多了个Options参数 public static Bitmap decodeResources(Resources res,int id,Options opt)
//传入文件路径加载,比如加载sd卡中的文件 //pathName:文件的全路径名 public static Bitmap decodeFile(String pathName); public static Bitmap decodeFile(String pathName,Options opt);
//从byte数组中加载 //offset:对应data数组的起始下标 //length:截取的data数组的长度 public static Bitmap decodeByteArray(byte[] data,int offset , int length); public static Bitmap decodeByteArray(byte[] data,int offset , int length,Options opt);
//从输入流中加载图片 //InputStream is:输入流 //Rect outPadding:用于返回矩形的内边距 public static Bitmap decodeStream(InputStream is); public static Bitmap decodeStream(InputStream is,Rect outPadding,Options opt);
//FileDescriptor :包含解码位图的数据文件的路径 //通过该方式从路径加载bitmap比decodeFile更节省内存,原因不解释了。 public static Bitmap decodeFileDescriptor(FileDescriptor fd); public static Bitmap decodeFileDescriptor(FileDescriptor fd,Rect outPadding,Options opt);
3.3 Bitmap静态方法
//width和height是长和宽单位px,config是存储格式 static Bitmap createBitmap(int width , int height Bitmap.Config config) // 根据一幅图像创建一份一模一样的实例 static Bitmap createBitmap(Bitmap bm) //截取一幅bitmap,起点是(x,y),width和height分别对应宽高 static Bitmap createBitmap(Bitmap bm,int x,int y,int width,int height) //比上面的裁剪函数多了两个参数,Matrix:给裁剪后的图像添加矩阵 boolean filter:是否给图像添加滤波效果 static Bitmap createBitmap(Bitmap bm,int x,int y,int width,int height,Matrix m,boolean filter); //用于缩放bitmap,dstWidth和dstHeight分别是目标宽高 createScaledBitmap(Bitmap bm,int dstWidth,int dstHeight,boolean filter)
3.4 创建Bitmap的总结
BitmapFactory
和Bitmap.create
系列方法
2.可以通过Options
实现缩放图片,获取图片信息,配置缩放比例等功能
3.如果需要裁剪或者缩放图片,只能使用create
系列函数
4.注意加载和创建bitmap
事通过try catch
捕捉OOM
异常
四.常见函数
4.1 函数及其参数
copy(Config config,boolean isMutable) //根据原图像创建一个副本,但可以指定副本的像素存储格式 //参数含义。 // config:像素在内存中的存储格式,但可以指定副本的像素存储格式 // boolean isMutable:新建的bitmap是否可以修改其中的像素值
extractAlpha() //主要作用是从bitmap中获取Alpha值,生成一幅只有Alpha值得图像,存储格式是ALPHA_8
getByteCount()//获取bitmap的字节数
recycle()://不用的bitmap必须要及时回收,以免造成oom
isRecycled()//判断bitmap是否被回收,被收回不可使用会造成crash
4.2 综合案例演示
String items[] = {"copy","extractAlpha 1","extractAlpha 2","bitmap大小","recycle","isRecycled()"}; ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { switch (position){ case 0: //copy Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Bitmap copy = bm.copy(Bitmap.Config.ARGB_8888, true); imageView.setImageBitmap(copy); bm.recycle(); break; case 1: //extractAlpha 不带参数 Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Bitmap alpha = bp.extractAlpha(); imageView.setImageBitmap(alpha); bp.recycle(); break; case 2: //extractAlpha 带参数 Bitmap bp1 = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Paint paint = new Paint(); BlurMaskFilter blurMaskFilter = new BlurMaskFilter(6, BlurMaskFilter.Blur.NORMAL); paint.setMaskFilter(blurMaskFilter); int[] offsetXY = new int[2]; Bitmap alpha1 = bp1.extractAlpha(paint, offsetXY); imageView.setImageBitmap(alpha1); break; case 3: //获取bitmap大小 Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.photo); Toast.makeText(getApplicationContext(), "图片大小为:"+b.getByteCount()+"字节", Toast.LENGTH_SHORT).show(); break; case 4: //回收bitmap Bitmap b1 = BitmapFactory.decodeResource(getResources(), R.drawable.photo); b1.recycle(); if(b1.isRecycled()){ Toast.makeText(getApplicationContext(), "已经被回收", Toast.LENGTH_SHORT).show(); } //isRecycled()判断是否被回收 break; } } @Override public void onNothingSelected(AdapterView<?> parent) { } });
五.常见问题
5.1 Bitmap与Canvas,View,Drawable的关系
Canvas
时,可以传入一个Bitmap
,Paint
在Canvas
上的绘制实际上就是绘制在Bitmap
对象上的。View
也是通过Canvas
中的Bitmap
来显示的。Drawable
在内存占用和绘制速度这两个非常关键的点上胜过Bitmap
.
5.2 使用Bitmap如何造成内存溢出的?
Bitmap
容易造成内存溢出是由于位图较大,一张屏幕大小的ARGB_8888
存储格式的图片竟然有24M,如果有几个这种量级的图片在内存中,并且没有及时回收,那会非常容易造成OOM
5.3怎么解决或者避免Bitmap内存溢出?
PNG,JPEG,WEBP
2.对不使用的Bitmap
一定要及时回收。
3.在创建Bitmap
时使用try catch
步骤OOM
异常,使程序更健壮,即使发生了OOM
也不会闪退,造成不好的使用体验.5.4Bitmap与Drawable的转换
5.4.1 Drawable转换成Bitmap
public static Bitmap drawableToBitmap(Drawable drawable) { // 取 drawable 的长宽 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // 建立对应 bitmap 的画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap; }
5.4.2 Bitmap转换成Drawable
Bitmap bm=Bitmap.createBitmap(xxx); BitmapDrawable bd= new BitmapDrawable(getResource(), bm);
六.小结
还在等什么,一起愉快的学习吧!
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算