责编 | 王晓曼
Bitmap的相关使用
Bitmap相关的使用主要有两种:
2.当做画布来使用 。
Bitmap的格式
第一:如何存储每个像素点?
1、存储格式
ARGB_4444:ARGB各用4位存储,1个像素点16位占2个字节;
RGB_565:只存储色值,不存储透明度,默认不透明,RGB分别占5,6,5位,一个像素点占用16位2个字节。
注意以下三点即可:
- 一般情况下用ARGB_8888格式存储Bitmap;
假如对图片没有透明度要求,可以使用RGB_565,比ARGB_8888节省一半的内存开销。
我们不妨来计算一下,如果一张和手机屏幕大小一样的Bitmap图片,采用ARGB_8888格式存储需要多大的内存!
一张手机屏幕大小的 Bitmap 图片竟然要 24M ? 那就不奇怪我的 APP 为什么一直闪退了,只不过用 for 循环创 建了几十个用在滑动列表里面。
Bitmap创建方法
想要创建一个Bitmap有很多种方法,其中很多方法都要求传入一个Bitmap.Options,它是什么呢,有什么作用呢?
介绍几个重要的成员变量:
- inJustDecodeBounds:boolean类型,设为true时,无需要把图片加载入内存就可以获取图片的高度,宽度和图片的MIME类型。
MIME通过options.outMineType获取。
- inSampleSize:这个字段表示采样率,打个比方说,设置为4,则是从原本图片的四个像素中取一个像素作为结果返回。其余的都被丢弃。可见,采样率越大,图片越小,失真越严重。如何计算采样率呢?看一下这段代码你就会明白:
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;
}
当屏幕分辨率与图片所在文件夹所对应的分辨率不同时,会进行缩放,缩放比例是屏幕分辨率/文件夹所对应的分辨率。
inScald :这个参数表示,在可以缩放时,是否对当前文件进行放缩,如果设置为 false 就不放缩。设置为 true,则会根据文件夹分辨率和屏幕分辨率进行动态缩放。
关于 Options 就介绍这几个关键的字段,下面进入重头戏,创建Bitmap。
BitmapFactory 提供了多种创建 bitmap 的静态方法:
//从资源文件中通过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、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)
加载图像可以使用BitmapFactory和Bitmap.create系列方法
如果需要裁剪或者缩放图片,只能使用create系列函数
常见函数
getByteCount//获取bitmap的字节数
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) {
}
});nerror="javascript:errorimg.call(this);">
1、Bitmap与Canvas,View,Drawable的关系:
我们自定义空间所显示的View也是通过Canvas中的Bitmap来显示的。
2、使用Bitmap如何造成内存溢出的?
3、怎么解决或者避免Bitmap内存溢出?
- 我们可以对位图进行压缩,压缩手段有 PNG,JPEG,WEBP。
在创建 Bitmap 时使用 try catch 步骤 OOM 异常,使程序更健壮,即使发生了 OOM 也不会闪退,造成不好的使用体验。
(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;
}小结
版权声明:本文为CSDN博主「IF 」的原创文章,遵循CC4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
https://blog.csdn.net/weixin_43927892/article/details/106209563
Linux 之父怒删工程师提交的补丁,称“太蠢了”网友:怼得好!
性能超越最新序列推荐模型,华为诺亚方舟提出记忆增强的图神经网络
稳定币经济:十大稳定币简史
- 我们可以对位图进行压缩,压缩手段有 PNG,JPEG,WEBP。
